mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 697230: Part 1 - Centralize style image observers. r=bz
This commit is contained in:
parent
1f53344b51
commit
dd495263dd
@ -116,6 +116,7 @@ class nsIObjectLoadingContent;
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class Loader;
|
||||
class ImageLoader;
|
||||
} // namespace css
|
||||
|
||||
namespace dom {
|
||||
@ -125,8 +126,8 @@ class Element;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0x8e51e6d9, 0x914d, 0x46ba, \
|
||||
{ 0xb3, 0x11, 0x2f, 0x27, 0x3d, 0xe6, 0x0d, 0x19 } }
|
||||
{ 0xdb888523, 0x541f, 0x49e3, \
|
||||
{ 0xa9, 0x71, 0xb5, 0xea, 0xd1, 0xf0, 0xc3, 0xcf } }
|
||||
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
@ -643,6 +644,13 @@ public:
|
||||
return mCSSLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this document's StyleImageLoader. This is guaranteed to not return null.
|
||||
*/
|
||||
mozilla::css::ImageLoader* StyleImageLoader() const {
|
||||
return mStyleImageLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channel that was passed to StartDocumentLoad or Reset for this
|
||||
* document. Note that this may be null in some cases (eg if
|
||||
@ -1739,6 +1747,7 @@ protected:
|
||||
// The cleanup is handled by the nsDocument destructor.
|
||||
nsNodeInfoManager* mNodeInfoManager; // [STRONG]
|
||||
mozilla::css::Loader* mCSSLoader; // [STRONG]
|
||||
mozilla::css::ImageLoader* mStyleImageLoader; // [STRONG]
|
||||
nsHTMLStyleSheet* mAttrStyleSheet;
|
||||
|
||||
// The set of all object, embed, applet, video and audio elements for
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIScriptRuntime.h"
|
||||
@ -1649,6 +1650,11 @@ nsDocument::~nsDocument()
|
||||
NS_RELEASE(mCSSLoader);
|
||||
}
|
||||
|
||||
if (mStyleImageLoader) {
|
||||
mStyleImageLoader->DropDocumentReference();
|
||||
NS_RELEASE(mStyleImageLoader);
|
||||
}
|
||||
|
||||
// XXX Ideally we'd do this cleanup in the nsIDocument destructor.
|
||||
if (mNodeInfoManager) {
|
||||
mNodeInfoManager->DropDocumentReference();
|
||||
@ -1983,7 +1989,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
nsresult
|
||||
nsDocument::Init()
|
||||
{
|
||||
if (mCSSLoader || mNodeInfoManager || mScriptLoader) {
|
||||
if (mCSSLoader || mStyleImageLoader || mNodeInfoManager || mScriptLoader) {
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
@ -2012,10 +2018,16 @@ nsDocument::Init()
|
||||
// Assume we're not quirky, until we know otherwise
|
||||
mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
|
||||
|
||||
mStyleImageLoader = new mozilla::css::ImageLoader(this);
|
||||
NS_ADDREF(mStyleImageLoader);
|
||||
|
||||
nsresult rv = mStyleImageLoader->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mNodeInfoManager = new nsNodeInfoManager();
|
||||
NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = mNodeInfoManager->Init(this);
|
||||
rv = mNodeInfoManager->Init(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// mNodeInfo keeps NodeInfoManager alive!
|
||||
|
@ -107,7 +107,6 @@ CPPSRCS = \
|
||||
nsFrameManager.cpp \
|
||||
nsFrameTraversal.cpp \
|
||||
nsGenConList.cpp \
|
||||
nsImageLoader.cpp \
|
||||
nsLayoutDebugger.cpp \
|
||||
nsLayoutHistoryState.cpp \
|
||||
nsLayoutUtils.cpp \
|
||||
|
@ -84,8 +84,10 @@
|
||||
#include "gfxDrawable.h"
|
||||
|
||||
#include "nsCSSRenderingBorders.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::css;
|
||||
|
||||
/**
|
||||
* This is a small wrapper class to encapsulate image drawing that can draw an
|
||||
@ -2419,10 +2421,20 @@ nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure we get invalidated for loads of the image. We need to do
|
||||
// this here because this might be the only code that knows about the
|
||||
// Ensure we get invalidated for loads of the image. If this is not the
|
||||
// frame's normal style context this is the only code that knows about the
|
||||
// association of the style data with the frame.
|
||||
aPresContext->SetupBackgroundImageLoaders(aForFrame, bg);
|
||||
if (aBackgroundSC != aForFrame->GetStyleContext()) {
|
||||
ImageLoader* loader = aPresContext->Document()->StyleImageLoader();
|
||||
|
||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
|
||||
if (bg->mLayers[i].mImage.GetType() == eStyleImageType_Image) {
|
||||
imgIRequest *image = bg->mLayers[i].mImage.GetImageData();
|
||||
|
||||
loader->AssociateRequestToFrame(image, aForFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can skip painting the background color if a background image is opaque.
|
||||
if (drawBackgroundColor &&
|
||||
@ -2732,9 +2744,11 @@ DrawBorderImage(nsPresContext* aPresContext,
|
||||
// XXX We shouldn't really... since if anybody is passing in a
|
||||
// different style, they'll potentially have the wrong size for the
|
||||
// border too.
|
||||
aPresContext->SetupBorderImageLoaders(aForFrame, &aStyleBorder);
|
||||
|
||||
imgIRequest *req = aStyleBorder.GetBorderImage();
|
||||
ImageLoader* loader = aPresContext->Document()->StyleImageLoader();
|
||||
|
||||
// If this fails there's not much we can do ...
|
||||
loader->AssociateRequestToFrame(req, aForFrame);
|
||||
|
||||
// Get the actual image.
|
||||
|
||||
|
@ -1,284 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* class to notify frames of background image loads */
|
||||
|
||||
#include "nsImageLoader.h"
|
||||
|
||||
#include "imgILoader.h"
|
||||
|
||||
#include "nsIURI.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
#include "imgIContainer.h"
|
||||
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
// Paint forcing
|
||||
#include "prenv.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver)
|
||||
|
||||
nsImageLoader::nsImageLoader(nsIFrame *aFrame, PRUint32 aActions,
|
||||
nsImageLoader *aNextLoader)
|
||||
: mFrame(aFrame),
|
||||
mActions(aActions),
|
||||
mNextLoader(aNextLoader),
|
||||
mRequestRegistered(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsImageLoader::~nsImageLoader()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<nsImageLoader>
|
||||
nsImageLoader::Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
||||
PRUint32 aActions, nsImageLoader *aNextLoader)
|
||||
{
|
||||
nsRefPtr<nsImageLoader> loader =
|
||||
new nsImageLoader(aFrame, aActions, aNextLoader);
|
||||
|
||||
loader->Load(aRequest);
|
||||
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoader::Destroy()
|
||||
{
|
||||
// Destroy the chain with only one level of recursion.
|
||||
nsRefPtr<nsImageLoader> list = mNextLoader;
|
||||
mNextLoader = nsnull;
|
||||
while (list) {
|
||||
nsRefPtr<nsImageLoader> todestroy = list;
|
||||
list = todestroy->mNextLoader;
|
||||
todestroy->mNextLoader = nsnull;
|
||||
todestroy->Destroy();
|
||||
}
|
||||
|
||||
if (mRequest && mFrame) {
|
||||
nsLayoutUtils::DeregisterImageRequest(mFrame->PresContext(), mRequest,
|
||||
&mRequestRegistered);
|
||||
}
|
||||
|
||||
mFrame = nsnull;
|
||||
|
||||
if (mRequest) {
|
||||
mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
mRequest = nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsImageLoader::Load(imgIRequest *aImage)
|
||||
{
|
||||
NS_ASSERTION(!mRequest, "can't reuse image loaders");
|
||||
NS_ASSERTION(mFrame, "not initialized");
|
||||
NS_ASSERTION(aImage, "must have non-null image");
|
||||
|
||||
if (!mFrame)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!aImage)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Deregister mRequest from the refresh driver, since it is no longer
|
||||
// going to be managed by this nsImageLoader.
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
|
||||
nsLayoutUtils::DeregisterImageRequest(presContext, mRequest,
|
||||
&mRequestRegistered);
|
||||
|
||||
// Make sure to clone into a temporary, then set mRequest, since
|
||||
// cloning may notify and we don't want to trigger paints from this
|
||||
// code.
|
||||
nsCOMPtr<imgIRequest> newRequest;
|
||||
nsresult rv = aImage->Clone(this, getter_AddRefs(newRequest));
|
||||
mRequest.swap(newRequest);
|
||||
|
||||
if (mRequest) {
|
||||
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mRequest,
|
||||
&mRequestRegistered);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
|
||||
imgIContainer *aImage)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aImage, "Who's calling us then?");
|
||||
|
||||
/* Get requested animation policy from the pres context:
|
||||
* normal = 0
|
||||
* one frame = 1
|
||||
* one loop = 2
|
||||
*/
|
||||
aImage->SetAnimationMode(mFrame->PresContext()->ImageAnimationMode());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImageLoader::OnStopFrame(imgIRequest *aRequest,
|
||||
PRUint32 aFrame)
|
||||
{
|
||||
if (!mFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mRequest) {
|
||||
// We're in the middle of a paint anyway
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Take requested actions
|
||||
if (mActions & ACTION_REDRAW_ON_DECODE) {
|
||||
DoRedraw(nsnull);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImageLoader::OnImageIsAnimated(imgIRequest *aRequest)
|
||||
{
|
||||
// Register with the refresh driver now that we are aware that
|
||||
// we are animated.
|
||||
nsLayoutUtils::RegisterImageRequest(mFrame->PresContext(),
|
||||
aRequest, &mRequestRegistered);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImageLoader::OnStopRequest(imgIRequest *aRequest,
|
||||
bool aLastPart)
|
||||
{
|
||||
if (!mFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mRequest) {
|
||||
// We're in the middle of a paint anyway
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Take requested actions
|
||||
if (mActions & ACTION_REDRAW_ON_LOAD) {
|
||||
DoRedraw(nsnull);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImageLoader::FrameChanged(imgIRequest *aRequest,
|
||||
imgIContainer *aContainer,
|
||||
const nsIntRect *aDirtyRect)
|
||||
{
|
||||
if (!mFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mRequest) {
|
||||
// We're in the middle of a paint anyway
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aRequest == mRequest, "This is a neat trick.");
|
||||
|
||||
nsRect r = aDirtyRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect()) ?
|
||||
nsRect(nsPoint(0, 0), mFrame->GetSize()) :
|
||||
aDirtyRect->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel());
|
||||
|
||||
DoRedraw(&r);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoader::DoRedraw(const nsRect* aDamageRect)
|
||||
{
|
||||
// NOTE: It is not sufficient to invalidate only the size of the image:
|
||||
// the image may be tiled!
|
||||
// The best option is to call into the frame, however lacking this
|
||||
// we have to at least invalidate the frame's bounds, hence
|
||||
// as long as we have a frame we'll use its size.
|
||||
//
|
||||
|
||||
// Invalidate the entire frame
|
||||
// XXX We really only need to invalidate the client area of the frame...
|
||||
|
||||
nsRect bounds(nsPoint(0, 0), mFrame->GetSize());
|
||||
|
||||
if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
|
||||
// The canvas's background covers the whole viewport.
|
||||
bounds = mFrame->GetVisualOverflowRect();
|
||||
}
|
||||
|
||||
// XXX this should be ok, but there is some crappy ass bug causing it not to work
|
||||
// XXX seems related to the "body fixup rule" dealing with the canvas and body frames...
|
||||
#if 0
|
||||
// Invalidate the entire frame only if the frame has a tiled background
|
||||
// image, otherwise just invalidate the intersection of the frame's bounds
|
||||
// with the damaged rect.
|
||||
nsStyleContext* styleContext;
|
||||
mFrame->GetStyleContext(&styleContext);
|
||||
const nsStyleBackground* bg = styleContext->GetStyleBackground();
|
||||
|
||||
if ((bg->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE) ||
|
||||
(bg->mBackgroundRepeat == NS_STYLE_BG_REPEAT_OFF)) {
|
||||
// The frame does not have a background image so we are free
|
||||
// to invalidate only the intersection of the damage rect and
|
||||
// the frame's bounds.
|
||||
|
||||
if (aDamageRect) {
|
||||
bounds.IntersectRect(*aDamageRect, bounds);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (mFrame->GetStyleVisibility()->IsVisible()) {
|
||||
mFrame->Invalidate(bounds);
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* class to notify frames of background and border image loads */
|
||||
|
||||
#include "nsStubImageDecoderObserver.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsIURI;
|
||||
|
||||
#include "imgIRequest.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
/**
|
||||
* Image loaders pass notifications for background and border image
|
||||
* loading and animation on to the frames.
|
||||
*
|
||||
* Each frame's image loaders form a linked list.
|
||||
*/
|
||||
class nsImageLoader : public nsStubImageDecoderObserver
|
||||
{
|
||||
private:
|
||||
nsImageLoader(nsIFrame *aFrame, PRUint32 aActions,
|
||||
nsImageLoader *aNextLoader);
|
||||
virtual ~nsImageLoader();
|
||||
|
||||
public:
|
||||
/*
|
||||
* Flags to specify actions that can be taken for the image at various
|
||||
* times. Reflows always occur before redraws. "Decode" refers to one
|
||||
* frame being available, whereas "load" refers to all the data being loaded
|
||||
* from the network.
|
||||
*/
|
||||
enum {
|
||||
ACTION_REDRAW_ON_DECODE = 0x01,
|
||||
ACTION_REDRAW_ON_LOAD = 0x02,
|
||||
};
|
||||
static already_AddRefed<nsImageLoader>
|
||||
Create(nsIFrame *aFrame, imgIRequest *aRequest,
|
||||
PRUint32 aActions, nsImageLoader *aNextLoader);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// imgIDecoderObserver (override nsStubImageDecoderObserver)
|
||||
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
|
||||
NS_IMETHOD OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame);
|
||||
NS_IMETHOD OnStopRequest(imgIRequest *aRequest, bool aLastPart);
|
||||
NS_IMETHOD OnImageIsAnimated(imgIRequest *aRequest);
|
||||
// Do not override OnDataAvailable since background images are not
|
||||
// displayed incrementally; they are displayed after the entire image
|
||||
// has been loaded.
|
||||
// Note: Images referenced by the <img> element are displayed
|
||||
// incrementally in nsImageFrame.cpp.
|
||||
|
||||
// imgIContainerObserver (override nsStubImageDecoderObserver)
|
||||
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
|
||||
imgIContainer *aContainer,
|
||||
const nsIntRect *aDirtyRect);
|
||||
|
||||
void Destroy();
|
||||
|
||||
imgIRequest *GetRequest() { return mRequest; }
|
||||
nsImageLoader *GetNextLoader() { return mNextLoader; }
|
||||
|
||||
private:
|
||||
nsresult Load(imgIRequest *aImage);
|
||||
/* if aDamageRect is nsnull, the whole frame is redrawn. */
|
||||
void DoRedraw(const nsRect* aDamageRect);
|
||||
|
||||
nsIFrame *mFrame;
|
||||
nsCOMPtr<imgIRequest> mRequest;
|
||||
PRUint32 mActions;
|
||||
nsRefPtr<nsImageLoader> mNextLoader;
|
||||
|
||||
// This is a boolean flag indicating whether or not the current image request
|
||||
// has been registered with the refresh driver.
|
||||
bool mRequestRegistered;
|
||||
};
|
@ -48,7 +48,6 @@
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsImageLoader.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIURL.h"
|
||||
@ -97,6 +96,7 @@
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsDOMMediaQueryList.h"
|
||||
#include "nsSMILAnimationController.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsBidiPresUtils.h"
|
||||
@ -194,14 +194,6 @@ IsVisualCharset(const nsCString& aCharset)
|
||||
}
|
||||
#endif // IBMBIDI
|
||||
|
||||
|
||||
static PLDHashOperator
|
||||
destroy_loads(nsIFrame* aKey, nsRefPtr<nsImageLoader>& aData, void* closure)
|
||||
{
|
||||
aData->Destroy();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
#include "nsContentCID.h"
|
||||
|
||||
// NOTE! nsPresContext::operator new() zeroes out all members, so don't
|
||||
@ -343,28 +335,12 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPresContext)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPresContext)
|
||||
|
||||
static PLDHashOperator
|
||||
TraverseImageLoader(nsIFrame* aKey, nsRefPtr<nsImageLoader>& aData,
|
||||
void* aClosure)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mImageLoaders[i] item");
|
||||
cb->NoteXPCOMChild(aData);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPresContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument);
|
||||
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDeviceContext); // not xpcom
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mEventManager, nsIObserver);
|
||||
// NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mLanguage); // an atom
|
||||
|
||||
for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
|
||||
tmp->mImageLoaders[i].Enumerate(TraverseImageLoader, &cb);
|
||||
|
||||
// We own only the items in mDOMMediaQueryLists that have listeners;
|
||||
// this reference is managed by their AddListener and RemoveListener
|
||||
// methods.
|
||||
@ -953,10 +929,6 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
|
||||
mDeviceContext->FlushFontCache();
|
||||
mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
|
||||
|
||||
for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
|
||||
if (!mImageLoaders[i].Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mEventManager = new nsEventStateManager();
|
||||
NS_ADDREF(mEventManager);
|
||||
|
||||
@ -1130,18 +1102,6 @@ nsPresContext::SetShell(nsIPresShell* aShell)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::DestroyImageLoaders()
|
||||
{
|
||||
// Destroy image loaders. This is important to do when frames are being
|
||||
// destroyed because imageloaders can have pointers to frames and we don't
|
||||
// want those pointers to outlive the destruction of the frame arena.
|
||||
for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i) {
|
||||
mImageLoaders[i].Enumerate(destroy_loads, nsnull);
|
||||
mImageLoaders[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::DoChangeCharSet(const nsCString& aCharSet)
|
||||
{
|
||||
@ -1252,18 +1212,6 @@ static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, PRUint16 aMode)
|
||||
}
|
||||
}
|
||||
|
||||
// Enumeration call back for HashTable
|
||||
static PLDHashOperator
|
||||
set_animation_mode(nsIFrame* aKey, nsRefPtr<nsImageLoader>& aData, void* closure)
|
||||
{
|
||||
for (nsImageLoader *loader = aData; loader;
|
||||
loader = loader->GetNextLoader()) {
|
||||
imgIRequest* imgReq = loader->GetRequest();
|
||||
SetImgAnimModeOnImgReq(imgReq, (PRUint16)NS_PTR_TO_INT32(closure));
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// IMPORTANT: Assumption is that all images for a Presentation
|
||||
// have the same Animation Mode (pavlov said this was OK)
|
||||
//
|
||||
@ -1318,15 +1266,13 @@ nsPresContext::SetImageAnimationModeInternal(PRUint16 aMode)
|
||||
if (!IsDynamic())
|
||||
return;
|
||||
|
||||
// Set the mode on the image loaders.
|
||||
for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
|
||||
mImageLoaders[i].Enumerate(set_animation_mode, NS_INT32_TO_PTR(aMode));
|
||||
|
||||
// Now walk the content tree and set the animation mode
|
||||
// on all the images.
|
||||
if (mShell != nsnull) {
|
||||
nsIDocument *doc = mShell->GetDocument();
|
||||
if (doc) {
|
||||
doc->StyleImageLoader()->SetAnimationMode(aMode);
|
||||
|
||||
Element *rootElement = doc->GetRootElement();
|
||||
if (rootElement) {
|
||||
SetImgAnimations(rootElement, aMode);
|
||||
@ -1412,68 +1358,6 @@ nsPresContext::SetFullZoom(float aZoom)
|
||||
mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::SetImageLoaders(nsIFrame* aTargetFrame,
|
||||
ImageLoadType aType,
|
||||
nsImageLoader* aImageLoaders)
|
||||
{
|
||||
NS_ASSERTION(mShell || !aImageLoaders,
|
||||
"Shouldn't add new image loader after the shell is gone");
|
||||
|
||||
nsRefPtr<nsImageLoader> oldLoaders;
|
||||
mImageLoaders[aType].Get(aTargetFrame, getter_AddRefs(oldLoaders));
|
||||
|
||||
if (aImageLoaders) {
|
||||
mImageLoaders[aType].Put(aTargetFrame, aImageLoaders);
|
||||
} else if (oldLoaders) {
|
||||
mImageLoaders[aType].Remove(aTargetFrame);
|
||||
}
|
||||
|
||||
if (oldLoaders)
|
||||
oldLoaders->Destroy();
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::SetupBackgroundImageLoaders(nsIFrame* aFrame,
|
||||
const nsStyleBackground* aStyleBackground)
|
||||
{
|
||||
nsRefPtr<nsImageLoader> loaders;
|
||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, aStyleBackground) {
|
||||
if (aStyleBackground->mLayers[i].mImage.GetType() == eStyleImageType_Image) {
|
||||
PRUint32 actions = nsImageLoader::ACTION_REDRAW_ON_DECODE;
|
||||
imgIRequest *image = aStyleBackground->mLayers[i].mImage.GetImageData();
|
||||
loaders = nsImageLoader::Create(aFrame, image, actions, loaders);
|
||||
}
|
||||
}
|
||||
SetImageLoaders(aFrame, BACKGROUND_IMAGE, loaders);
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::SetupBorderImageLoaders(nsIFrame* aFrame,
|
||||
const nsStyleBorder* aStyleBorder)
|
||||
{
|
||||
// We get called the first time we try to draw a border-image, and
|
||||
// also when the border image changes (including when it changes from
|
||||
// non-null to null).
|
||||
imgIRequest *borderImage = aStyleBorder->GetBorderImage();
|
||||
if (!borderImage) {
|
||||
SetImageLoaders(aFrame, BORDER_IMAGE, nsnull);
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint32 actions = nsImageLoader::ACTION_REDRAW_ON_LOAD;
|
||||
nsRefPtr<nsImageLoader> loader =
|
||||
nsImageLoader::Create(aFrame, borderImage, actions, nsnull);
|
||||
SetImageLoaders(aFrame, BORDER_IMAGE, loader);
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::StopImagesFor(nsIFrame* aTargetFrame)
|
||||
{
|
||||
for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
|
||||
SetImageLoaders(aTargetFrame, ImageLoadType(i), nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::SetContainer(nsISupports* aHandler)
|
||||
{
|
||||
@ -2180,6 +2064,8 @@ NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
|
||||
void
|
||||
nsPresContext::NotifyDidPaintForSubtree()
|
||||
{
|
||||
Document()->StyleImageLoader()->NotifyPaint();
|
||||
|
||||
if (!mFireAfterPaintEvents)
|
||||
return;
|
||||
mFireAfterPaintEvents = false;
|
||||
|
@ -74,7 +74,6 @@
|
||||
#include "nsIContent.h"
|
||||
#include "prclist.h"
|
||||
|
||||
class nsImageLoader;
|
||||
#ifdef IBMBIDI
|
||||
class nsBidiPresUtils;
|
||||
#endif // IBMBIDI
|
||||
@ -384,49 +383,6 @@ public:
|
||||
bool GetFocusRingOnAnything() const { return mFocusRingOnAnything; }
|
||||
PRUint8 GetFocusRingStyle() const { return mFocusRingStyle; }
|
||||
|
||||
/**
|
||||
* The types of image load types that the pres context needs image
|
||||
* loaders to track invalidation for.
|
||||
*/
|
||||
enum ImageLoadType {
|
||||
BACKGROUND_IMAGE,
|
||||
BORDER_IMAGE,
|
||||
IMAGE_LOAD_TYPE_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the list of image loaders that track invalidation for a
|
||||
* specific frame and type of image. This list will replace any
|
||||
* previous list for that frame and image type (and null will remove
|
||||
* any previous list).
|
||||
*/
|
||||
NS_HIDDEN_(void) SetImageLoaders(nsIFrame* aTargetFrame,
|
||||
ImageLoadType aType,
|
||||
nsImageLoader* aImageLoaders);
|
||||
|
||||
/**
|
||||
* Make an appropriate SetImageLoaders call (including potentially
|
||||
* with null aImageLoaders) given that aFrame draws its background
|
||||
* based on aStyleBackground.
|
||||
*/
|
||||
NS_HIDDEN_(void) SetupBackgroundImageLoaders(nsIFrame* aFrame,
|
||||
const nsStyleBackground*
|
||||
aStyleBackground);
|
||||
|
||||
/**
|
||||
* Make an appropriate SetImageLoaders call (including potentially
|
||||
* with null aImageLoaders) given that aFrame draws its border
|
||||
* based on aStyleBorder.
|
||||
*/
|
||||
NS_HIDDEN_(void) SetupBorderImageLoaders(nsIFrame* aFrame,
|
||||
const nsStyleBorder* aStyleBorder);
|
||||
|
||||
/**
|
||||
* This method is called when a frame is being destroyed to
|
||||
* ensure that the image loads get disassociated from the prescontext
|
||||
*/
|
||||
NS_HIDDEN_(void) StopImagesFor(nsIFrame* aTargetFrame);
|
||||
|
||||
NS_HIDDEN_(void) SetContainer(nsISupports* aContainer);
|
||||
|
||||
virtual NS_HIDDEN_(already_AddRefed<nsISupports>) GetContainerExternal() const;
|
||||
@ -953,8 +909,6 @@ public:
|
||||
}
|
||||
inline void ForgetUpdatePluginGeometryFrame(nsIFrame* aFrame);
|
||||
|
||||
void DestroyImageLoaders();
|
||||
|
||||
bool GetContainsUpdatePluginGeometryFrame()
|
||||
{
|
||||
return mContainsUpdatePluginGeometryFrame;
|
||||
@ -1131,10 +1085,6 @@ public:
|
||||
nscoord mCurrentInflationContainerWidth;
|
||||
|
||||
protected:
|
||||
|
||||
nsRefPtrHashtable<nsPtrHashKey<nsIFrame>, nsImageLoader>
|
||||
mImageLoaders[IMAGE_LOAD_TYPE_COUNT];
|
||||
|
||||
nsWeakPtr mContainer;
|
||||
|
||||
PRCList mDOMMediaQueryLists;
|
||||
|
@ -154,6 +154,7 @@
|
||||
#include "nsHTMLMediaElement.h"
|
||||
#endif
|
||||
#include "nsSMILAnimationController.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
@ -2112,11 +2113,10 @@ PresShell::FireResizeEvent()
|
||||
void
|
||||
PresShell::SetIgnoreFrameDestruction(bool aIgnore)
|
||||
{
|
||||
if (mPresContext) {
|
||||
// We need to destroy the image loaders first, as they won't be
|
||||
// notified when frames are destroyed once this setting takes effect.
|
||||
// (See bug 673984)
|
||||
mPresContext->DestroyImageLoaders();
|
||||
if (mDocument) {
|
||||
// We need to tell the ImageLoader to drop all its references to frames
|
||||
// because they're about to go away and it won't get notifications of that.
|
||||
mDocument->StyleImageLoader()->ClearAll();
|
||||
}
|
||||
mIgnoreFrameDestruction = aIgnore;
|
||||
}
|
||||
@ -2129,7 +2129,7 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame)
|
||||
mPresContext->ForgetUpdatePluginGeometryFrame(aFrame);
|
||||
|
||||
if (!mIgnoreFrameDestruction) {
|
||||
mPresContext->StopImagesFor(aFrame);
|
||||
mDocument->StyleImageLoader()->DropRequestsForFrame(aFrame);
|
||||
|
||||
mFrameConstructor->NotifyDestroyingFrame(aFrame);
|
||||
|
||||
|
@ -129,10 +129,12 @@
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::layout;
|
||||
using namespace mozilla::css;
|
||||
|
||||
// Struct containing cached metrics for box-wrapped frames.
|
||||
struct nsBoxLayoutMetrics
|
||||
@ -707,6 +709,8 @@ EqualImages(imgIRequest *aOldImage, imgIRequest *aNewImage)
|
||||
/* virtual */ void
|
||||
nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
||||
{
|
||||
ImageLoader* imageLoader = PresContext()->Document()->StyleImageLoader();
|
||||
|
||||
if (aOldStyleContext) {
|
||||
// If the old context had a background image image and new context
|
||||
// does not have the same image, clear the image load notifier
|
||||
@ -719,12 +723,29 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
||||
const nsStyleBackground *oldBG = aOldStyleContext->GetStyleBackground();
|
||||
const nsStyleBackground *newBG = GetStyleBackground();
|
||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, oldBG) {
|
||||
// If there is an image in oldBG that's not in newBG, drop it.
|
||||
if (i >= newBG->mImageCount ||
|
||||
oldBG->mLayers[i].mImage != newBG->mLayers[i].mImage) {
|
||||
// stop the image loading for the frame, the image has changed
|
||||
PresContext()->SetImageLoaders(this,
|
||||
nsPresContext::BACKGROUND_IMAGE, nsnull);
|
||||
break;
|
||||
const nsStyleImage& oldImage = oldBG->mLayers[i].mImage;
|
||||
if (oldImage.GetType() != eStyleImageType_Image) {
|
||||
continue;
|
||||
}
|
||||
|
||||
imageLoader->DisassociateRequestFromFrame(oldImage.GetImageData(),
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, newBG) {
|
||||
// If there is an image in newBG that's not in oldBG, add it.
|
||||
if (i >= oldBG->mImageCount ||
|
||||
newBG->mLayers[i].mImage != oldBG->mLayers[i].mImage) {
|
||||
const nsStyleImage& newImage = newBG->mLayers[i].mImage;
|
||||
if (newImage.GetType() != eStyleImageType_Image) {
|
||||
continue;
|
||||
}
|
||||
|
||||
imageLoader->AssociateRequestToFrame(newImage.GetImageData(), this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -766,6 +787,7 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
||||
imgIRequest *oldBorderImage = aOldStyleContext
|
||||
? aOldStyleContext->GetStyleBorder()->GetBorderImage()
|
||||
: nsnull;
|
||||
imgIRequest *newBorderImage = GetStyleBorder()->GetBorderImage();
|
||||
// For border-images, we can't be as conservative (we need to set the
|
||||
// new loaders if there has been any change) since the CalcDifference
|
||||
// call depended on the result of GetActualBorder() and that result
|
||||
@ -779,9 +801,14 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
||||
// is loaded) and paint. We also don't really care about any callers
|
||||
// who try to paint borders with a different style context, because
|
||||
// they won't have the correct size for the border either.
|
||||
if (!EqualImages(oldBorderImage, GetStyleBorder()->GetBorderImage())) {
|
||||
if (!EqualImages(oldBorderImage, newBorderImage)) {
|
||||
// stop and restart the image loading/notification
|
||||
PresContext()->SetupBorderImageLoaders(this, GetStyleBorder());
|
||||
if (oldBorderImage) {
|
||||
imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
|
||||
}
|
||||
if (newBorderImage) {
|
||||
imageLoader->AssociateRequestToFrame(newBorderImage, this);
|
||||
}
|
||||
}
|
||||
|
||||
// If the page contains markup that overrides text direction, and
|
||||
|
449
layout/style/ImageLoader.cpp
Normal file
449
layout/style/ImageLoader.cpp
Normal file
@ -0,0 +1,449 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* A class that handles style system image loads (other image loads are handled
|
||||
* by the nodes in the content tree).
|
||||
*/
|
||||
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsNetError.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
/* static */ PLDHashOperator
|
||||
ImageLoader::SetAnimationModeEnumerator(nsISupports* aKey, FrameSet* aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
imgIRequest* request = static_cast<imgIRequest*>(aKey);
|
||||
|
||||
PRUint16* mode = static_cast<PRUint16*>(aClosure);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<imgIRequest> debugRequest = do_QueryInterface(aKey);
|
||||
NS_ASSERTION(debugRequest == request, "This is bad");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
request->GetImage(getter_AddRefs(container));
|
||||
if (!container) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// This can fail if the image is in error, and we don't care.
|
||||
container->SetAnimationMode(*mode);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ImageLoader::Init()
|
||||
{
|
||||
MOZ_ASSERT(mDocument);
|
||||
|
||||
if (!mRequestToFrameMap.Init() ||
|
||||
!mFrameToRequestMap.Init() ||
|
||||
!mImages.Init()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DropDocumentReference()
|
||||
{
|
||||
ClearAll();
|
||||
mDocument = nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::AssociateRequestToFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
MOZ_ASSERT(mRequestToFrameMap.IsInitialized() &&
|
||||
mFrameToRequestMap.IsInitialized() &&
|
||||
mImages.IsInitialized());
|
||||
|
||||
nsCOMPtr<imgIDecoderObserver> observer;
|
||||
aRequest->GetDecoderObserver(getter_AddRefs(observer));
|
||||
if (!observer) {
|
||||
// The request has already been canceled, so ignore it. This is ok because
|
||||
// we're not going to get any more notifications from a canceled request.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(observer == this);
|
||||
|
||||
FrameSet* frameSet = nsnull;
|
||||
if (mRequestToFrameMap.Get(aRequest, &frameSet)) {
|
||||
NS_ASSERTION(frameSet, "This should never be null!");
|
||||
}
|
||||
|
||||
if (!frameSet) {
|
||||
nsAutoPtr<FrameSet> newFrameSet(new FrameSet());
|
||||
|
||||
bool result = mRequestToFrameMap.Put(aRequest, newFrameSet);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
frameSet = newFrameSet.forget();
|
||||
}
|
||||
|
||||
RequestSet* requestSet = nsnull;
|
||||
if (mFrameToRequestMap.Get(aFrame, &requestSet)) {
|
||||
NS_ASSERTION(requestSet, "This should never be null");
|
||||
}
|
||||
|
||||
if (!requestSet) {
|
||||
nsAutoPtr<RequestSet> newRequestSet(new RequestSet());
|
||||
|
||||
bool result = mFrameToRequestMap.Put(aFrame, newRequestSet);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
requestSet = newRequestSet.forget();
|
||||
}
|
||||
|
||||
// Add these to the sets, but only if they're not already there.
|
||||
PRUint32 i;
|
||||
if (!frameSet->GreatestIndexLtEq(aFrame, i)) {
|
||||
frameSet->InsertElementAt(i, aFrame);
|
||||
}
|
||||
if (!requestSet->GreatestIndexLtEq(aRequest, i)) {
|
||||
requestSet->InsertElementAt(i, aRequest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::MaybeRegisterCSSImage(nsCSSValue::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(aImage, "This should never be null!");
|
||||
|
||||
bool found = false;
|
||||
aImage->mRequests.GetWeak(mDocument, &found);
|
||||
if (found) {
|
||||
// This document already has a request.
|
||||
return;
|
||||
}
|
||||
|
||||
imgIRequest* canonicalRequest = aImage->mRequests.GetWeak(nsnull);
|
||||
if (!canonicalRequest) {
|
||||
// The image was blocked or something.
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIRequest> request;
|
||||
|
||||
// Ignore errors here. If cloning fails for some reason we'll put a null
|
||||
// entry in the hash and we won't keep trying to clone.
|
||||
mInClone = true;
|
||||
canonicalRequest->Clone(this, getter_AddRefs(request));
|
||||
mInClone = false;
|
||||
|
||||
aImage->mRequests.Put(mDocument, request);
|
||||
|
||||
AddImage(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DeregisterCSSImage(nsCSSValue::Image* aImage)
|
||||
{
|
||||
RemoveImage(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DisassociateRequestFromFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
FrameSet* frameSet = nsnull;
|
||||
RequestSet* requestSet = nsnull;
|
||||
|
||||
MOZ_ASSERT(mRequestToFrameMap.IsInitialized() &&
|
||||
mFrameToRequestMap.IsInitialized() &&
|
||||
mImages.IsInitialized());
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<imgIDecoderObserver> observer;
|
||||
aRequest->GetDecoderObserver(getter_AddRefs(observer));
|
||||
MOZ_ASSERT(!observer || observer == this);
|
||||
}
|
||||
#endif
|
||||
|
||||
mRequestToFrameMap.Get(aRequest, &frameSet);
|
||||
mFrameToRequestMap.Get(aFrame, &requestSet);
|
||||
|
||||
if (frameSet) {
|
||||
frameSet->RemoveElementSorted(aFrame);
|
||||
}
|
||||
if (requestSet) {
|
||||
requestSet->RemoveElementSorted(aRequest);
|
||||
}
|
||||
|
||||
if (frameSet && !frameSet->Length()) {
|
||||
mRequestToFrameMap.Remove(aRequest);
|
||||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
nsLayoutUtils::DeregisterImageRequest(presContext,
|
||||
aRequest,
|
||||
nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
if (requestSet && !requestSet->Length()) {
|
||||
mFrameToRequestMap.Remove(aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DropRequestsForFrame(nsIFrame* aFrame)
|
||||
{
|
||||
RequestSet* requestSet = nsnull;
|
||||
if (!mFrameToRequestMap.Get(aFrame, &requestSet)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(requestSet, "This should never be null");
|
||||
|
||||
RequestSet frozenRequestSet(*requestSet);
|
||||
for (RequestSet::size_type i = frozenRequestSet.Length(); i != 0; --i) {
|
||||
imgIRequest* request = frozenRequestSet.ElementAt(i - 1);
|
||||
|
||||
DisassociateRequestFromFrame(request, aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::SetAnimationMode(PRUint16 aMode)
|
||||
{
|
||||
NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
|
||||
aMode == imgIContainer::kDontAnimMode ||
|
||||
aMode == imgIContainer::kLoopOnceAnimMode,
|
||||
"Wrong Animation Mode is being set!");
|
||||
|
||||
mRequestToFrameMap.EnumerateRead(SetAnimationModeEnumerator, &aMode);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
ClearImageHashSet(nsPtrHashKey<nsCSSValue::Image>* aKey, void* aClosure)
|
||||
{
|
||||
nsIDocument* doc = static_cast<nsIDocument*>(aClosure);
|
||||
nsCSSValue::Image* image = aKey->GetKey();
|
||||
|
||||
imgIRequest* request = image->mRequests.GetWeak(doc);
|
||||
if (request) {
|
||||
request->CancelAndForgetObserver(NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
image->mRequests.Remove(doc);
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::ClearAll()
|
||||
{
|
||||
mRequestToFrameMap.Clear();
|
||||
mFrameToRequestMap.Clear();
|
||||
mImages.EnumerateEntries(&ClearImageHashSet, mDocument);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::LoadImage(nsIURI* aURI, nsIPrincipal* aOriginPrincipal,
|
||||
nsIURI* aReferrer, nsCSSValue::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(aImage->mRequests.Count() == 0, "Huh?");
|
||||
|
||||
aImage->mRequests.Put(nsnull, nsnull);
|
||||
|
||||
if (!aURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nsContentUtils::CanLoadImage(aURI, mDocument, mDocument,
|
||||
aOriginPrincipal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIRequest> request;
|
||||
nsContentUtils::LoadImage(aURI, mDocument, aOriginPrincipal, aReferrer,
|
||||
nsnull, nsIRequest::LOAD_NORMAL,
|
||||
getter_AddRefs(request));
|
||||
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIRequest> clonedRequest;
|
||||
mInClone = true;
|
||||
nsresult rv = request->Clone(this, getter_AddRefs(clonedRequest));
|
||||
mInClone = false;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aImage->mRequests.Put(nsnull, request);
|
||||
aImage->mRequests.Put(mDocument, clonedRequest);
|
||||
|
||||
AddImage(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::AddImage(nsCSSValue::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(!mImages.Contains(aImage), "Huh?");
|
||||
if (!mImages.PutEntry(aImage)) {
|
||||
NS_RUNTIMEABORT("OOM");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::RemoveImage(nsCSSValue::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(mImages.Contains(aImage), "Huh?");
|
||||
mImages.RemoveEntry(aImage);
|
||||
}
|
||||
|
||||
nsPresContext*
|
||||
ImageLoader::GetPresContext()
|
||||
{
|
||||
if (!mDocument) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = mDocument->GetShell();
|
||||
if (!shell) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return shell->GetPresContext();
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DoRedraw(FrameSet* aFrameSet)
|
||||
{
|
||||
NS_ASSERTION(aFrameSet, "Must have a frame set");
|
||||
NS_ASSERTION(mDocument, "Should have returned earlier!");
|
||||
NS_ASSERTION(mHavePainted, "Should have returned earlier!");
|
||||
|
||||
FrameSet::size_type length = aFrameSet->Length();
|
||||
for (FrameSet::size_type i = 0; i < length; i++) {
|
||||
nsIFrame* frame = aFrameSet->ElementAt(i);
|
||||
|
||||
// NOTE: It is not sufficient to invalidate only the size of the image:
|
||||
// the image may be tiled!
|
||||
// The best option is to call into the frame, however lacking this
|
||||
// we have to at least invalidate the frame's bounds, hence
|
||||
// as long as we have a frame we'll use its size.
|
||||
//
|
||||
|
||||
// Invalidate the entire frame
|
||||
// XXX We really only need to invalidate the client area of the frame...
|
||||
|
||||
nsRect bounds(nsPoint(0, 0), frame->GetSize());
|
||||
|
||||
if (frame->GetType() == nsGkAtoms::canvasFrame) {
|
||||
// The canvas's background covers the whole viewport.
|
||||
bounds = frame->GetVisualOverflowRect();
|
||||
}
|
||||
|
||||
if (frame->GetStyleVisibility()->IsVisible()) {
|
||||
frame->Invalidate(bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(ImageLoader)
|
||||
NS_IMPL_RELEASE(ImageLoader)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ImageLoader)
|
||||
NS_INTERFACE_MAP_ENTRY(imgIDecoderObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(imgIContainerObserver)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageLoader::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (!presContext) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aImage->SetAnimationMode(presContext->ImageAnimationMode());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageLoader::OnImageIsAnimated(imgIRequest* aRequest)
|
||||
{
|
||||
// NB: Don't ignore this when cloning, it's our only chance to register
|
||||
// the request with the refresh driver.
|
||||
if (!mDocument) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Register with the refresh driver now that we are aware that
|
||||
// we are animated.
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
nsLayoutUtils::RegisterImageRequest(presContext,
|
||||
aRequest,
|
||||
nsnull);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageLoader::OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame)
|
||||
{
|
||||
if (!mDocument || !mHavePainted || mInClone) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FrameSet* frameSet = nsnull;
|
||||
if (!mRequestToFrameMap.Get(aRequest, &frameSet)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(frameSet, "This should never be null!");
|
||||
|
||||
DoRedraw(frameSet);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageLoader::FrameChanged(imgIRequest *aRequest,
|
||||
imgIContainer *aContainer,
|
||||
const nsIntRect *aDirtyRect)
|
||||
{
|
||||
if (!mDocument || !mHavePainted || mInClone) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FrameSet* frameSet = nsnull;
|
||||
if (!mRequestToFrameMap.Get(aRequest, &frameSet)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(frameSet, "This should never be null!");
|
||||
|
||||
DoRedraw(frameSet);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
124
layout/style/ImageLoader.h
Normal file
124
layout/style/ImageLoader.h
Normal file
@ -0,0 +1,124 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// A class that handles style system image loads (other image loads are handled
|
||||
// by the nodes in the content tree).
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "nsStubImageDecoderObserver.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsIDocument;
|
||||
class nsPresContext;
|
||||
class nsIURI;
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
class ImageLoader : public nsStubImageDecoderObserver {
|
||||
public:
|
||||
ImageLoader(nsIDocument* aDocument)
|
||||
: mDocument(aDocument),
|
||||
mHavePainted(false),
|
||||
mInClone(false)
|
||||
{ }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// imgIDecoderObserver (override nsStubImageDecoderObserver)
|
||||
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
|
||||
NS_IMETHOD OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame);
|
||||
NS_IMETHOD OnImageIsAnimated(imgIRequest *aRequest);
|
||||
// Do not override OnDataAvailable since background images are not
|
||||
// displayed incrementally; they are displayed after the entire image
|
||||
// has been loaded.
|
||||
|
||||
// imgIContainerObserver (override nsStubImageDecoderObserver)
|
||||
NS_IMETHOD FrameChanged(imgIRequest* aRequest,
|
||||
imgIContainer *aContainer,
|
||||
const nsIntRect *aDirtyRect);
|
||||
|
||||
nsresult Init();
|
||||
|
||||
inline void NotifyPaint()
|
||||
{
|
||||
mHavePainted = true;
|
||||
}
|
||||
|
||||
void DropDocumentReference();
|
||||
|
||||
void MaybeRegisterCSSImage(nsCSSValue::Image* aImage);
|
||||
void DeregisterCSSImage(nsCSSValue::Image* aImage);
|
||||
|
||||
void AssociateRequestToFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
void DisassociateRequestFromFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
void DropRequestsForFrame(nsIFrame* aFrame);
|
||||
|
||||
void SetAnimationMode(PRUint16 aMode);
|
||||
|
||||
void ClearAll();
|
||||
|
||||
void LoadImage(nsIURI* aURI, nsIPrincipal* aPrincipal, nsIURI* aReferrer,
|
||||
nsCSSValue::Image* aCSSValue);
|
||||
|
||||
void DestroyRequest(imgIRequest* aRequest);
|
||||
|
||||
private:
|
||||
// We need to be able to look up the frames associated with a request (for
|
||||
// delivering notifications) and the requests associated with a frame (when
|
||||
// the frame goes away). Thus we maintain hashtables going both ways. These
|
||||
// should always be in sync.
|
||||
|
||||
typedef nsTArray<nsIFrame*> FrameSet;
|
||||
typedef nsTArray<nsCOMPtr<imgIRequest> > RequestSet;
|
||||
typedef nsTHashtable<nsPtrHashKey<nsCSSValue::Image> > ImageHashSet;
|
||||
typedef nsClassHashtable<nsISupportsHashKey,
|
||||
FrameSet> RequestToFrameMap;
|
||||
typedef nsClassHashtable<nsPtrHashKey<nsIFrame>,
|
||||
RequestSet> FrameToRequestMap;
|
||||
|
||||
void AddImage(nsCSSValue::Image* aCSSImage);
|
||||
void RemoveImage(nsCSSValue::Image* aCSSImage);
|
||||
|
||||
nsPresContext* GetPresContext();
|
||||
|
||||
void DoRedraw(FrameSet* aFrameSet);
|
||||
|
||||
static PLDHashOperator
|
||||
SetAnimationModeEnumerator(nsISupports* aKey, FrameSet* aValue,
|
||||
void* aClosure);
|
||||
|
||||
// A map of imgIRequests to the nsIFrames that are using them.
|
||||
RequestToFrameMap mRequestToFrameMap;
|
||||
|
||||
// A map of nsIFrames to the imgIRequests they use.
|
||||
FrameToRequestMap mFrameToRequestMap;
|
||||
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
nsIDocument* mDocument;
|
||||
|
||||
// The set of all nsCSSValue::Images (whether they're associated a frame or
|
||||
// not). We'll need this when we go away to remove any requests associated
|
||||
// with our document from those Images.
|
||||
ImageHashSet mImages;
|
||||
|
||||
// Have we painted yet? If not, no need to deliver notifications.
|
||||
bool mHavePainted;
|
||||
|
||||
// Are we cloning? If so, ignore any notifications we get.
|
||||
bool mInClone;
|
||||
};
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
@ -101,6 +101,7 @@ EXPORTS = \
|
||||
EXPORTS_mozilla/css = \
|
||||
Declaration.h \
|
||||
GroupRule.h \
|
||||
ImageLoader.h \
|
||||
ImportRule.h \
|
||||
Loader.h \
|
||||
NameSpaceRule.h \
|
||||
@ -114,6 +115,7 @@ CPPSRCS = \
|
||||
nsCSSDataBlock.cpp \
|
||||
Declaration.cpp \
|
||||
nsCSSKeywords.cpp \
|
||||
ImageLoader.cpp \
|
||||
Loader.cpp \
|
||||
nsAnimationManager.cpp \
|
||||
nsCSSParser.cpp \
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
#include "nsCSSDataBlock.h"
|
||||
#include "mozilla/css/Declaration.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsStyleContext.h"
|
||||
@ -79,16 +80,25 @@ ShouldIgnoreColors(nsRuleData *aRuleData)
|
||||
static void
|
||||
TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument)
|
||||
{
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
if (aValue.GetUnit() == eCSSUnit_URL) {
|
||||
aValue.StartImageLoad(aDocument);
|
||||
}
|
||||
else if (aValue.GetUnit() == eCSSUnit_Image) {
|
||||
// If we already have a request, see if this document needs to clone it.
|
||||
imgIRequest* request = aValue.GetImageValue(nsnull);
|
||||
|
||||
if (request) {
|
||||
aDocument->StyleImageLoader()->MaybeRegisterCSSImage(aValue.GetImageStructValue());
|
||||
}
|
||||
}
|
||||
else if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
|
||||
nsCSSValue::Array* arguments = aValue.GetArrayValue();
|
||||
NS_ABORT_IF_FALSE(arguments->Count() == 6, "unexpected num of arguments");
|
||||
|
||||
const nsCSSValue& image = arguments->Item(1);
|
||||
if (image.GetUnit() == eCSSUnit_URL)
|
||||
image.StartImageLoad(aDocument);
|
||||
TryToStartImageLoadOnValue(image, aDocument);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "nsStyleUtil.h"
|
||||
#include "CSSCalc.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
|
||||
namespace css = mozilla::css;
|
||||
|
||||
@ -272,10 +273,10 @@ double nsCSSValue::GetAngleValueInRadians() const
|
||||
}
|
||||
}
|
||||
|
||||
imgIRequest* nsCSSValue::GetImageValue() const
|
||||
imgIRequest* nsCSSValue::GetImageValue(nsIDocument* aDocument) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Image, "not an Image value");
|
||||
return mValue.mImage->mRequest;
|
||||
return mValue.mImage->mRequests.GetWeak(aDocument);
|
||||
}
|
||||
|
||||
nscoord nsCSSValue::GetFixedLength(nsPresContext* aPresContext) const
|
||||
@ -1679,17 +1680,43 @@ nsCSSValue::Image::Image(nsIURI* aURI, nsStringBuffer* aString,
|
||||
if (aDocument->GetOriginalDocument()) {
|
||||
aDocument = aDocument->GetOriginalDocument();
|
||||
}
|
||||
if (aURI &&
|
||||
nsContentUtils::CanLoadImage(aURI, aDocument, aDocument,
|
||||
aOriginPrincipal)) {
|
||||
nsContentUtils::LoadImage(aURI, aDocument, aOriginPrincipal, aReferrer,
|
||||
nsnull, nsIRequest::LOAD_NORMAL,
|
||||
getter_AddRefs(mRequest));
|
||||
|
||||
if (!mRequests.Init()) {
|
||||
NS_RUNTIMEABORT("out of memory");
|
||||
}
|
||||
|
||||
aDocument->StyleImageLoader()->LoadImage(aURI, aOriginPrincipal, aReferrer,
|
||||
this);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
ClearRequestHashtable(nsISupports* aKey, nsCOMPtr<imgIRequest>& aValue,
|
||||
void* aClosure)
|
||||
{
|
||||
nsCSSValue::Image* image = static_cast<nsCSSValue::Image*>(aClosure);
|
||||
nsIDocument* doc = static_cast<nsIDocument*>(aKey);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIDocument> slowDoc = do_QueryInterface(aKey);
|
||||
MOZ_ASSERT(slowDoc == doc);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (doc) {
|
||||
doc->StyleImageLoader()->DeregisterCSSImage(image);
|
||||
}
|
||||
|
||||
if (aValue) {
|
||||
aValue->CancelAndForgetObserver(NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
nsCSSValue::Image::~Image()
|
||||
{
|
||||
mRequests.Enumerate(&ClearRequestHashtable, this);
|
||||
}
|
||||
|
||||
nsCSSValueGradientStop::nsCSSValueGradientStop()
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "nsCSSProperty.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsTArray.h"
|
||||
@ -58,6 +59,8 @@ class nsIDocument;
|
||||
class nsIPrincipal;
|
||||
class nsPresContext;
|
||||
class nsIURI;
|
||||
template <class T>
|
||||
class nsPtrHashKey;
|
||||
|
||||
// Deletes a linked list iteratively to avoid blowing up the stack (bug 456196).
|
||||
#define NS_CSS_DELETE_LIST_MEMBER(type_, ptr_, member_) \
|
||||
@ -386,6 +389,12 @@ public:
|
||||
return mValue.mURL;
|
||||
}
|
||||
|
||||
Image* GetImageStructValue() const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Image, "not an Image value");
|
||||
return mValue.mImage;
|
||||
}
|
||||
|
||||
const PRUnichar* GetOriginalURLValue() const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image,
|
||||
@ -398,7 +407,7 @@ public:
|
||||
// Not making this inline because that would force us to include
|
||||
// imgIRequest.h, which leads to REQUIRES hell, since this header is included
|
||||
// all over.
|
||||
imgIRequest* GetImageValue() const;
|
||||
imgIRequest* GetImageValue(nsIDocument* aDocument) const;
|
||||
|
||||
nscoord GetFixedLength(nsPresContext* aPresContext) const;
|
||||
nscoord GetPixelLength() const;
|
||||
@ -517,7 +526,7 @@ public:
|
||||
|
||||
// Inherit operator== from nsCSSValue::URL
|
||||
|
||||
nsCOMPtr<imgIRequest> mRequest; // null == image load blocked or somehow failed
|
||||
nsInterfaceHashtable<nsISupportsHashKey, imgIRequest> mRequests;
|
||||
|
||||
// Override AddRef and Release to not only log ourselves correctly, but
|
||||
// also so that we delete correctly without a virtual destructor
|
||||
|
@ -103,6 +103,12 @@ using namespace mozilla::dom;
|
||||
method_(req); \
|
||||
}
|
||||
|
||||
#define NS_SET_IMAGE_REQUEST_WITH_DOC(method_, context_, requestgetter_) \
|
||||
{ \
|
||||
nsIDocument* doc = (context_)->PresContext()->Document(); \
|
||||
NS_SET_IMAGE_REQUEST(method_, context_, requestgetter_(doc)) \
|
||||
}
|
||||
|
||||
/*
|
||||
* For storage of an |nsRuleNode|'s children in a PLDHashTable.
|
||||
*/
|
||||
@ -933,9 +939,9 @@ static void SetStyleImageToImageRect(nsStyleContext* aStyleContext,
|
||||
|
||||
// <uri>
|
||||
if (arr->Item(1).GetUnit() == eCSSUnit_Image) {
|
||||
NS_SET_IMAGE_REQUEST(aResult.SetImageData,
|
||||
NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
|
||||
aStyleContext,
|
||||
arr->Item(1).GetImageValue())
|
||||
arr->Item(1).GetImageValue)
|
||||
} else {
|
||||
NS_WARNING("nsCSSValue::Image::Image() failed?");
|
||||
}
|
||||
@ -965,9 +971,9 @@ static void SetStyleImage(nsStyleContext* aStyleContext,
|
||||
|
||||
switch (aValue.GetUnit()) {
|
||||
case eCSSUnit_Image:
|
||||
NS_SET_IMAGE_REQUEST(aResult.SetImageData,
|
||||
NS_SET_IMAGE_REQUEST_WITH_DOC(aResult.SetImageData,
|
||||
aStyleContext,
|
||||
aValue.GetImageValue())
|
||||
aValue.GetImageValue)
|
||||
break;
|
||||
case eCSSUnit_Function:
|
||||
if (aValue.EqualsFunction(eCSSKeyword__moz_image_rect)) {
|
||||
@ -3625,9 +3631,10 @@ nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
|
||||
cursorUnit).get());
|
||||
const nsCSSValueList* list = cursorValue->GetListValue();
|
||||
const nsCSSValueList* list2 = list;
|
||||
nsIDocument* doc = aContext->PresContext()->Document();
|
||||
PRUint32 arrayLength = 0;
|
||||
for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext)
|
||||
if (list->mValue.GetArrayValue()->Item(0).GetImageValue())
|
||||
if (list->mValue.GetArrayValue()->Item(0).GetImageValue(doc))
|
||||
++arrayLength;
|
||||
|
||||
if (arrayLength != 0) {
|
||||
@ -3639,7 +3646,7 @@ nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
|
||||
list2->mValue.GetUnit() == eCSSUnit_Array;
|
||||
list2 = list2->mNext) {
|
||||
nsCSSValue::Array *arr = list2->mValue.GetArrayValue();
|
||||
imgIRequest *req = arr->Item(0).GetImageValue();
|
||||
imgIRequest *req = arr->Item(0).GetImageValue(doc);
|
||||
if (req) {
|
||||
item->SetImage(req);
|
||||
if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
|
||||
@ -5727,11 +5734,13 @@ nsRuleNode::ComputeBorderData(void* aStartStruct,
|
||||
// border-image-source
|
||||
const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
|
||||
if (borderImageSource->GetUnit() == eCSSUnit_Image) {
|
||||
NS_SET_IMAGE_REQUEST(border->SetBorderImage, aContext,
|
||||
borderImageSource->GetImageValue());
|
||||
NS_SET_IMAGE_REQUEST_WITH_DOC(border->SetBorderImage,
|
||||
aContext,
|
||||
borderImageSource->GetImageValue);
|
||||
} else if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
|
||||
canStoreInRuleTree = false;
|
||||
NS_SET_IMAGE_REQUEST(border->SetBorderImage, aContext,
|
||||
NS_SET_IMAGE_REQUEST(border->SetBorderImage,
|
||||
aContext,
|
||||
parentBorder->GetBorderImage());
|
||||
} else if (borderImageSource->GetUnit() == eCSSUnit_Initial ||
|
||||
borderImageSource->GetUnit() == eCSSUnit_None) {
|
||||
@ -5982,9 +5991,9 @@ nsRuleNode::ComputeListData(void* aStartStruct,
|
||||
// list-style-image: url, none, inherit
|
||||
const nsCSSValue* imageValue = aRuleData->ValueForListStyleImage();
|
||||
if (eCSSUnit_Image == imageValue->GetUnit()) {
|
||||
NS_SET_IMAGE_REQUEST(list->SetListStyleImage,
|
||||
NS_SET_IMAGE_REQUEST_WITH_DOC(list->SetListStyleImage,
|
||||
aContext,
|
||||
imageValue->GetImageValue())
|
||||
imageValue->GetImageValue)
|
||||
}
|
||||
else if (eCSSUnit_None == imageValue->GetUnit() ||
|
||||
eCSSUnit_Initial == imageValue->GetUnit()) {
|
||||
@ -6303,7 +6312,9 @@ nsRuleNode::ComputeContentData(void* aStartStruct,
|
||||
}
|
||||
data.mType = type;
|
||||
if (type == eStyleContentType_Image) {
|
||||
NS_SET_IMAGE_REQUEST(data.SetImage, aContext, value.GetImageValue());
|
||||
NS_SET_IMAGE_REQUEST_WITH_DOC(data.SetImage,
|
||||
aContext,
|
||||
value.GetImageValue);
|
||||
}
|
||||
else if (type <= eStyleContentType_Attr) {
|
||||
value.GetStringValue(buffer);
|
||||
|
Loading…
Reference in New Issue
Block a user