1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/svg/nsSVGImageFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,607 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// Keep in (case-insensitive) order: 1.10 +#include "gfxContext.h" 1.11 +#include "gfxPlatform.h" 1.12 +#include "mozilla/gfx/2D.h" 1.13 +#include "imgIContainer.h" 1.14 +#include "nsIImageLoadingContent.h" 1.15 +#include "nsLayoutUtils.h" 1.16 +#include "nsRenderingContext.h" 1.17 +#include "imgINotificationObserver.h" 1.18 +#include "nsSVGEffects.h" 1.19 +#include "nsSVGPathGeometryFrame.h" 1.20 +#include "mozilla/dom/SVGSVGElement.h" 1.21 +#include "nsSVGUtils.h" 1.22 +#include "SVGContentUtils.h" 1.23 +#include "SVGImageContext.h" 1.24 +#include "mozilla/dom/SVGImageElement.h" 1.25 +#include "nsContentUtils.h" 1.26 +#include "nsIReflowCallback.h" 1.27 + 1.28 +using namespace mozilla; 1.29 +using namespace mozilla::dom; 1.30 +using namespace mozilla::gfx; 1.31 + 1.32 +class nsSVGImageFrame; 1.33 + 1.34 +class nsSVGImageListener MOZ_FINAL : public imgINotificationObserver 1.35 +{ 1.36 +public: 1.37 + nsSVGImageListener(nsSVGImageFrame *aFrame); 1.38 + 1.39 + NS_DECL_ISUPPORTS 1.40 + NS_DECL_IMGINOTIFICATIONOBSERVER 1.41 + 1.42 + void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; } 1.43 + 1.44 +private: 1.45 + nsSVGImageFrame *mFrame; 1.46 +}; 1.47 + 1.48 +typedef nsSVGPathGeometryFrame nsSVGImageFrameBase; 1.49 + 1.50 +class nsSVGImageFrame : public nsSVGImageFrameBase, 1.51 + public nsIReflowCallback 1.52 +{ 1.53 + friend nsIFrame* 1.54 + NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.55 + 1.56 +protected: 1.57 + nsSVGImageFrame(nsStyleContext* aContext) : nsSVGImageFrameBase(aContext), 1.58 + mReflowCallbackPosted(false) {} 1.59 + virtual ~nsSVGImageFrame(); 1.60 + 1.61 +public: 1.62 + NS_DECL_FRAMEARENA_HELPERS 1.63 + 1.64 + // nsISVGChildFrame interface: 1.65 + virtual nsresult PaintSVG(nsRenderingContext *aContext, 1.66 + const nsIntRect *aDirtyRect, 1.67 + nsIFrame* aTransformRoot) MOZ_OVERRIDE; 1.68 + virtual nsIFrame* GetFrameForPoint(const nsPoint &aPoint) MOZ_OVERRIDE; 1.69 + virtual void ReflowSVG() MOZ_OVERRIDE; 1.70 + 1.71 + // nsSVGPathGeometryFrame methods: 1.72 + virtual uint16_t GetHitTestFlags() MOZ_OVERRIDE; 1.73 + 1.74 + // nsIFrame interface: 1.75 + virtual nsresult AttributeChanged(int32_t aNameSpaceID, 1.76 + nsIAtom* aAttribute, 1.77 + int32_t aModType) MOZ_OVERRIDE; 1.78 + virtual void Init(nsIContent* aContent, 1.79 + nsIFrame* aParent, 1.80 + nsIFrame* aPrevInFlow) MOZ_OVERRIDE; 1.81 + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; 1.82 + 1.83 + /** 1.84 + * Get the "type" of the frame 1.85 + * 1.86 + * @see nsGkAtoms::svgImageFrame 1.87 + */ 1.88 + virtual nsIAtom* GetType() const MOZ_OVERRIDE; 1.89 + 1.90 +#ifdef DEBUG_FRAME_DUMP 1.91 + virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE 1.92 + { 1.93 + return MakeFrameName(NS_LITERAL_STRING("SVGImage"), aResult); 1.94 + } 1.95 +#endif 1.96 + 1.97 + // nsIReflowCallback 1.98 + virtual bool ReflowFinished() MOZ_OVERRIDE; 1.99 + virtual void ReflowCallbackCanceled() MOZ_OVERRIDE; 1.100 + 1.101 +private: 1.102 + gfx::Matrix GetRasterImageTransform(int32_t aNativeWidth, 1.103 + int32_t aNativeHeight, 1.104 + uint32_t aFor, 1.105 + nsIFrame* aTransformRoot = nullptr); 1.106 + gfx::Matrix GetVectorImageTransform(uint32_t aFor, 1.107 + nsIFrame* aTransformRoot = nullptr); 1.108 + bool TransformContextForPainting(gfxContext* aGfxContext, 1.109 + nsIFrame* aTransformRoot); 1.110 + 1.111 + nsCOMPtr<imgINotificationObserver> mListener; 1.112 + 1.113 + nsCOMPtr<imgIContainer> mImageContainer; 1.114 + 1.115 + bool mReflowCallbackPosted; 1.116 + 1.117 + friend class nsSVGImageListener; 1.118 +}; 1.119 + 1.120 +//---------------------------------------------------------------------- 1.121 +// Implementation 1.122 + 1.123 +nsIFrame* 1.124 +NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.125 +{ 1.126 + return new (aPresShell) nsSVGImageFrame(aContext); 1.127 +} 1.128 + 1.129 +NS_IMPL_FRAMEARENA_HELPERS(nsSVGImageFrame) 1.130 + 1.131 +nsSVGImageFrame::~nsSVGImageFrame() 1.132 +{ 1.133 + // set the frame to null so we don't send messages to a dead object. 1.134 + if (mListener) { 1.135 + nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent); 1.136 + if (imageLoader) { 1.137 + imageLoader->RemoveObserver(mListener); 1.138 + } 1.139 + reinterpret_cast<nsSVGImageListener*>(mListener.get())->SetFrame(nullptr); 1.140 + } 1.141 + mListener = nullptr; 1.142 +} 1.143 + 1.144 +void 1.145 +nsSVGImageFrame::Init(nsIContent* aContent, 1.146 + nsIFrame* aParent, 1.147 + nsIFrame* aPrevInFlow) 1.148 +{ 1.149 + NS_ASSERTION(aContent->IsSVG(nsGkAtoms::image), 1.150 + "Content is not an SVG image!"); 1.151 + 1.152 + nsSVGImageFrameBase::Init(aContent, aParent, aPrevInFlow); 1.153 + 1.154 + mListener = new nsSVGImageListener(this); 1.155 + nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent); 1.156 + if (!imageLoader) { 1.157 + NS_RUNTIMEABORT("Why is this not an image loading content?"); 1.158 + } 1.159 + 1.160 + // We should have a PresContext now, so let's notify our image loader that 1.161 + // we need to register any image animations with the refresh driver. 1.162 + imageLoader->FrameCreated(this); 1.163 + 1.164 + imageLoader->AddObserver(mListener); 1.165 +} 1.166 + 1.167 +/* virtual */ void 1.168 +nsSVGImageFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.169 +{ 1.170 + if (mReflowCallbackPosted) { 1.171 + PresContext()->PresShell()->CancelReflowCallback(this); 1.172 + mReflowCallbackPosted = false; 1.173 + } 1.174 + 1.175 + nsCOMPtr<nsIImageLoadingContent> imageLoader = 1.176 + do_QueryInterface(nsFrame::mContent); 1.177 + 1.178 + if (imageLoader) { 1.179 + imageLoader->FrameDestroyed(this); 1.180 + } 1.181 + 1.182 + nsFrame::DestroyFrom(aDestructRoot); 1.183 +} 1.184 + 1.185 +//---------------------------------------------------------------------- 1.186 +// nsIFrame methods: 1.187 + 1.188 +nsresult 1.189 +nsSVGImageFrame::AttributeChanged(int32_t aNameSpaceID, 1.190 + nsIAtom* aAttribute, 1.191 + int32_t aModType) 1.192 +{ 1.193 + if (aNameSpaceID == kNameSpaceID_None) { 1.194 + if (aAttribute == nsGkAtoms::x || 1.195 + aAttribute == nsGkAtoms::y || 1.196 + aAttribute == nsGkAtoms::width || 1.197 + aAttribute == nsGkAtoms::height) { 1.198 + nsSVGEffects::InvalidateRenderingObservers(this); 1.199 + nsSVGUtils::ScheduleReflowSVG(this); 1.200 + return NS_OK; 1.201 + } 1.202 + else if (aAttribute == nsGkAtoms::preserveAspectRatio) { 1.203 + // We don't paint the content of the image using display lists, therefore 1.204 + // we have to invalidate for this children-only transform changes since 1.205 + // there is no layer tree to notice that the transform changed and 1.206 + // recomposite. 1.207 + InvalidateFrame(); 1.208 + return NS_OK; 1.209 + } 1.210 + } 1.211 + if (aNameSpaceID == kNameSpaceID_XLink && 1.212 + aAttribute == nsGkAtoms::href) { 1.213 + 1.214 + // Prevent setting image.src by exiting early 1.215 + if (nsContentUtils::IsImageSrcSetDisabled()) { 1.216 + return NS_OK; 1.217 + } 1.218 + SVGImageElement *element = static_cast<SVGImageElement*>(mContent); 1.219 + 1.220 + if (element->mStringAttributes[SVGImageElement::HREF].IsExplicitlySet()) { 1.221 + element->LoadSVGImage(true, true); 1.222 + } else { 1.223 + element->CancelImageRequests(true); 1.224 + } 1.225 + } 1.226 + 1.227 + return nsSVGImageFrameBase::AttributeChanged(aNameSpaceID, 1.228 + aAttribute, aModType); 1.229 +} 1.230 + 1.231 +gfx::Matrix 1.232 +nsSVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth, 1.233 + int32_t aNativeHeight, 1.234 + uint32_t aFor, 1.235 + nsIFrame* aTransformRoot) 1.236 +{ 1.237 + float x, y, width, height; 1.238 + SVGImageElement *element = static_cast<SVGImageElement*>(mContent); 1.239 + element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); 1.240 + 1.241 + Matrix viewBoxTM = 1.242 + SVGContentUtils::GetViewBoxTransform(width, height, 1.243 + 0, 0, aNativeWidth, aNativeHeight, 1.244 + element->mPreserveAspectRatio); 1.245 + 1.246 + return viewBoxTM * 1.247 + gfx::Matrix::Translation(x, y) * 1.248 + gfx::ToMatrix(GetCanvasTM(aFor, aTransformRoot)); 1.249 +} 1.250 + 1.251 +gfx::Matrix 1.252 +nsSVGImageFrame::GetVectorImageTransform(uint32_t aFor, 1.253 + nsIFrame* aTransformRoot) 1.254 +{ 1.255 + float x, y, width, height; 1.256 + SVGImageElement *element = static_cast<SVGImageElement*>(mContent); 1.257 + element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); 1.258 + 1.259 + // No viewBoxTM needed here -- our height/width overrides any concept of 1.260 + // "native size" that the SVG image has, and it will handle viewBox and 1.261 + // preserveAspectRatio on its own once we give it a region to draw into. 1.262 + 1.263 + return gfx::Matrix::Translation(x, y) * 1.264 + gfx::ToMatrix(GetCanvasTM(aFor, aTransformRoot)); 1.265 +} 1.266 + 1.267 +bool 1.268 +nsSVGImageFrame::TransformContextForPainting(gfxContext* aGfxContext, 1.269 + nsIFrame* aTransformRoot) 1.270 +{ 1.271 + gfx::Matrix imageTransform; 1.272 + if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) { 1.273 + imageTransform = GetVectorImageTransform(FOR_PAINTING, aTransformRoot); 1.274 + } else { 1.275 + int32_t nativeWidth, nativeHeight; 1.276 + if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) || 1.277 + NS_FAILED(mImageContainer->GetHeight(&nativeHeight)) || 1.278 + nativeWidth == 0 || nativeHeight == 0) { 1.279 + return false; 1.280 + } 1.281 + imageTransform = 1.282 + GetRasterImageTransform(nativeWidth, nativeHeight, FOR_PAINTING, 1.283 + aTransformRoot); 1.284 + 1.285 + // NOTE: We need to cancel out the effects of Full-Page-Zoom, or else 1.286 + // it'll get applied an extra time by DrawSingleUnscaledImage. 1.287 + nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); 1.288 + gfxFloat pageZoomFactor = 1.289 + nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPx); 1.290 + imageTransform.Scale(pageZoomFactor, pageZoomFactor); 1.291 + } 1.292 + 1.293 + if (imageTransform.IsSingular()) { 1.294 + return false; 1.295 + } 1.296 + 1.297 + aGfxContext->Multiply(ThebesMatrix(imageTransform)); 1.298 + return true; 1.299 +} 1.300 + 1.301 +//---------------------------------------------------------------------- 1.302 +// nsISVGChildFrame methods: 1.303 +nsresult 1.304 +nsSVGImageFrame::PaintSVG(nsRenderingContext *aContext, 1.305 + const nsIntRect *aDirtyRect, 1.306 + nsIFrame* aTransformRoot) 1.307 +{ 1.308 + nsresult rv = NS_OK; 1.309 + 1.310 + if (!StyleVisibility()->IsVisible()) 1.311 + return NS_OK; 1.312 + 1.313 + float x, y, width, height; 1.314 + SVGImageElement *imgElem = static_cast<SVGImageElement*>(mContent); 1.315 + imgElem->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); 1.316 + NS_ASSERTION(width > 0 && height > 0, 1.317 + "Should only be painting things with valid width/height"); 1.318 + 1.319 + if (!mImageContainer) { 1.320 + nsCOMPtr<imgIRequest> currentRequest; 1.321 + nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent); 1.322 + if (imageLoader) 1.323 + imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, 1.324 + getter_AddRefs(currentRequest)); 1.325 + 1.326 + if (currentRequest) 1.327 + currentRequest->GetImage(getter_AddRefs(mImageContainer)); 1.328 + } 1.329 + 1.330 + if (mImageContainer) { 1.331 + gfxContext* ctx = aContext->ThebesContext(); 1.332 + gfxContextAutoSaveRestore autoRestorer(ctx); 1.333 + 1.334 + if (StyleDisplay()->IsScrollableOverflow()) { 1.335 + gfxRect clipRect = nsSVGUtils::GetClipRectForFrame(this, x, y, 1.336 + width, height); 1.337 + nsSVGUtils::SetClipRect(ctx, GetCanvasTM(FOR_PAINTING, aTransformRoot), 1.338 + clipRect); 1.339 + } 1.340 + 1.341 + if (!TransformContextForPainting(ctx, aTransformRoot)) { 1.342 + return NS_ERROR_FAILURE; 1.343 + } 1.344 + 1.345 + // fill-opacity doesn't affect <image>, so if we're allowed to 1.346 + // optimize group opacity, the opacity used for compositing the 1.347 + // image into the current canvas is just the group opacity. 1.348 + float opacity = 1.0f; 1.349 + if (nsSVGUtils::CanOptimizeOpacity(this)) { 1.350 + opacity = StyleDisplay()->mOpacity; 1.351 + } 1.352 + 1.353 + if (opacity != 1.0f || StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { 1.354 + ctx->PushGroup(gfxContentType::COLOR_ALPHA); 1.355 + } 1.356 + 1.357 + nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel(); 1.358 + nsRect dirtyRect; // only used if aDirtyRect is non-null 1.359 + if (aDirtyRect) { 1.360 + NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() || 1.361 + (mState & NS_FRAME_IS_NONDISPLAY), 1.362 + "Display lists handle dirty rect intersection test"); 1.363 + dirtyRect = aDirtyRect->ToAppUnits(appUnitsPerDevPx); 1.364 + // Adjust dirtyRect to match our local coordinate system. 1.365 + nsRect rootRect = 1.366 + nsSVGUtils::TransformFrameRectToOuterSVG(mRect, 1.367 + GetCanvasTM(FOR_PAINTING), PresContext()); 1.368 + dirtyRect.MoveBy(-rootRect.TopLeft()); 1.369 + } 1.370 + 1.371 + // XXXbholley - I don't think huge images in SVGs are common enough to 1.372 + // warrant worrying about the responsiveness impact of doing synchronous 1.373 + // decodes. The extra code complexity of determinining when we want to 1.374 + // force sync probably just isn't worth it, so always pass FLAG_SYNC_DECODE 1.375 + uint32_t drawFlags = imgIContainer::FLAG_SYNC_DECODE; 1.376 + 1.377 + if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) { 1.378 + // Package up the attributes of this image element which can override the 1.379 + // attributes of mImageContainer's internal SVG document. 1.380 + SVGImageContext context(imgElem->mPreserveAspectRatio.GetAnimValue()); 1.381 + 1.382 + nsRect destRect(0, 0, 1.383 + appUnitsPerDevPx * width, 1.384 + appUnitsPerDevPx * height); 1.385 + 1.386 + // Note: Can't use DrawSingleUnscaledImage for the TYPE_VECTOR case. 1.387 + // That method needs our image to have a fixed native width & height, 1.388 + // and that's not always true for TYPE_VECTOR images. 1.389 + nsLayoutUtils::DrawSingleImage( 1.390 + aContext, 1.391 + mImageContainer, 1.392 + nsLayoutUtils::GetGraphicsFilterForFrame(this), 1.393 + destRect, 1.394 + aDirtyRect ? dirtyRect : destRect, 1.395 + &context, 1.396 + drawFlags); 1.397 + } else { // mImageContainer->GetType() == TYPE_RASTER 1.398 + nsLayoutUtils::DrawSingleUnscaledImage( 1.399 + aContext, 1.400 + mImageContainer, 1.401 + nsLayoutUtils::GetGraphicsFilterForFrame(this), 1.402 + nsPoint(0, 0), 1.403 + aDirtyRect ? &dirtyRect : nullptr, 1.404 + drawFlags); 1.405 + } 1.406 + 1.407 + if (opacity != 1.0f || StyleDisplay()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) { 1.408 + ctx->PopGroupToSource(); 1.409 + ctx->SetOperator(gfxContext::OPERATOR_OVER); 1.410 + ctx->Paint(opacity); 1.411 + } 1.412 + // gfxContextAutoSaveRestore goes out of scope & cleans up our gfxContext 1.413 + } 1.414 + 1.415 + return rv; 1.416 +} 1.417 + 1.418 +nsIFrame* 1.419 +nsSVGImageFrame::GetFrameForPoint(const nsPoint &aPoint) 1.420 +{ 1.421 + // Special case for raster images -- we only want to accept points that fall 1.422 + // in the underlying image's (transformed) native bounds. That region 1.423 + // doesn't necessarily map to our <image> element's [x,y,width,height]. So, 1.424 + // we have to look up the native image size & our image transform in order 1.425 + // to filter out points that fall outside that area. 1.426 + if (StyleDisplay()->IsScrollableOverflow() && mImageContainer) { 1.427 + if (mImageContainer->GetType() == imgIContainer::TYPE_RASTER) { 1.428 + int32_t nativeWidth, nativeHeight; 1.429 + if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) || 1.430 + NS_FAILED(mImageContainer->GetHeight(&nativeHeight)) || 1.431 + nativeWidth == 0 || nativeHeight == 0) { 1.432 + return nullptr; 1.433 + } 1.434 + 1.435 + if (!nsSVGUtils::HitTestRect( 1.436 + GetRasterImageTransform(nativeWidth, nativeHeight, 1.437 + FOR_HIT_TESTING), 1.438 + 0, 0, nativeWidth, nativeHeight, 1.439 + PresContext()->AppUnitsToDevPixels(aPoint.x), 1.440 + PresContext()->AppUnitsToDevPixels(aPoint.y))) { 1.441 + return nullptr; 1.442 + } 1.443 + } 1.444 + // The special case above doesn't apply to vector images, because they 1.445 + // don't limit their drawing to explicit "native bounds" -- they have 1.446 + // an infinite canvas on which to place content. So it's reasonable to 1.447 + // just fall back on our <image> element's own bounds here. 1.448 + } 1.449 + 1.450 + return nsSVGImageFrameBase::GetFrameForPoint(aPoint); 1.451 +} 1.452 + 1.453 +nsIAtom * 1.454 +nsSVGImageFrame::GetType() const 1.455 +{ 1.456 + return nsGkAtoms::svgImageFrame; 1.457 +} 1.458 + 1.459 +//---------------------------------------------------------------------- 1.460 +// nsSVGPathGeometryFrame methods: 1.461 + 1.462 +// Lie about our fill/stroke so that covered region and hit detection work properly 1.463 + 1.464 +void 1.465 +nsSVGImageFrame::ReflowSVG() 1.466 +{ 1.467 + NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this), 1.468 + "This call is probably a wasteful mistake"); 1.469 + 1.470 + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY), 1.471 + "ReflowSVG mechanism not designed for this"); 1.472 + 1.473 + if (!nsSVGUtils::NeedsReflowSVG(this)) { 1.474 + return; 1.475 + } 1.476 + 1.477 + float x, y, width, height; 1.478 + SVGImageElement *element = static_cast<SVGImageElement*>(mContent); 1.479 + element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr); 1.480 + 1.481 + Rect extent(x, y, width, height); 1.482 + 1.483 + if (!extent.IsEmpty()) { 1.484 + mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent, 1.485 + PresContext()->AppUnitsPerCSSPixel()); 1.486 + } else { 1.487 + mRect.SetEmpty(); 1.488 + } 1.489 + 1.490 + if (mState & NS_FRAME_FIRST_REFLOW) { 1.491 + // Make sure we have our filter property (if any) before calling 1.492 + // FinishAndStoreOverflow (subsequent filter changes are handled off 1.493 + // nsChangeHint_UpdateEffects): 1.494 + nsSVGEffects::UpdateEffects(this); 1.495 + 1.496 + if (!mReflowCallbackPosted) { 1.497 + nsIPresShell* shell = PresContext()->PresShell(); 1.498 + mReflowCallbackPosted = true; 1.499 + shell->PostReflowCallback(this); 1.500 + } 1.501 + } 1.502 + 1.503 + nsRect overflow = nsRect(nsPoint(0,0), mRect.Size()); 1.504 + nsOverflowAreas overflowAreas(overflow, overflow); 1.505 + FinishAndStoreOverflow(overflowAreas, mRect.Size()); 1.506 + 1.507 + mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | 1.508 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.509 + 1.510 + // Invalidate, but only if this is not our first reflow (since if it is our 1.511 + // first reflow then we haven't had our first paint yet). 1.512 + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { 1.513 + InvalidateFrame(); 1.514 + } 1.515 +} 1.516 + 1.517 +bool 1.518 +nsSVGImageFrame::ReflowFinished() 1.519 +{ 1.520 + mReflowCallbackPosted = false; 1.521 + 1.522 + nsLayoutUtils::UpdateImageVisibilityForFrame(this); 1.523 + 1.524 + return false; 1.525 +} 1.526 + 1.527 +void 1.528 +nsSVGImageFrame::ReflowCallbackCanceled() 1.529 +{ 1.530 + mReflowCallbackPosted = false; 1.531 +} 1.532 + 1.533 +uint16_t 1.534 +nsSVGImageFrame::GetHitTestFlags() 1.535 +{ 1.536 + uint16_t flags = 0; 1.537 + 1.538 + switch(StyleVisibility()->mPointerEvents) { 1.539 + case NS_STYLE_POINTER_EVENTS_NONE: 1.540 + break; 1.541 + case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED: 1.542 + case NS_STYLE_POINTER_EVENTS_AUTO: 1.543 + if (StyleVisibility()->IsVisible()) { 1.544 + /* XXX: should check pixel transparency */ 1.545 + flags |= SVG_HIT_TEST_FILL; 1.546 + } 1.547 + break; 1.548 + case NS_STYLE_POINTER_EVENTS_VISIBLEFILL: 1.549 + case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE: 1.550 + case NS_STYLE_POINTER_EVENTS_VISIBLE: 1.551 + if (StyleVisibility()->IsVisible()) { 1.552 + flags |= SVG_HIT_TEST_FILL; 1.553 + } 1.554 + break; 1.555 + case NS_STYLE_POINTER_EVENTS_PAINTED: 1.556 + /* XXX: should check pixel transparency */ 1.557 + flags |= SVG_HIT_TEST_FILL; 1.558 + break; 1.559 + case NS_STYLE_POINTER_EVENTS_FILL: 1.560 + case NS_STYLE_POINTER_EVENTS_STROKE: 1.561 + case NS_STYLE_POINTER_EVENTS_ALL: 1.562 + flags |= SVG_HIT_TEST_FILL; 1.563 + break; 1.564 + default: 1.565 + NS_ERROR("not reached"); 1.566 + break; 1.567 + } 1.568 + 1.569 + return flags; 1.570 +} 1.571 + 1.572 +//---------------------------------------------------------------------- 1.573 +// nsSVGImageListener implementation 1.574 + 1.575 +NS_IMPL_ISUPPORTS(nsSVGImageListener, imgINotificationObserver) 1.576 + 1.577 +nsSVGImageListener::nsSVGImageListener(nsSVGImageFrame *aFrame) : mFrame(aFrame) 1.578 +{ 1.579 +} 1.580 + 1.581 +NS_IMETHODIMP 1.582 +nsSVGImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData) 1.583 +{ 1.584 + if (!mFrame) 1.585 + return NS_ERROR_FAILURE; 1.586 + 1.587 + if (aType == imgINotificationObserver::LOAD_COMPLETE) { 1.588 + mFrame->InvalidateFrame(); 1.589 + nsSVGEffects::InvalidateRenderingObservers(mFrame); 1.590 + nsSVGUtils::ScheduleReflowSVG(mFrame); 1.591 + } 1.592 + 1.593 + if (aType == imgINotificationObserver::FRAME_UPDATE) { 1.594 + // No new dimensions, so we don't need to call 1.595 + // nsSVGUtils::InvalidateAndScheduleBoundsUpdate. 1.596 + nsSVGEffects::InvalidateRenderingObservers(mFrame); 1.597 + mFrame->InvalidateFrame(); 1.598 + } 1.599 + 1.600 + if (aType == imgINotificationObserver::SIZE_AVAILABLE) { 1.601 + // Called once the resource's dimensions have been obtained. 1.602 + aRequest->GetImage(getter_AddRefs(mFrame->mImageContainer)); 1.603 + mFrame->InvalidateFrame(); 1.604 + nsSVGEffects::InvalidateRenderingObservers(mFrame); 1.605 + nsSVGUtils::ScheduleReflowSVG(mFrame); 1.606 + } 1.607 + 1.608 + return NS_OK; 1.609 +} 1.610 +