Bug 1359844 - Ensure full decode be triggered after style-image was downloaded, draft
authorcku <cku@mozilla.com>
Mon, 17 Apr 2017 15:10:52 +0800
changeset 568897 46e4243f9bd1154e0d88d81acb5ecdab66b4ffce
parent 568807 a477e80f03b61be9961bc61770a2b55cce139b91
child 626060 766744b151f63b2a57c96ee04abf9d35f3ae3b45
push id56016
push userbmo:cku@mozilla.com
push dateWed, 26 Apr 2017 18:16:33 +0000
bugs1359844
milestone55.0a1
Bug 1359844 - Ensure full decode be triggered after style-image was downloaded, In nsCSSRendering::PaintBorderWithStyleBorder: DrawResult nsCSSRendering::PaintBorderWithStyleBorder() { if (aStyleBorder.IsBorderImageLoaded()) { (1) } (2) } At (1), we create a nsCSSBorderImageRenderer object. While creating it, we call imgRenderer.PrepareImage() to ensure a full image decode at [1]. PrepareImage is used in both bg-image/mask-image and border-image. The difference is, in bg-image/mask-image painting path, we unconditionally use PrepareImage(in nsCSSRendering::PrepareImageLayer), whereas in border-image painting path we use it only after border-image was downloaded. This difference does cause a problem. After border image was downloaded, the decoder will not do full decoding since we did not ask for it, so there will be no repaint notification and no chance to paint border-image again. In this patch, I try to align the behavior between bg-image/mask-image and border-image: always call nsImageRenderer::PrepareImage. This is a generic fix for both stylo-enable and stylo-disable build. We do not find this problem in reftest is because we use SYNC_DECODE in reftest harness, which hides this race condition. When daily using firefox, if nsCSSRendering::PaintBorderWithStyleBorder is called after border-image was loaded, your program run into (1), border-image will be drawn correctly; In the case that nsCSSRendering::PaintBorderWithStyleBorder is called before border-image is loaded, your program run into (2), and you can only see border-color. [1] https://hg.mozilla.org/mozilla-central/file/a6f35285bd1e/layout/painting/nsCSSRenderingBorders.cpp#l3598 MozReview-Commit-ID: 6pidHJdPG8I
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRenderingBorders.cpp
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -815,34 +815,38 @@ nsCSSRendering::PaintBorderWithStyleBord
     nsITheme *theme = aPresContext->GetTheme();
     if (theme &&
         theme->ThemeSupportsWidget(aPresContext, aForFrame,
                                    displayData->UsedAppearance())) {
       return DrawResult::SUCCESS; // Let the theme handle it.
     }
   }
 
-  if (aStyleBorder.IsBorderImageLoaded()) {
-    DrawResult result;
+  if (!aStyleBorder.mBorderImageSource.IsEmpty()) {
+    DrawResult result = DrawResult::SUCCESS;
 
     uint32_t irFlags = 0;
     if (aFlags & PaintBorderFlags::SYNC_DECODE_IMAGES) {
       irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
     }
 
+    // Creating the border image renderer will request a decode, and we rely on
+    // that happening.
     Maybe<nsCSSBorderImageRenderer> renderer =
       nsCSSBorderImageRenderer::CreateBorderImageRenderer(aPresContext, aForFrame, aBorderArea,
                                                           aStyleBorder, aDirtyRect, aSkipSides,
                                                           irFlags, &result);
-    if (!renderer) {
-      return result;
+    if (aStyleBorder.IsBorderImageLoaded()) {
+      if (!renderer) {
+        return result;
+      }
+
+      return renderer->DrawBorderImage(aPresContext, aRenderingContext,
+                                       aForFrame, aDirtyRect);
     }
-
-    return renderer->DrawBorderImage(aPresContext, aRenderingContext,
-                                     aForFrame, aDirtyRect);
   }
 
   DrawResult result = DrawResult::SUCCESS;
 
   // If we had a border-image, but it wasn't loaded, then we should return
   // DrawResult::NOT_READY; we'll want to try again if we do a paint with sync
   // decoding enabled.
   if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3580,18 +3580,16 @@ nsCSSBorderImageRenderer::CreateBorderIm
                                                     nsIFrame* aForFrame,
                                                     const nsRect& aBorderArea,
                                                     const nsStyleBorder& aStyleBorder,
                                                     const nsRect& aDirtyRect,
                                                     Sides aSkipSides,
                                                     uint32_t aFlags,
                                                     DrawResult* aDrawResult)
 {
-  NS_PRECONDITION(aStyleBorder.IsBorderImageLoaded(),
-                  "drawing border image that isn't successfully loaded");
   MOZ_ASSERT(aDrawResult);
 
   if (aDirtyRect.IsEmpty()) {
     *aDrawResult = DrawResult::SUCCESS;
     return Nothing();
   }
 
   nsImageRenderer imgRenderer(aForFrame, &aStyleBorder.mBorderImageSource, aFlags);