Bug 1471583. Add a new ImgDrawResult variant to distinguish INCOMPLETE and 'fully drew an image which wasn't really complete'. r=tnikkel
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 29 Aug 2018 00:53:08 -0500
changeset 488867 851b26405a346d8aff55d96bc26ed9bb12995701
parent 488866 5955f883a957e165be245385c640fa3a64fabd8d
child 488868 972b64c9061501955b056adcb71e96b6f4b83abd
push id9734
push usershindli@mozilla.com
push dateThu, 30 Aug 2018 12:18:07 +0000
treeherdermozilla-beta@71c71ab3afae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1471583
milestone63.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 1471583. Add a new ImgDrawResult variant to distinguish INCOMPLETE and 'fully drew an image which wasn't really complete'. r=tnikkel
image/ImgDrawResult.h
layout/painting/nsDisplayList.cpp
layout/painting/nsImageRenderer.cpp
layout/svg/nsSVGIntegrationUtils.cpp
--- a/image/ImgDrawResult.h
+++ b/image/ImgDrawResult.h
@@ -18,16 +18,22 @@ namespace image {
  *
  * Most users of ImgDrawResult will only be interested in whether the value is
  * SUCCESS or not. The other values are primarily useful for debugging and error
  * handling.
  *
  * SUCCESS: We successfully drew a completely decoded frame of the requested
  * size. Drawing again with FLAG_SYNC_DECODE would not change the result.
  *
+ * SUCCESS_NOT_COMPLETE: The image was drawn successfully and completely, but
+ * it hasn't notified about the sync-decode yet. This can only happen when
+ * layout pokes at the internal image state beforehand via
+ * nsStyleImage::StartDecoding. This should probably go away eventually,
+ * somehow, see bug 1471583.
+ *
  * INCOMPLETE: We successfully drew a frame that was partially decoded. (Note
  * that successfully drawing a partially decoded frame may not actually draw any
  * pixels!) Drawing again with FLAG_SYNC_DECODE would improve the result.
  *
  * WRONG_SIZE: We successfully drew a wrongly-sized frame that had to be scaled.
  * This is only returned if drawing again with FLAG_SYNC_DECODE would improve
  * the result; if the size requested was larger than the intrinsic size of the
  * image, for example, we would generally have to scale whether FLAG_SYNC_DECODE
@@ -44,16 +50,17 @@ namespace image {
  * BAD_IMAGE: We failed to draw because the image has an error. This is a
  * permanent condition.
  *
  * BAD_ARGS: We failed to draw because bad arguments were passed to draw().
  */
 enum class MOZ_MUST_USE_TYPE ImgDrawResult : uint8_t
 {
   SUCCESS,
+  SUCCESS_NOT_COMPLETE,
   INCOMPLETE,
   WRONG_SIZE,
   NOT_READY,
   TEMPORARY_ERROR,
   BAD_IMAGE,
   BAD_ARGS
 };
 
@@ -66,17 +73,21 @@ enum class MOZ_MUST_USE_TYPE ImgDrawResu
  * are recoverable and we want to know if any recoverable failures occurred.
  */
 inline ImgDrawResult
 operator&(const ImgDrawResult aLeft, const ImgDrawResult aRight)
 {
   if (MOZ_LIKELY(aLeft == ImgDrawResult::SUCCESS)) {
     return aRight;
   }
-  if (aLeft == ImgDrawResult::BAD_IMAGE && aRight != ImgDrawResult::SUCCESS) {
+
+  if ((aLeft == ImgDrawResult::BAD_IMAGE ||
+       aLeft == ImgDrawResult::SUCCESS_NOT_COMPLETE) &&
+      aRight != ImgDrawResult::SUCCESS &&
+      aRight != ImgDrawResult::SUCCESS_NOT_COMPLETE) {
     return aRight;
   }
   return aLeft;
 }
 
 inline ImgDrawResult&
 operator&=(ImgDrawResult& aLeft, const ImgDrawResult aRight)
 {
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -9264,34 +9264,35 @@ nsDisplayMask::BuildLayer(nsDisplayListB
 
 bool
 nsDisplayMask::PaintMask(nsDisplayListBuilder* aBuilder,
                          gfxContext* aMaskContext,
                          bool* aMaskPainted)
 {
   MOZ_ASSERT(aMaskContext->GetDrawTarget()->GetFormat() == SurfaceFormat::A8);
 
-  imgDrawingParams imgParmas(aBuilder->ShouldSyncDecodeImages()
+  imgDrawingParams imgParams(aBuilder->ShouldSyncDecodeImages()
                              ? imgIContainer::FLAG_SYNC_DECODE
                              : imgIContainer::FLAG_SYNC_DECODE_IF_FAST);
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   nsSVGIntegrationUtils::PaintFramesParams params(*aMaskContext,
                                                   mFrame,  GetBuildingRect(),
                                                   borderArea, aBuilder,
                                                   nullptr,
-                                                  mHandleOpacity, imgParmas);
+                                                  mHandleOpacity, imgParams);
   ComputeMaskGeometry(params);
   bool painted = nsSVGIntegrationUtils::PaintMask(params);
   if (aMaskPainted) {
     *aMaskPainted = painted;
   }
 
-  nsDisplayMaskGeometry::UpdateDrawResult(this, imgParmas.result);
-
-  return imgParmas.result == mozilla::image::ImgDrawResult::SUCCESS;
+  nsDisplayMaskGeometry::UpdateDrawResult(this, imgParams.result);
+
+  return imgParams.result == ImgDrawResult::SUCCESS ||
+    imgParams.result == ImgDrawResult::SUCCESS_NOT_COMPLETE;
 }
 
 LayerState
 nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder,
                              LayerManager* aManager,
                              const ContainerLayerParameters& aParameters)
 {
   if (CanPaintOnMaskLayer(aManager)) {
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -554,17 +554,17 @@ nsImageRenderer::Draw(nsPresContext*    
                       DrawSurfaceOptions(SamplingFilter::POINT),
                       DrawOptions(1.0f, aRenderingContext.CurrentOp()));
     }
 
     dt->SetTransform(oldTransform);
   }
 
   if (!mImage->IsComplete()) {
-    result &= ImgDrawResult::INCOMPLETE;
+    result &= ImgDrawResult::SUCCESS_NOT_COMPLETE;
   }
 
   return result;
 }
 
 ImgDrawResult
 nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext* aPresContext,
                                             mozilla::wr::DisplayListBuilder& aBuilder,
@@ -656,17 +656,19 @@ nsImageRenderer::BuildWebRenderDisplayIt
                          wr::ToLayoutSize(destRect.Size()), wr::ToLayoutSize(gapSize),
                          wr::ToImageRendering(samplingFilter), key.value());
       break;
     }
     default:
       break;
   }
 
-  return mImage->IsComplete() ? ImgDrawResult::SUCCESS : ImgDrawResult::INCOMPLETE;
+  return mImage->IsComplete()
+    ? ImgDrawResult::SUCCESS
+    : ImgDrawResult::SUCCESS_NOT_COMPLETE;
 }
 
 already_AddRefed<gfxDrawable>
 nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
                                     gfxContext&  aContext)
 {
   NS_ASSERTION(mType == eStyleImageType_Element,
                "DrawableForElement only makes sense if backed by an element");
@@ -942,17 +944,17 @@ nsImageRenderer::DrawBorderImageComponen
                                        aPresContext,
                                        subImage,
                                        samplingFilter,
                                        aFill, aDirtyRect,
                                        /* no SVGImageContext */ Nothing(),
                                        drawFlags);
 
       if (!mImage->IsComplete()) {
-        result &= ImgDrawResult::INCOMPLETE;
+        result &= ImgDrawResult::SUCCESS_NOT_COMPLETE;
       }
 
       return result;
     }
 
     nsSize repeatSize;
     nsRect fillRect(aFill);
     nsRect tile = ComputeTile(fillRect, aHFill, aVFill, aUnitSize, repeatSize);
@@ -963,17 +965,17 @@ nsImageRenderer::DrawBorderImageComponen
                                          mForFrame, aPresContext,
                                          subImage, imageSize, samplingFilter,
                                          tile, fillRect, repeatSize,
                                          tile.TopLeft(), aDirtyRect,
                                          drawFlags,
                                          ExtendMode::CLAMP, 1.0);
 
       if (!mImage->IsComplete()) {
-        result &= ImgDrawResult::INCOMPLETE;
+        result &= ImgDrawResult::SUCCESS_NOT_COMPLETE;
       }
 
       return result;
   }
 
   nsSize repeatSize(aFill.Size());
   nsRect fillRect(aFill);
   nsRect destTile = RequiresScaling(fillRect, aHFill, aVFill, aUnitSize)
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -574,17 +574,18 @@ CreateAndPaintMaskSurface(const PaintFra
   Matrix maskSurfaceMatrix =
     ctx.CurrentMatrix() * Matrix::Translation(-aParams.maskRect.TopLeft());
 
   PaintMaskSurface(aParams, maskDT,
                    paintResult.opacityApplied ? aOpacity : 1.0,
                    aSC, aMaskFrames, maskSurfaceMatrix,
                    aOffsetToUserSpace);
 
-  if (aParams.imgParams.result != ImgDrawResult::SUCCESS) {
+  if (aParams.imgParams.result != ImgDrawResult::SUCCESS &&
+      aParams.imgParams.result != ImgDrawResult::SUCCESS_NOT_COMPLETE) {
     // Now we know the status of mask resource since we used it while painting.
     // According to the return value of PaintMaskSurface, we know whether mask
     // resource is resolvable or not.
     //
     // For a HTML doc:
     //   According to css-masking spec, always create a mask surface when
     //   we have any item in maskFrame even if all of those items are
     //   non-resolvable <mask-sources> or <images>.