Bug 1301245 - Part 4. Delay image mask download. draft
authorcku <cku@mozilla.com>
Thu, 20 Jul 2017 00:59:59 +0800
changeset 612863 c8bcc59c99b0dfd87530a2e45bbe17860c9b4726
parent 612862 1e36844c06dbe6ee659ba7d442f5c531164dbe52
child 612864 08410a5da2b3e90c96de36de5a5ea2f01ae85f49
push id69621
push userbmo:cku@mozilla.com
push dateFri, 21 Jul 2017 04:42:07 +0000
bugs1301245
milestone56.0a1
Bug 1301245 - Part 4. Delay image mask download. Kick off image mask download after we failed to get the specific SVG mask resource. MozReview-Commit-ID: DM0xVjAFrC9
layout/generic/nsFrame.cpp
layout/painting/nsDisplayList.cpp
layout/style/nsStyleStruct.cpp
layout/svg/nsSVGEffects.cpp
layout/svg/nsSVGEffects.h
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -867,17 +867,18 @@ AddAndRemoveImageAssociations(nsFrame* a
   }
 
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aNewLayers)) {
     // 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) {
+      if (newImage.GetType() != eStyleImageType_Image ||
+          !newImage.IsResolved()) {
         continue;
       }
 
       if (imgRequestProxy* req = newImage.GetImageData()) {
         imageLoader->AssociateRequestToFrame(req, aFrame);
       }
     }
   }
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8434,16 +8434,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
@@ -2455,16 +2455,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/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -14,16 +14,17 @@
 #include "nsSVGClipPathFrame.h"
 #include "nsSVGPaintServerFrame.h"
 #include "nsSVGFilterFrame.h"
 #include "nsSVGMaskFrame.h"
 #include "nsIReflowCallback.h"
 #include "nsCycleCollectionParticipant.h"
 #include "SVGGeometryElement.h"
 #include "SVGUseElement.h"
+#include "ImageLoader.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 void
 nsSVGRenderingObserver::StartListening()
 {
   Element* target = GetTarget();
@@ -387,16 +388,17 @@ nsSVGMarkerProperty::DoUpdate()
   }
   frame->PresContext()->RestyleManager()->PostRestyleEvent(
     frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
 }
 
 NS_IMPL_ISUPPORTS(nsSVGMaskProperty, nsISupports)
 
 nsSVGMaskProperty::nsSVGMaskProperty(nsIFrame* aFrame)
+ : mFrame(aFrame)
 {
   const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
 
   for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
     nsCOMPtr<nsIURI> maskUri = nsSVGEffects::GetMaskURI(aFrame, i);
     bool hasRef = false;
     if (maskUri) {
       maskUri->GetHasRef(&hasRef);
@@ -408,16 +410,37 @@ nsSVGMaskProperty::nsSVGMaskProperty(nsI
     } else {
       nsSVGPaintingProperty* prop = new nsSVGPaintingProperty(maskUri, aFrame,
                                                               false);
       mProperties.AppendElement(prop);
     }
   }
 }
 
+void
+nsSVGMaskProperty::ResolveImage(uint32_t aIndex)
+{
+  const nsStyleSVGReset *svgReset = mFrame->StyleSVGReset();
+  MOZ_ASSERT(aIndex <= svgReset->mMask.mImageCount);
+
+  nsStyleImage& image =
+    const_cast<nsStyleImage&>(svgReset->mMask.mLayers[aIndex].mImage);
+
+  if (!image.IsResolved()) {
+    MOZ_ASSERT(image.GetType() == nsStyleImageType::eStyleImageType_Image);
+    image.ResolveImage(mFrame->PresContext());
+
+    mozilla::css::ImageLoader* imageLoader =
+      mFrame->PresContext()->Document()->StyleImageLoader();
+    if (imgRequestProxy* req = image.GetImageData()) {
+        imageLoader->AssociateRequestToFrame(req, mFrame);
+    }
+  }
+}
+
 bool
 nsSVGTextPathProperty::TargetIsValid()
 {
   Element* target = GetTarget();
   return target && target->IsSVGElement(nsGkAtoms::path);
 }
 
 void
@@ -672,22 +695,30 @@ nsSVGEffects::EffectProperties::GetMaskS
       bool ok = true;
       maskFrame = static_cast<nsSVGMaskFrame*>(
         props[i]->GetReferencedFrame(LayoutFrameType::SVGMask, &ok));
       MOZ_ASSERT(!maskFrame || ok);
       MOZ_ASSERT_IF(!ok, !maskFrame);
 
       if (!ok) {
         type = MaskSourceType::ImageMask;
+        // We can not find the specific SVG mask resoruce after the external
+        // resoruce was downloaded and parsed.
+        // It's right time to kick off style image download.
+        mMask->ResolveImage(i);
       } else {
         type = maskFrame ? MaskSourceType::SVGMask
                          : MaskSourceType::Uncertain;
       }
     } else {
       type = MaskSourceType::ImageMask;
+      // props[i] is nullptr, which means we already know the given mask URL
+      // can not be an SVG mask. (See the comment in
+      // nsSVGMaskProperty::nsSVGMaskProperty)
+      mMask->ResolveImage(i);
     }
 
     MOZ_ASSERT_IF(type == MaskSourceType::SVGMask, maskFrame);
     MOZ_ASSERT_IF(type == MaskSourceType::ImageMask ||
                   type == MaskSourceType::Uncertain, !maskFrame);
     result.AppendElement(MakePair(type, maskFrame));
   }
 
--- a/layout/svg/nsSVGEffects.h
+++ b/layout/svg/nsSVGEffects.h
@@ -350,19 +350,22 @@ public:
   // nsISupports
   NS_DECL_ISUPPORTS
 
   const nsTArray<RefPtr<nsSVGPaintingProperty>>& GetProps() const
   {
     return mProperties;
   }
 
+  void ResolveImage(uint32_t aIndex);
+
 private:
   virtual ~nsSVGMaskProperty() {}
   nsTArray<RefPtr<nsSVGPaintingProperty>> mProperties;
+  nsIFrame* mFrame;
 };
 
 /**
  * A manager for one-shot nsSVGRenderingObserver tracking.
  * nsSVGRenderingObservers can be added or removed. They are not strongly
  * referenced so an observer must be removed before it dies.
  * When InvalidateAll is called, all outstanding references get
  * InvalidateViaReferencedElement()