Bug 1301245 - Part 2. Do not resolve a style image if the given url has a fragment. draft
authorcku <cku@mozilla.com>
Wed, 26 Jul 2017 11:21:30 +0800
changeset 615788 5dec40d18494f9b62f12147c032d87b70727c74f
parent 615787 ccfb7f6380d0255c270854d5f1b270547c316181
child 615789 9d0993da476d08f1425d1e7fba2c57031c7049ac
push id70472
push userbmo:cku@mozilla.com
push dateWed, 26 Jul 2017 09:57:39 +0000
bugs1301245
milestone56.0a1
Bug 1301245 - Part 2. Do not resolve a style image if the given url has a fragment. MozReview-Commit-ID: 18LFjlWZBLl
layout/generic/nsFrame.cpp
layout/painting/nsDisplayList.cpp
layout/style/nsStyleStruct.cpp
layout/svg/nsSVGIntegrationUtils.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -843,44 +843,45 @@ AddAndRemoveImageAssociations(nsFrame* a
   // We want to do this conservatively because some frames paint their
   // backgrounds from some other frame's style data, and we don't want
   // to clear those notifiers unless we have to.  (They'll be reset
   // when we paint, although we could miss a notification in that
   // interval.)
 
   if (aOldLayers) {
     NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aOldLayers)) {
+      const nsStyleImage& oldImage = aOldLayers->mLayers[i].mImage;
+      if (oldImage.GetType() != eStyleImageType_Image ||
+          !oldImage.IsResolved()) {
+        continue;
+      }
+
       // If there is an image in oldBG that's not in newBG, drop it.
       if (i >= aNewLayers->mImageCount ||
-          !aOldLayers->mLayers[i].mImage.ImageDataEquals(
-            aNewLayers->mLayers[i].mImage)) {
-        const nsStyleImage& oldImage = aOldLayers->mLayers[i].mImage;
-        if (oldImage.GetType() != eStyleImageType_Image) {
-          continue;
-        }
+          !oldImage.ImageDataEquals(aNewLayers->mLayers[i].mImage)) {
 
         if (aFrame->HasImageRequest()) {
           if (imgRequestProxy* req = oldImage.GetImageData()) {
             imageLoader->DisassociateRequestFromFrame(req, aFrame);
           }
         }
       }
     }
   }
 
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aNewLayers)) {
+    const nsStyleImage& newImage = aNewLayers->mLayers[i].mImage;
+    if (newImage.GetType() != eStyleImageType_Image ||
+        !newImage.IsResolved()) {
+      continue;
+    }
+
     // If there is an image in newBG that's not in oldBG, add it.
     if (!aOldLayers || i >= aOldLayers->mImageCount ||
-        !aNewLayers->mLayers[i].mImage.ImageDataEquals(
-          aOldLayers->mLayers[i].mImage)) {
-      const nsStyleImage& newImage = aNewLayers->mLayers[i].mImage;
-      if (newImage.GetType() != eStyleImageType_Image) {
-        continue;
-      }
-
+        !newImage.ImageDataEquals(aOldLayers->mLayers[i].mImage)) {
       if (imgRequestProxy* req = newImage.GetImageData()) {
         imageLoader->AssociateRequestToFrame(req, aFrame);
       }
     }
   }
 }
 
 // Subclass hook for style post processing
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8550,16 +8550,19 @@ nsDisplayMask::nsDisplayMask(nsDisplayLi
 {
   MOZ_COUNT_CTOR(nsDisplayMask);
 
   nsPresContext* presContext = mFrame->PresContext();
   uint32_t flags = aBuilder->GetBackgroundPaintFlags() |
                    nsCSSRendering::PAINTBG_MASK_IMAGE;
   const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
+    if (!svgReset->mMask.mLayers[i].mImage.IsResolved()) {
+      continue;
+    }
     bool isTransformedFixed;
     nsBackgroundLayerState state =
       nsCSSRendering::PrepareImageLayer(presContext, aFrame, flags,
                                         mFrame->GetRectRelativeToSelf(),
                                         mFrame->GetRectRelativeToSelf(),
                                         svgReset->mMask.mLayers[i],
                                         &isTransformedFixed);
     mDestRects.AppendElement(state.mDestArea);
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1200,17 +1200,28 @@ nsStyleSVGReset::Destroy(nsPresContext* 
 }
 
 void
 nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
 
-  mMask.ResolveImages(aPresContext);
+  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mMask) {
+    nsStyleImage& image = mMask.mLayers[i].mImage;
+    if (image.GetType() == eStyleImageType_Image) {
+      // If the url of mask resource contains a reference('#'), it should be a
+      // <mask-source>, mostly. For a <mask-source>, there is no need to
+      // resolve this style image, since we do not depend on it to get the
+      // SVG mask resource.
+      if (!image.GetURLValue()->HasRef()) {
+        image.ResolveImage(aPresContext);
+      }
+    }
+  }
 }
 
 nsChangeHint
 nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aNewData) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (!mClipPath.DefinitelyEquals(aNewData.mClipPath)) {
@@ -2455,16 +2466,19 @@ nsStyleImage::IsComplete() const
   switch (mType) {
     case eStyleImageType_Null:
       return false;
     case eStyleImageType_Gradient:
     case eStyleImageType_Element:
     case eStyleImageType_URL:
       return true;
     case eStyleImageType_Image: {
+      if (!IsResolved()) {
+        return false;
+      }
       imgRequestProxy* req = GetImageData();
       if (!req) {
         return false;
       }
       uint32_t status = imgIRequest::STATUS_ERROR;
       return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
              (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
              (status & imgIRequest::STATUS_FRAME_COMPLETE);
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -478,33 +478,35 @@ PaintMaskSurface(const PaintFramesParams
       if (svgMask) {
         gfxContextMatrixAutoSaveRestore matRestore(maskContext);
 
         maskContext->Multiply(ThebesMatrix(svgMaskMatrix));
         aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
                              Point(0, 0),
                              DrawOptions(1.0, compositionOp));
       }
-    } else {
+    } else if (svgReset->mMask.mLayers[i].mImage.IsResolved()) {
       gfxContextMatrixAutoSaveRestore matRestore(maskContext);
 
       maskContext->Multiply(gfxMatrix::Translation(-devPixelOffsetToUserSpace));
       nsCSSRendering::PaintBGParams  params =
         nsCSSRendering::PaintBGParams::ForSingleLayer(*presContext,
                                                       aParams.dirtyRect,
                                                       aParams.borderArea,
                                                       aParams.frame,
                                                       aParams.builder->GetBackgroundPaintFlags() |
                                                       nsCSSRendering::PAINTBG_MASK_IMAGE,
                                                       i, compositionOp,
                                                       aOpacity);
 
       aParams.imgParams.result &=
         nsCSSRendering::PaintStyleImageLayerWithSC(params, *maskContext, aSC,
                                               *aParams.frame->StyleBorder());
+    } else {
+      aParams.imgParams.result &= DrawResult::NOT_READY;
     }
   }
 }
 
 struct MaskPaintResult {
   RefPtr<SourceSurface> maskSurface;
   Matrix maskTransform;
   bool transparentBlackMask;