Bug 1534240 - Boost loading priority of CSS images similarly to how we do for HTML images. r=tnikkel
authorCameron McCormack <cam@mcc.id.au>
Thu, 28 Mar 2019 02:54:16 +0000
changeset 525326 7f0d03ec917cfc831b7c4104729801fa33b1d167
parent 525325 1aa2a852f2fd0ece3a15285518b579afe424b702
child 525327 a99248b3ec384f417cd3c22eb82e68b3cad0a4e4
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1534240
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1534240 - Boost loading priority of CSS images similarly to how we do for HTML images. r=tnikkel Differential Revision: https://phabricator.services.mozilla.com/D24814
image/imgIRequest.idl
image/imgRequest.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsFloatManager.cpp
layout/painting/nsImageRenderer.cpp
layout/style/nsStyleStruct.cpp
--- a/image/imgIRequest.idl
+++ b/image/imgIRequest.idl
@@ -211,25 +211,30 @@ interface imgIRequest : nsIRequest
    *
    * @see Image::DecrementAnimationConsumers for documentation of the
    * underlying call.
    */
   void decrementAnimationConsumers();
 
   /**
    * Request loading priority boost to requested category, each category
-   * of request increases priority only one time..
+   * of request increases priority only one time.
    *
    * CATEGORY_FRAME_INIT: increase priority when the imgRequest is associated
    * with an nsImageFrame.
    *
+   * CATEGORY_FRAME_STYLE: increase priority when the imgRequest is for a CSS
+   * background-image, list-style-image, etc. on a ComputedStyle, and a frame
+   * has been assigned this ComputedStyle.
+   *
    * CATEGORY_SIZE_QUERY: increase priority when size decoding is necessary to
-   * determine the layout size of the associated nsImageFrame.
+   * determine the layout size of an associated nsImageFrame.
    *
    * CATEGORY_DISPLAY: increase priority when the image is about to be displayed
    * in the viewport.
    */
-  const uint32_t CATEGORY_FRAME_INIT = 1 << 0;
-  const uint32_t CATEGORY_SIZE_QUERY = 1 << 1;
-  const uint32_t CATEGORY_DISPLAY    = 1 << 2;
+  const uint32_t CATEGORY_FRAME_INIT  = 1 << 0;
+  const uint32_t CATEGORY_FRAME_STYLE = 1 << 1;
+  const uint32_t CATEGORY_SIZE_QUERY  = 1 << 2;
+  const uint32_t CATEGORY_DISPLAY     = 1 << 3;
   void boostPriority(in uint32_t aCategory);
 };
 
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -484,16 +484,20 @@ void imgRequest::BoostPriority(uint32_t 
            newRequestedCategory));
 
   int32_t delta = 0;
 
   if (newRequestedCategory & imgIRequest::CATEGORY_FRAME_INIT) {
     --delta;
   }
 
+  if (newRequestedCategory & imgIRequest::CATEGORY_FRAME_STYLE) {
+    --delta;
+  }
+
   if (newRequestedCategory & imgIRequest::CATEGORY_SIZE_QUERY) {
     --delta;
   }
 
   if (newRequestedCategory & imgIRequest::CATEGORY_DISPLAY) {
     delta += nsISupportsPriority::PRIORITY_HIGH;
   }
 
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -6382,16 +6382,20 @@ void nsBlockFrame::BuildDisplayList(nsDi
   }
   PRTime start = 0;  // Initialize these variables to silence the compiler.
   if (gLamePaintMetrics) {
     start = PR_Now();
     drawnLines = 0;
   }
 #endif
 
+  // TODO(heycam): Should we boost the load priority of any shape-outside
+  // images using CATEGORY_DISPLAY, now that this block is being displayed?
+  // We don't have a float manager here.
+
   DisplayBorderBackgroundOutline(aBuilder, aLists);
 
   if (GetPrevInFlow()) {
     DisplayOverflowContainers(aBuilder, aLists);
     for (nsIFrame* f : mFloats) {
       if (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)
         BuildDisplayListForChild(aBuilder, f, aLists);
     }
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -137,16 +137,20 @@ void nsBulletFrame::DidSetComputedStyle(
       // Deregister the old request. We wait until after Clone is done in case
       // the old request and the new request are the same underlying image
       // accessed via different URLs.
       DeregisterAndCancelImageRequest();
 
       // Register the new request.
       mImageRequest = std::move(newRequestClone);
       RegisterImageRequest(/* aKnownToBeAnimated = */ false);
+
+      // Image bullets can affect the layout of the page, so boost the image
+      // load priority.
+      mImageRequest->BoostPriority(imgIRequest::CATEGORY_SIZE_QUERY);
     }
   } else {
     // No image request on the new ComputedStyle.
     DeregisterAndCancelImageRequest();
   }
 
 #ifdef ACCESSIBILITY
   // Update the list bullet accessible. If old style list isn't available then
@@ -660,26 +664,31 @@ Maybe<BulletRenderer> nsBulletFrame::Cre
     gfxContext& aRenderingContext, nsPoint aPt) {
   const nsStyleList* myList = StyleList();
   CounterStyle* listStyleType = ResolveCounterStyle();
   nsMargin padding = mPadding.GetPhysicalMargin(GetWritingMode());
 
   if (myList->GetListStyleImage() && mImageRequest) {
     uint32_t status;
     mImageRequest->GetImageStatus(&status);
-    if (status & imgIRequest::STATUS_LOAD_COMPLETE &&
-        !(status & imgIRequest::STATUS_ERROR)) {
-      nsCOMPtr<imgIContainer> imageCon;
-      mImageRequest->GetImage(getter_AddRefs(imageCon));
-      if (imageCon) {
-        nsRect dest(padding.left, padding.top,
-                    mRect.width - (padding.left + padding.right),
-                    mRect.height - (padding.top + padding.bottom));
-        BulletRenderer br(imageCon, dest + aPt);
-        return Some(br);
+    if (!(status & imgIRequest::STATUS_ERROR)) {
+      if (status & imgIRequest::STATUS_LOAD_COMPLETE) {
+        nsCOMPtr<imgIContainer> imageCon;
+        mImageRequest->GetImage(getter_AddRefs(imageCon));
+        if (imageCon) {
+          nsRect dest(padding.left, padding.top,
+                      mRect.width - (padding.left + padding.right),
+                      mRect.height - (padding.top + padding.bottom));
+          BulletRenderer br(imageCon, dest + aPt);
+          return Some(br);
+        }
+      } else {
+        // Boost the load priority further now that we know we want to display
+        // the bullet image.
+        mImageRequest->BoostPriority(imgIRequest::CATEGORY_DISPLAY);
       }
     }
   }
 
   nscolor color = nsLayoutUtils::GetColor(this, &nsStyleColor::mColor);
 
   DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
   int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -2679,17 +2679,23 @@ nsFloatManager::ShapeInfo::CreateImageSh
   MOZ_ASSERT(
       &aShapeImage == &aFrame->StyleDisplay()->mShapeOutside.ShapeImage(),
       "aFrame should be the frame that we got aShapeImage from");
 
   nsImageRenderer imageRenderer(aFrame, &aShapeImage,
                                 nsImageRenderer::FLAG_SYNC_DECODE_IMAGES);
 
   if (!imageRenderer.PrepareImage()) {
-    // The image is not ready yet.
+    // The image is not ready yet.  Boost its loading priority since it will
+    // affect layout.
+    if (aShapeImage.GetType() == eStyleImageType_Image) {
+      if (imgRequestProxy* req = aShapeImage.GetImageData()) {
+        req->BoostPriority(imgIRequest::CATEGORY_SIZE_QUERY);
+      }
+    }
     return nullptr;
   }
 
   nsRect contentRect = aFrame->GetContentRect();
 
   // Create a draw target and draw shape image on it.
   nsDeviceContext* dc = aFrame->PresContext()->DeviceContext();
   int32_t appUnitsPerDevPixel = dc->AppUnitsPerDevPixel();
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -96,40 +96,51 @@ static bool ShouldTreatAsCompleteDueToSy
     // available, or else sync decoding won't be able to decode the image.
     return false;
   }
 
   return true;
 }
 
 bool nsImageRenderer::PrepareImage() {
-  if (mImage->IsEmpty()) {
+  if (mImage->IsEmpty() ||
+      (mType == eStyleImageType_Image && !mImage->GetImageData())) {
+    // mImage->GetImageData() could be null here if the nsStyleImage refused
+    // to load a same-document URL.
     mPrepareResult = ImgDrawResult::BAD_IMAGE;
     return false;
   }
 
   if (!mImage->IsComplete()) {
     // Make sure the image is actually decoding.
     bool frameComplete = mImage->StartDecoding();
 
+    // Boost the loading priority since we know we want to draw the image.
+    if ((mFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) &&
+        mType == eStyleImageType_Image) {
+      MOZ_ASSERT(mImage->GetImageData(),
+                 "must have image data, since we checked above");
+      mImage->GetImageData()->BoostPriority(imgIRequest::CATEGORY_DISPLAY);
+    }
+
     // Check again to see if we finished.
     // We cannot prepare the image for rendering if it is not fully loaded.
     // Special case: If we requested a sync decode and the image has loaded,
     // push on through because the Draw() will do a sync decode then.
     if (!(frameComplete || mImage->IsComplete()) &&
         !ShouldTreatAsCompleteDueToSyncDecode(mImage, mFlags)) {
       mPrepareResult = ImgDrawResult::NOT_READY;
       return false;
     }
   }
 
   switch (mType) {
     case eStyleImageType_Image: {
       MOZ_ASSERT(mImage->GetImageData(),
-                 "must have image data, since we checked IsEmpty above");
+                 "must have image data, since we checked above");
       nsCOMPtr<imgIContainer> srcImage;
       DebugOnly<nsresult> rv =
           mImage->GetImageData()->GetImage(getter_AddRefs(srcImage));
       MOZ_ASSERT(NS_SUCCEEDED(rv) && srcImage,
                  "If GetImage() is failing, mImage->IsComplete() "
                  "should have returned false");
 
       if (!mImage->GetCropRect()) {
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1893,16 +1893,20 @@ bool nsStyleImageRequest::Resolve(Docume
     }
   }
 
   if (!mRequestProxy) {
     // The URL resolution or image load failed.
     return false;
   }
 
+  // Boost priority now that we know the image is present in the ComputedStyle
+  // of some frame.
+  mRequestProxy->BoostPriority(imgIRequest::CATEGORY_FRAME_STYLE);
+
   if (mModeFlags & Mode::Track) {
     mImageTracker = aDocument.ImageTracker();
   }
 
   MaybeTrackAndLock();
   return true;
 }