Bug 1501122 - Handle opacity with WebRender instead of generating a mask if we have a simple clip. r=kats
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 23 Oct 2018 02:23:19 +0200
changeset 490974 4e67ecbff9579883cfde518f79694164153ddcdd
parent 490973 e2a6c1b95477cba193170f8a9e5b98c8f74d32ce
child 490975 85cfe824ab6a8c80cd73faa101dcf9ddffe0db89
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerskats
bugs1501122
milestone65.0a1
Bug 1501122 - Handle opacity with WebRender instead of generating a mask if we have a simple clip. r=kats Differential Revision: https://phabricator.services.mozilla.com/D9458
layout/painting/nsDisplayList.cpp
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -9971,22 +9971,16 @@ CreateSimpleClipRegion(const nsDisplayMa
 {
   nsIFrame* frame = aDisplayItem.Frame();
   auto* style = frame->StyleSVGReset();
   MOZ_ASSERT(style->HasClipPath() || style->HasMask());
   if (style->HasMask()) {
     return Nothing();
   }
 
-  // TODO(emilio): We should be able to still generate a clip and pass the
-  // opacity down to StackingContextHelper instead.
-  if (frame->StyleEffects()->mOpacity != 1.0) {
-    return Nothing();
-  }
-
   auto& clipPath = style->mClipPath;
   if (clipPath.GetType() != StyleShapeSourceType::Shape) {
     return Nothing();
   }
 
   // TODO(emilio): We should be able to also simplify most of the circle() and
   // ellipse() shapes.
   auto& shape = clipPath.GetBasicShape();
@@ -10011,85 +10005,97 @@ CreateSimpleClipRegion(const nsDisplayMa
 
   auto rect = wr::ToRoundedLayoutRect(
     LayoutDeviceRect::FromAppUnits(insetRect, appUnitsPerDevPixel));
   wr::WrClipId clipId =
     aBuilder.DefineClip(Nothing(), rect, &clipRegions, nullptr);
   return Some(clipId);
 }
 
-static Maybe<wr::WrClipId>
+enum class HandleOpacity
+{
+  No,
+  Yes,
+};
+
+static Maybe<Pair<wr::WrClipId, HandleOpacity>>
 CreateWRClipPathAndMasks(nsDisplayMasksAndClipPaths* aDisplayItem,
                          const LayoutDeviceRect& aBounds,
                          wr::IpcResourceUpdateQueue& aResources,
                          wr::DisplayListBuilder& aBuilder,
                          const StackingContextHelper& aSc,
                          layers::WebRenderLayerManager* aManager,
                          nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (auto clip = CreateSimpleClipRegion(*aDisplayItem, aBuilder)) {
-    return clip;
+    return Some(MakePair(*clip, HandleOpacity::Yes));
   }
 
   Maybe<wr::WrImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(
     aDisplayItem, aBuilder, aResources, aSc, aDisplayListBuilder, aBounds);
   if (!mask) {
     return Nothing();
   }
 
   wr::WrClipId clipId =
     aBuilder.DefineClip(Nothing(),
                         wr::ToRoundedLayoutRect(aBounds),
                         nullptr,
                         mask.ptr());
 
-  return Some(clipId);
+  return Some(MakePair(clipId, HandleOpacity::No));
 }
 
 bool
 nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
   mozilla::wr::DisplayListBuilder& aBuilder,
   mozilla::wr::IpcResourceUpdateQueue& aResources,
   const StackingContextHelper& aSc,
   mozilla::layers::WebRenderLayerManager* aManager,
   nsDisplayListBuilder* aDisplayListBuilder)
 {
   bool snap;
   auto appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsRect displayBounds = GetBounds(aDisplayListBuilder, &snap);
   LayoutDeviceRect bounds =
     LayoutDeviceRect::FromAppUnits(displayBounds, appUnitsPerDevPixel);
 
-  Maybe<wr::WrClipId> clip =
+  Maybe<Pair<wr::WrClipId, HandleOpacity>> clip =
     CreateWRClipPathAndMasks(
       this, bounds, aResources, aBuilder, aSc, aManager, aDisplayListBuilder);
 
   Maybe<StackingContextHelper> layer;
   const StackingContextHelper* sc = &aSc;
   if (clip) {
     // Create a new stacking context to attach the mask to, ensuring the mask is
     // applied to the aggregate, and not the individual elements.
 
     // The stacking context shouldn't have any offset.
     bounds.MoveTo(0, 0);
 
+    wr::WrClipId clipId = clip->first();
+
+    Maybe<float> opacity = clip->second() == HandleOpacity::Yes
+      ? Some(mFrame->StyleEffects()->mOpacity)
+      : Nothing();
+
     layer.emplace(aSc,
                   aBuilder,
                   /*aFilters: */ nsTArray<wr::WrFilterOp>(),
                   /*aBounds: */ bounds,
                   /*aBoundTransform: */ nullptr,
                   /*aAnimation: */ nullptr,
-                  /*aOpacity: */ nullptr,
+                  /*aOpacity: */ opacity.ptrOr(nullptr),
                   /*aTransform: */ nullptr,
                   /*aPerspective: */ nullptr,
                   /*aMixBlendMode: */ gfx::CompositionOp::OP_OVER,
                   /*aBackfaceVisible: */ true,
                   /*aIsPreserve3D: */ false,
                   /*aTransformForScrollData: */ Nothing(),
-                  /*aClipNodeId: */ clip.ptr());
+                  /*aClipNodeId: */ &clipId);
     sc = layer.ptr();
     // The whole stacking context will be clipped by us, so no need to have any
     // parent for the children context's clip.
     aManager->CommandBuilder().PushOverrideForASR(GetActiveScrolledRoot(),
                                                   Nothing());
   }
 
   nsDisplayEffectsBase::CreateWebRenderCommands(