Bug 1455944 - Do not paint nsDisplayOpacity children when opacity push/pop markers have empty paint rect
MozReview-Commit-ID: 5BgHOFjW34H
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -6254,16 +6254,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)
@@ -6273,32 +6288,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);
@@ -6306,30 +6332,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)) {
@@ -6367,16 +6392,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