Bug 1128769 (Part 1) - Propagate the imgIContainer::Draw result through the nsLayoutUtils::PaintBackground* functions. r=tn a=lmandel
authorSeth Fowler <seth@mozilla.com>
Mon, 09 Feb 2015 23:27:39 -0800
changeset 250149 759ad062242f
parent 250148 824656d7ad0d
child 250150 69da299d5e49
push id4514
push usermfowler@mozilla.com
push date2015-03-02 22:11 +0000
treeherdermozilla-beta@7b3c7ba30dfe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, lmandel
bugs1128769
milestone37.0
Bug 1128769 (Part 1) - Propagate the imgIContainer::Draw result through the nsLayoutUtils::PaintBackground* functions. r=tn a=lmandel
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -57,17 +57,17 @@
 #include "gfxColor.h"
 #include "gfxGradientCache.h"
 #include "GraphicsFilter.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::gfx;
-using mozilla::image::ImageOps;
+using namespace mozilla::image;
 using mozilla::CSSSizeOrRatio;
 
 static int gFrameTreeLockCount = 0;
 
 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
 // recalculating this for each frame in a continuation (perf), hold
 // a cache of various coordinate information that we need in order
 // to paint inline backgrounds.
@@ -1613,17 +1613,17 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
     shadowContext->Fill();
     shadowContext->NewPath();
 
     blurringArea.DoPaint();
     renderContext->Restore();
   }
 }
 
-void
+DrawResult
 nsCSSRendering::PaintBackground(nsPresContext* aPresContext,
                                 nsRenderingContext& aRenderingContext,
                                 nsIFrame* aForFrame,
                                 const nsRect& aDirtyRect,
                                 const nsRect& aBorderArea,
                                 uint32_t aFlags,
                                 nsRect* aBGClipRect,
                                 int32_t aLayer)
@@ -1637,31 +1637,31 @@ nsCSSRendering::PaintBackground(nsPresCo
   nsStyleContext *sc;
   if (!FindBackground(aForFrame, &sc)) {
     // We don't want to bail out if moz-appearance is set on a root
     // node. If it has a parent content node, bail because it's not
     // a root, otherwise keep going in order to let the theme stuff
     // draw the background. The canvas really should be drawing the
     // bg, but there's no way to hook that up via css.
     if (!aForFrame->StyleDisplay()->mAppearance) {
-      return;
+      return DrawResult::SUCCESS;
     }
 
     nsIContent* content = aForFrame->GetContent();
     if (!content || content->GetParent()) {
-      return;
+      return DrawResult::SUCCESS;
     }
 
     sc = aForFrame->StyleContext();
   }
 
-  PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
-                        aDirtyRect, aBorderArea, sc,
-                        *aForFrame->StyleBorder(), aFlags,
-                        aBGClipRect, aLayer);
+  return PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
+                               aDirtyRect, aBorderArea, sc,
+                               *aForFrame->StyleBorder(), aFlags,
+                               aBGClipRect, aLayer);
 }
 
 static bool
 IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::css::Side aSide)
 {
   if (aBorder.GetComputedBorder().Side(aSide) == 0)
     return true;
   switch (aBorder.GetBorderStyle(aSide)) {
@@ -2812,47 +2812,52 @@ nsCSSRendering::PaintGradient(nsPresCont
         ctx->SetPattern(gradientPattern);
       }
       ctx->Fill();
       ctx->SetMatrix(ctm);
     }
   }
 }
 
-void
+DrawResult
 nsCSSRendering::PaintBackgroundWithSC(nsPresContext* aPresContext,
                                       nsRenderingContext& aRenderingContext,
                                       nsIFrame* aForFrame,
                                       const nsRect& aDirtyRect,
                                       const nsRect& aBorderArea,
                                       nsStyleContext* aBackgroundSC,
                                       const nsStyleBorder& aBorder,
                                       uint32_t aFlags,
                                       nsRect* aBGClipRect,
                                       int32_t aLayer)
 {
   NS_PRECONDITION(aForFrame,
                   "Frame is expected to be provided to PaintBackground");
 
+  // Initialize our result to success. We update it only if its value is
+  // currently DrawResult::SUCCESS, which means that as soon as we hit our first
+  // non-successful draw, we stop updating and will return that value.
+  DrawResult result = DrawResult::SUCCESS;
+
   // Check to see if we have an appearance defined.  If so, we let the theme
   // renderer draw the background and bail out.
   // XXXzw this ignores aBGClipRect.
   const nsStyleDisplay* displayData = aForFrame->StyleDisplay();
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame,
                                             displayData->mAppearance)) {
       nsRect drawing(aBorderArea);
       theme->GetWidgetOverflow(aPresContext->DeviceContext(),
                                aForFrame, displayData->mAppearance, &drawing);
       drawing.IntersectRect(drawing, aDirtyRect);
       theme->DrawWidgetBackground(&aRenderingContext, aForFrame,
                                   displayData->mAppearance, aBorderArea,
                                   drawing);
-      return;
+      return DrawResult::SUCCESS;
     }
   }
 
   // For canvas frames (in the CSS sense) we draw the background color using
   // a solid color item that gets added in nsLayoutUtils::PaintFrame,
   // or nsSubDocumentFrame::BuildDisplayList (bug 488242). (The solid
   // color may be moved into nsDisplayCanvasBackground by
   // nsPresShell::AddCanvasBackgroundColorItem, and painted by
@@ -2877,17 +2882,17 @@ nsCSSRendering::PaintBackgroundWithSC(ns
   if (drawBackgroundColor && aLayer >= 0) {
     drawBackgroundColor = false;
   }
 
   // At this point, drawBackgroundImage and drawBackgroundColor are
   // true if and only if we are actually supposed to paint an image or
   // color into aDirtyRect, respectively.
   if (!drawBackgroundImage && !drawBackgroundColor)
-    return;
+    return DrawResult::SUCCESS;
 
   // Compute the outermost boundary of the area that might be painted.
   // Same coordinate space as aBorderArea & aBGClipRect.
   Sides skipSides = aForFrame->GetSkipSides();
   nsRect paintBorderArea =
     ::BoxDecorationRectForBackground(aForFrame, aBorderArea, skipSides, &aBorder);
   nsRect clipBorderArea =
     ::BoxDecorationRectForBorder(aForFrame, aBorderArea, skipSides, &aBorder);
@@ -2924,23 +2929,23 @@ nsCSSRendering::PaintBackgroundWithSC(ns
 
   // If there is no background image, draw a color.  (If there is
   // neither a background image nor a color, we wouldn't have gotten
   // this far.)
   if (!drawBackgroundImage) {
     if (!isCanvasFrame) {
       DrawBackgroundColor(clipState, ctx, appUnitsPerPixel);
     }
-    return;
+    return DrawResult::SUCCESS;
   }
 
   if (bg->mImageCount < 1) {
     // Return if there are no background layers, all work from this point
     // onwards happens iteratively on these.
-    return;
+    return DrawResult::SUCCESS;
   }
 
   // Validate the layer range before we start iterating.
   int32_t startLayer = aLayer;
   int32_t nLayers = 1;
   if (startLayer < 0) {
     startLayer = (int32_t)bg->mImageCount - 1;
     nLayers = bg->mImageCount;
@@ -2999,27 +3004,36 @@ nsCSSRendering::PaintBackgroundWithSC(ns
         nsBackgroundLayerState state = PrepareBackgroundLayer(aPresContext, aForFrame,
             aFlags, paintBorderArea, clipState.mBGClipArea, layer);
         if (!state.mFillArea.IsEmpty()) {
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             NS_ASSERTION(ctx->CurrentOperator() == gfxContext::OPERATOR_OVER,
                          "It is assumed the initial operator is OPERATOR_OVER, when it is restored later");
             ctx->SetOperator(state.mCompositingOp);
           }
-          state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
-                                              state.mDestArea, state.mFillArea,
-                                              state.mAnchor + paintBorderArea.TopLeft(),
-                                              clipState.mDirtyRect);
+
+          DrawResult resultForLayer =
+            state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
+                                                state.mDestArea, state.mFillArea,
+                                                state.mAnchor + paintBorderArea.TopLeft(),
+                                                clipState.mDirtyRect);
+
+          if (result == DrawResult::SUCCESS) {
+            result = resultForLayer;
+          }
+
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             ctx->SetOperator(gfxContext::OPERATOR_OVER);
           }
         }
       }
     }
   }
+
+  return result;
 }
 
 static inline bool
 IsTransformed(nsIFrame* aForFrame, nsIFrame* aTopFrame)
 {
   for (nsIFrame* f = aForFrame; f != aTopFrame; f = f->GetParent()) {
     if (f->IsTransformed()) {
       return true;
@@ -4904,62 +4918,62 @@ ConvertImageRendererToDrawFlags(uint32_t
     drawFlags |= imgIContainer::FLAG_SYNC_DECODE;
   }
   if (aImageRendererFlags & nsImageRenderer::FLAG_PAINTING_TO_WINDOW) {
     drawFlags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
   }
   return drawFlags;
 }
 
-void
+DrawResult
 nsImageRenderer::Draw(nsPresContext*       aPresContext,
                       nsRenderingContext&  aRenderingContext,
                       const nsRect&        aDirtyRect,
                       const nsRect&        aDest,
                       const nsRect&        aFill,
                       const nsPoint&       aAnchor,
                       const CSSIntRect&    aSrc)
 {
   if (!mIsReady) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
-    return;
+    return DrawResult::TEMPORARY_ERROR;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
-    return;
+    return DrawResult::SUCCESS;
   }
 
   GraphicsFilter filter = nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame);
 
   switch (mType) {
     case eStyleImageType_Image:
     {
       nsIntSize imageSize(nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                           nsPresContext::AppUnitsToIntCSSPixels(mSize.height));
-      nsLayoutUtils::DrawBackgroundImage(*aRenderingContext.ThebesContext(),
-                                         aPresContext,
-                                         mImageContainer, imageSize, filter,
-                                         aDest, aFill, aAnchor, aDirtyRect,
-                                         ConvertImageRendererToDrawFlags(mFlags));
-      return;
+      return
+        nsLayoutUtils::DrawBackgroundImage(*aRenderingContext.ThebesContext(),
+                                           aPresContext,
+                                           mImageContainer, imageSize, filter,
+                                           aDest, aFill, aAnchor, aDirtyRect,
+                                           ConvertImageRendererToDrawFlags(mFlags));
     }
     case eStyleImageType_Gradient:
     {
       nsCSSRendering::PaintGradient(aPresContext, aRenderingContext,
                                     mGradientData, aDirtyRect,
                                     aDest, aFill, aSrc, mSize);
-      return;
+      return DrawResult::SUCCESS;
     }
     case eStyleImageType_Element:
     {
       nsRefPtr<gfxDrawable> drawable = DrawableForElement(aDest,
                                                           aRenderingContext);
       if (!drawable) {
         NS_WARNING("Could not create drawable for element");
-        return;
+        return DrawResult::TEMPORARY_ERROR;
       }
 
       gfxContext* ctx = aRenderingContext.ThebesContext();
       gfxContext::GraphicsOperator op = ctx->CurrentOperator();
       if (op != gfxContext::OPERATOR_OVER) {
         ctx->PushGroup(gfxContentType::COLOR_ALPHA);
         ctx->SetOperator(gfxContext::OPERATOR_OVER);
       }
@@ -4970,21 +4984,21 @@ nsImageRenderer::Draw(nsPresContext*    
                                filter, aDest, aFill, aAnchor, aDirtyRect,
                                ConvertImageRendererToDrawFlags(mFlags));
 
       if (op != gfxContext::OPERATOR_OVER) {
         ctx->PopGroupToSource();
         ctx->Paint();
       }
 
-      return;
+      return DrawResult::SUCCESS;
     }
     case eStyleImageType_Null:
     default:
-      return;
+      return DrawResult::SUCCESS;
   }
 }
 
 already_AddRefed<gfxDrawable>
 nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
                                     nsRenderingContext&  aRenderingContext)
 {
   NS_ASSERTION(mType == eStyleImageType_Element,
@@ -5007,38 +5021,38 @@ nsImageRenderer::DrawableForElement(cons
   }
   NS_ASSERTION(mImageElementSurface.mSourceSurface, "Surface should be ready.");
   nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(
                                 mImageElementSurface.mSourceSurface,
                                 mImageElementSurface.mSize);
   return drawable.forget();
 }
 
-void
+DrawResult
 nsImageRenderer::DrawBackground(nsPresContext*       aPresContext,
                                 nsRenderingContext&  aRenderingContext,
                                 const nsRect&        aDest,
                                 const nsRect&        aFill,
                                 const nsPoint&       aAnchor,
                                 const nsRect&        aDirty)
 {
   if (!mIsReady) {
     NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
-    return;
+    return DrawResult::TEMPORARY_ERROR;
   }
   if (aDest.IsEmpty() || aFill.IsEmpty() ||
       mSize.width <= 0 || mSize.height <= 0) {
-    return;
+    return DrawResult::SUCCESS;
   }
 
-  Draw(aPresContext, aRenderingContext,
-       aDirty, aDest, aFill, aAnchor,
-       CSSIntRect(0, 0,
-                  nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
-                  nsPresContext::AppUnitsToIntCSSPixels(mSize.height)));
+  return Draw(aPresContext, aRenderingContext,
+              aDirty, aDest, aFill, aAnchor,
+              CSSIntRect(0, 0,
+                         nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
+                         nsPresContext::AppUnitsToIntCSSPixels(mSize.height)));
 }
 
 /**
  * Compute the size and position of the master copy of the image. I.e., a single
  * tile used to fill the dest rect.
  * aFill The destination rect to be filled
  * aHFill and aVFill are the repeat patterns for the component -
  * NS_STYLE_BORDER_IMAGE_REPEAT_* - i.e., how a tiling unit is used to fill aFill
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -5,16 +5,17 @@
 
 /* utility functions for drawing borders and backgrounds */
 
 #ifndef nsCSSRendering_h___
 #define nsCSSRendering_h___
 
 #include "gfxBlur.h"
 #include "gfxContext.h"
+#include "imgIContainer.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/gfx/Rect.h"
 #include "nsLayoutUtils.h"
 #include "nsStyleStruct.h"
 #include "nsIFrame.h"
 
 class gfxDrawable;
 class nsStyleContext;
@@ -104,16 +105,17 @@ struct CSSSizeOrRatio
  * nsStyleImage image, which may internally be a real image, a sub image, or a
  * CSS gradient.
  *
  * @note Always call the member functions in the order of PrepareImage(),
  * SetSize(), and Draw*().
  */
 class nsImageRenderer {
 public:
+  typedef mozilla::image::DrawResult DrawResult;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::ImageContainer ImageContainer;
 
   enum {
     FLAG_SYNC_DECODE_IMAGES = 0x01,
     FLAG_PAINTING_TO_WINDOW = 0x02
   };
   enum FitType
@@ -197,22 +199,22 @@ public:
   void SetPreferredSize(const mozilla::CSSSizeOrRatio& aIntrinsicSize,
                         const nsSize& aDefaultSize);
 
   /**
    * Draws the image to the target rendering context using background-specific
    * arguments.
    * @see nsLayoutUtils::DrawImage() for parameters.
    */
-  void DrawBackground(nsPresContext*       aPresContext,
-                      nsRenderingContext&  aRenderingContext,
-                      const nsRect&        aDest,
-                      const nsRect&        aFill,
-                      const nsPoint&       aAnchor,
-                      const nsRect&        aDirty);
+  DrawResult DrawBackground(nsPresContext*       aPresContext,
+                            nsRenderingContext&  aRenderingContext,
+                            const nsRect&        aDest,
+                            const nsRect&        aFill,
+                            const nsPoint&       aAnchor,
+                            const nsRect&        aDirty);
 
   /**
    * Draw the image to a single component of a border-image style rendering.
    * aFill The destination rect to be drawn into
    * aSrc is the part of the image to be rendered into a tile (aUnitSize in
    * aFill), if aSrc and the dest tile are different sizes, the image will be
    * scaled to map aSrc onto the dest tile.
    * aHFill and aVFill are the repeat patterns for the component -
@@ -242,23 +244,23 @@ public:
 private:
   /**
    * Draws the image to the target rendering context.
    * aSrc is a rect on the source image which will be mapped to aDest; it's
    * currently only used for gradients.
    *
    * @see nsLayoutUtils::DrawImage() for other parameters.
    */
-  void Draw(nsPresContext*       aPresContext,
-            nsRenderingContext&  aRenderingContext,
-            const nsRect&        aDirtyRect,
-            const nsRect&        aDest,
-            const nsRect&        aFill,
-            const nsPoint&       aAnchor,
-            const mozilla::CSSIntRect& aSrc);
+  DrawResult Draw(nsPresContext*       aPresContext,
+                  nsRenderingContext&  aRenderingContext,
+                  const nsRect&        aDirtyRect,
+                  const nsRect&        aDest,
+                  const nsRect&        aFill,
+                  const nsPoint&       aAnchor,
+                  const mozilla::CSSIntRect& aSrc);
 
   /**
    * Helper method for creating a gfxDrawable from mPaintServerFrame or 
    * mImageElementSurface.
    * Requires mType is eStyleImageType_Element.
    * Returns null if we cannot create the drawable.
    */
   already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
@@ -316,16 +318,17 @@ struct nsBackgroundLayerState {
   gfxContext::GraphicsOperator mCompositingOp;
 };
 
 struct nsCSSRendering {
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
+  typedef mozilla::image::DrawResult DrawResult;
   typedef nsIFrame::Sides Sides;
 
   /**
    * Initialize any static variables used by nsCSSRendering.
    */
   static void Init();
   
   /**
@@ -549,44 +552,44 @@ struct nsCSSRendering {
      */
     PAINTBG_SYNC_DECODE_IMAGES = 0x02,
     /**
      * When this flag is passed, painting will go to the screen so we can
      * take advantage of the fact that it will be clipped to the viewport.
      */
     PAINTBG_TO_WINDOW = 0x04
   };
-  static void PaintBackground(nsPresContext* aPresContext,
-                              nsRenderingContext& aRenderingContext,
-                              nsIFrame* aForFrame,
-                              const nsRect& aDirtyRect,
-                              const nsRect& aBorderArea,
-                              uint32_t aFlags,
-                              nsRect* aBGClipRect = nullptr,
-                              int32_t aLayer = -1);
+  static DrawResult PaintBackground(nsPresContext* aPresContext,
+                                    nsRenderingContext& aRenderingContext,
+                                    nsIFrame* aForFrame,
+                                    const nsRect& aDirtyRect,
+                                    const nsRect& aBorderArea,
+                                    uint32_t aFlags,
+                                    nsRect* aBGClipRect = nullptr,
+                                    int32_t aLayer = -1);
 
   /**
    * Same as |PaintBackground|, except using the provided style structs.
    * This short-circuits the code that ensures that the root element's
    * background is drawn on the canvas.
    * The aLayer parameter allows you to paint a single layer of the background.
    * The default value for aLayer, -1, means that all layers will be painted.
    * The background color will only be painted if the back-most layer is also
    * being painted.
    */
-  static void PaintBackgroundWithSC(nsPresContext* aPresContext,
-                                    nsRenderingContext& aRenderingContext,
-                                    nsIFrame* aForFrame,
-                                    const nsRect& aDirtyRect,
-                                    const nsRect& aBorderArea,
-                                    nsStyleContext *aStyleContext,
-                                    const nsStyleBorder& aBorder,
-                                    uint32_t aFlags,
-                                    nsRect* aBGClipRect = nullptr,
-                                    int32_t aLayer = -1);
+  static DrawResult PaintBackgroundWithSC(nsPresContext* aPresContext,
+                                          nsRenderingContext& aRenderingContext,
+                                          nsIFrame* aForFrame,
+                                          const nsRect& aDirtyRect,
+                                          const nsRect& aBorderArea,
+                                          nsStyleContext *aStyleContext,
+                                          const nsStyleBorder& aBorder,
+                                          uint32_t aFlags,
+                                          nsRect* aBGClipRect = nullptr,
+                                          int32_t aLayer = -1);
 
   /**
    * Returns the rectangle covered by the given background layer image, taking
    * into account background positioning, sizing, and repetition, but not
    * clipping.
    */
   static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,