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 482018 851b26405a346d8aff55d96bc26ed9bb12995701
parent 482017 5955f883a957e165be245385c640fa3a64fabd8d
child 482019 972b64c9061501955b056adcb71e96b6f4b83abd
push id232
push userfmarier@mozilla.com
push dateWed, 05 Sep 2018 20:45:54 +0000
reviewerstnikkel
bugs1471583
milestone63.0a1
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>.