Bug 1275026: Part 1. Prevent infinit recursion in GenerateAndPushTextMask draft
authorcku <cku@mozilla.com>
Tue, 24 May 2016 12:14:57 +0800
changeset 370263 55ed71ad5cb64174cee70cbbc3a5cdd42052acd6
parent 369957 46fe2115d46a5bb40523b8466341d8f9a26e1bdf
child 370264 e1514dec77f704fa4d69cc078f47df20b921ea55
push id19024
push usercku@mozilla.com
push dateTue, 24 May 2016 12:13:19 +0000
bugs1275026
milestone49.0a1
Bug 1275026: Part 1. Prevent infinit recursion in GenerateAndPushTextMask MozReview-Commit-ID: 4tcMuW5i13F
layout/base/nsDisplayList.cpp
layout/base/nsLayoutUtils.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -487,20 +487,25 @@ AddAnimationsForProperty(nsIFrame* aFram
       continue;
     }
 
     AddAnimationForProperty(aFrame, *property, anim, aLayer, aData, aPending);
     effect->SetIsRunningOnCompositor(aProperty, true);
   }
 }
 
-static void
+static bool
 GenerateAndPushTextMask(nsIFrame* aFrame, nsRenderingContext* aContext,
-                        const nsRect& aFillRect)
-{
+                        const nsRect& aFillRect, nsDisplayListBuilder* aBuilder)
+{
+  if (aBuilder->IsForGenerateGlyphMask() ||
+      aBuilder->IsForPaintingSelectionBG()) {
+    return false;
+  }
+
   // The main function of enabling background-clip:text property value.
   // When a nsDisplayBackgroundImage detects "text" bg-clip style, it will call
   // this function to
   // 1. Paint background color of the selection text if any.
   // 2. Generate a mask by all descendant text frames
   // 3. Push the generated mask into aContext.
   //
   // TBD: we actually generate display list of aFrame twice here. It's better
@@ -557,16 +562,18 @@ GenerateAndPushTextMask(nsIFrame* aFrame
   // Push the generated mask into aContext, so that the caller can pop and
   // blend with it.
   Matrix maskTransform = ToMatrix(currentMatrix) *
                          Matrix::Translation(-drawRect.x, -drawRect.y);
   maskTransform.Invert();
 
   RefPtr<SourceSurface> maskSurface = maskDT->Snapshot();
   sourceCtx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0, maskSurface, maskTransform);
+
+  return true;
 }
 
 /* static */ void
 nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
                                                          nsDisplayListBuilder* aBuilder,
                                                          nsDisplayItem* aItem,
                                                          nsIFrame* aFrame,
                                                          nsCSSProperty aProperty)
@@ -2446,21 +2453,16 @@ SetBackgroundClipRegion(DisplayListClipS
 
 /*static*/ bool
 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
                                                      nsIFrame* aFrame,
                                                      const nsRect& aBackgroundRect,
                                                      nsDisplayList* aList,
                                                      bool aAllowWillPaintBorderOptimization)
 {
-  if (aBuilder->IsForGenerateGlyphMask() ||
-      aBuilder->IsForPaintingSelectionBG()) {
-    return true;
-  }
-
   nsStyleContext* bgSC = nullptr;
   const nsStyleBackground* bg = nullptr;
   nsRect bgRect = aBackgroundRect + aBuilder->ToReferenceFrame(aFrame);
   nsPresContext* presContext = aFrame->PresContext();
   bool isThemed = aFrame->IsThemed();
   if (!isThemed) {
     bgSC = GetBackgroundStyleContext(aFrame);
     if (bgSC) {
@@ -2952,17 +2954,19 @@ nsDisplayBackgroundImage::PaintInternal(
                                         nsRect* aClipRect) {
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   CheckForBorderItem(this, flags);
 
   gfxContext* ctx = aCtx->ThebesContext();
   uint8_t clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip;
 
   if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
-    GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect);
+    if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
+      return;
+    }
   }
 
   nsCSSRendering::PaintBGParams params =
     nsCSSRendering::PaintBGParams::ForSingleLayer(*mFrame->PresContext(),
                                                   *aCtx,
                                                   aBounds, mBackgroundRect,
                                                   mFrame, flags, mLayer,
                                                   CompositionOp::OP_OVER);
@@ -3386,17 +3390,20 @@ nsDisplayBackgroundColor::Paint(nsDispla
 #else
   gfxContext* ctx = aCtx->ThebesContext();
   gfxRect bounds =
     nsLayoutUtils::RectToGfxRect(mBackgroundRect,
                                  mFrame->PresContext()->AppUnitsPerDevPixel());
 
   uint8_t clip = mBackgroundStyle->mImage.mLayers[0].mClip;
   if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
-    GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect);
+    if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
+      return;
+    }
+
     ctx->SetColor(mColor);
     ctx->Rectangle(bounds, true);
     ctx->Fill();
     ctx->PopGroupAndBlend();
     return;
   }
 
   ctx->SetColor(mColor);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3451,30 +3451,16 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
 #endif
 
     nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
 
     PROFILER_LABEL("nsLayoutUtils", "PaintFrame::BuildDisplayList",
       js::ProfileEntry::Category::GRAPHICS);
 
     aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list);
-#ifdef DEBUG
-    if (builder.IsForGenerateGlyphMask() || builder.IsForPaintingSelectionBG()) {
-      // PaintFrame is called to generate text glyph by
-      // nsDisplayBackgroundImage::Paint or nsDisplayBackgroundColor::Paint.
-      //
-      // Assert that we do not generate and put nsDisplayBackgroundImage or
-      // nsDisplayBackgroundColor into the list again, which would lead to
-      // infinite recursion.
-      for (nsDisplayItem* i = list.GetBottom(); i; i = i->GetAbove()) {
-        MOZ_ASSERT(nsDisplayItem::TYPE_BACKGROUND != i->GetType() &&
-                   nsDisplayItem::TYPE_BACKGROUND_COLOR != i->GetType());
-      }
-    }
-#endif
   }
 
   nsIAtom* frameType = aFrame->GetType();
 
   // For the viewport frame in print preview/page layout we want to paint
   // the grey background behind the page, not the canvas color.
   if (frameType == nsGkAtoms::viewportFrame &&
       nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {