Bug 1455944 - Do not paint nsDisplayOpacity children when opacity push/pop markers have empty paint rect r=mattwoodrow
authorMiko Mynttinen <mikokm@gmail.com>
Wed, 25 Apr 2018 22:54:18 +0200
changeset 471810 f9c00fb269a09a7944eb0be45eafc719f621d129
parent 471809 e561ff49b7cdd86d4cf437b98c986de76847f0dd
child 471811 f93d567284f7365632af954635ccfd438e8f2ed8
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1455944
milestone61.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 1455944 - Do not paint nsDisplayOpacity children when opacity push/pop markers have empty paint rect r=mattwoodrow MozReview-Commit-ID: 5BgHOFjW34H
layout/painting/FrameLayerBuilder.cpp
layout/painting/crashtests/1455944-1.html
layout/painting/crashtests/crashtests.list
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -6278,16 +6278,31 @@ struct ClipTracker {
     mContext->Save();
     mClips.AppendElement(aOpacityNesting);
   };
 
   AutoTArray<int, 2> mClips;
   gfxContext* mContext;
 };
 
+static void
+UpdateOpacityNesting(int& aOpacityNesting, DisplayItemEntryType aType)
+{
+  if (aType == DisplayItemEntryType::PUSH_OPACITY ||
+      aType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
+    aOpacityNesting++;
+  }
+
+  if (aType == DisplayItemEntryType::POP_OPACITY) {
+    aOpacityNesting--;
+  }
+
+  MOZ_ASSERT(aOpacityNesting >= 0);
+}
+
 void
 FrameLayerBuilder::PaintItems(nsTArray<AssignedDisplayItem>& aItems,
                               const nsIntRect& aRect,
                               gfxContext *aContext,
                               nsDisplayListBuilder* aBuilder,
                               nsPresContext* aPresContext,
                               const nsIntPoint& aOffset,
                               float aXScale, float aYScale)
@@ -6297,32 +6312,43 @@ FrameLayerBuilder::PaintItems(nsTArray<A
   int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
   nsRect boundRect = ToAppUnits(aRect, appUnitsPerDevPixel);
   boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
   boundRect.ScaleInverseRoundOut(aXScale, aYScale);
 
   DisplayItemClip currentClip, tmpClip;
 
+  // Tracks opacity nesting level for item level clipping.
   int opacityNesting = 0;
+
+  // Tracks opacity nesting level for skipping items between opacity markers,
+  // when opacity has empty visible rect set.
+  int emptyOpacityNesting = 0;
+
   ClipTracker clipTracker(aContext);
 
   for (uint32_t i = 0; i < aItems.Length(); ++i) {
     AssignedDisplayItem& cdi = aItems[i];
     nsDisplayItem* item = cdi.mItem;
 
     if (!item) {
       MOZ_ASSERT(cdi.mType == DisplayItemEntryType::ITEM);
       continue;
     }
 
     const nsRect& visibleRect = item->GetVisibleRect();
-
-    nsRect paintRect = visibleRect.Intersect(boundRect);
-    if (paintRect.IsEmpty()) {
+    const nsRect paintRect = visibleRect.Intersect(boundRect);
+
+    if (paintRect.IsEmpty() || emptyOpacityNesting > 0) {
+      // In order for this branch to be hit, either this item has an empty paint
+      // rect and nothing would be drawn, or a PUSH_OPACITY marker before this
+      // item had an empty paint rect. In the latter case, the items are skipped
+      // until POP_OPACITY markers bring |emptyOpacityNesting| back to 0.
+      UpdateOpacityNesting(emptyOpacityNesting, cdi.mType);
       continue;
     }
 
 #ifdef MOZ_DUMP_PAINTING
     AUTO_PROFILER_LABEL_DYNAMIC_CSTR("FrameLayerBuilder::PaintItems", GRAPHICS,
                                      item->Name());
 #else
     AUTO_PROFILER_LABEL("FrameLayerBuilder::PaintItems", GRAPHICS);
@@ -6330,30 +6356,29 @@ FrameLayerBuilder::PaintItems(nsTArray<A
 
     MOZ_ASSERT((opacityNesting == 0 && !cdi.mHasOpacity) ||
                (opacityNesting > 0 && cdi.mHasOpacity));
 
     if (cdi.mType == DisplayItemEntryType::PUSH_OPACITY ||
         cdi.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
       clipTracker.PopClipIfNeeded(opacityNesting);
       PushOpacity(aContext, paintRect, cdi, appUnitsPerDevPixel);
-      opacityNesting++;
     }
 
     if (cdi.mType == DisplayItemEntryType::POP_OPACITY) {
       MOZ_ASSERT(item->GetType() == DisplayItemType::TYPE_OPACITY);
       MOZ_ASSERT(opacityNesting > 0);
 
       clipTracker.PopClipIfNeeded(opacityNesting);
       aContext->PopGroupAndBlend();
       aContext->Restore();
-      opacityNesting--;
     }
 
     if (cdi.mType != DisplayItemEntryType::ITEM) {
+      UpdateOpacityNesting(opacityNesting, cdi.mType);
       continue;
     }
 
     // If the new desired clip state is different from the current state,
     // update the clip.
     const DisplayItemClip* clip = &item->GetClip();
     if (clip->GetRoundedRectCount() > 0 &&
         !clip->IsRectClippedByRoundedCorner(visibleRect)) {
@@ -6391,16 +6416,17 @@ FrameLayerBuilder::PaintItems(nsTArray<A
       {
         item->Paint(aBuilder, aContext);
       }
     }
   }
 
   clipTracker.PopClipIfNeeded(opacityNesting);
   MOZ_ASSERT(opacityNesting == 0);
+  MOZ_ASSERT(emptyOpacityNesting == 0);
 }
 
 /**
  * Returns true if it is preferred to draw the list of display
  * items separately for each rect in the visible region rather
  * than clipping to a complex region.
  */
 static bool
new file mode 100644
--- /dev/null
+++ b/layout/painting/crashtests/1455944-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="utf-8">
+</head>
+
+<body>
+<div style="opacity: 0.9;">
+    <iframe style="border: none;" src=""></iframe>
+</div>
+
+</body>
+</html>
--- a/layout/painting/crashtests/crashtests.list
+++ b/layout/painting/crashtests/crashtests.list
@@ -5,8 +5,9 @@ load 1413073-2.html
 load 1405881-1.html
 load 1418177-1.html
 load 1418722-1.html
 load 1419917.html
 load 1425271-1.html
 load 1428906-1.html
 skip-if(webrender) load 1430589-1.html # bug 1421825 for webrender
 load 1454105-1.html
+load 1455944-1.html