--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -498,16 +498,41 @@ static inline wr::BorderRadius ToBorderR
wr::BorderRadius br;
br.top_left = ToLayoutSize(topLeft);
br.top_right = ToLayoutSize(topRight);
br.bottom_left = ToLayoutSize(bottomLeft);
br.bottom_right = ToLayoutSize(bottomRight);
return br;
}
+static inline wr::ComplexClipRegion ToComplexClipRegion(
+ const nsRect& aRect,
+ const nscoord* aRadii,
+ int32_t aAppUnitsPerDevPixel)
+{
+ wr::ComplexClipRegion ret;
+ ret.rect = ToRoundedLayoutRect(
+ LayoutDeviceRect::FromAppUnits(aRect, aAppUnitsPerDevPixel));
+ ret.radii = ToBorderRadius(
+ LayoutDeviceSize::FromAppUnits(
+ nsSize(aRadii[eCornerTopLeftX], aRadii[eCornerTopLeftY]),
+ aAppUnitsPerDevPixel),
+ LayoutDeviceSize::FromAppUnits(
+ nsSize(aRadii[eCornerTopRightX], aRadii[eCornerTopRightY]),
+ aAppUnitsPerDevPixel),
+ LayoutDeviceSize::FromAppUnits(
+ nsSize(aRadii[eCornerBottomLeftX], aRadii[eCornerBottomLeftY]),
+ aAppUnitsPerDevPixel),
+ LayoutDeviceSize::FromAppUnits(
+ nsSize(aRadii[eCornerBottomRightX], aRadii[eCornerBottomRightY]),
+ aAppUnitsPerDevPixel));
+ ret.mode = ClipMode::Clip;
+ return ret;
+}
+
static inline wr::LayoutSideOffsets ToBorderWidths(float top, float right, float bottom, float left)
{
wr::LayoutSideOffsets bw;
bw.top = top;
bw.right = right;
bw.bottom = bottom;
bw.left = left;
return bw;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3180,17 +3180,17 @@ nsIFrame::BuildDisplayListForStackingCon
}
/* If there are any SVG effects, wrap the list up in an SVG effects item
* (which also handles CSS group opacity). Note that we create an SVG effects
* item even if resultList is empty, since a filter can produce graphical
* output even if the element being filtered wouldn't otherwise do so.
*/
if (usingSVGEffects) {
- MOZ_ASSERT(usingFilter ||usingMask,
+ MOZ_ASSERT(usingFilter || usingMask,
"Beside filter & mask/clip-path, what else effect do we have?");
if (clipCapturedBy == ContainerItemType::eFilter) {
clipState.Restore();
}
// Revert to the post-filter dirty rect.
aBuilder->SetVisibleRect(visibleRectOutsideSVGEffects);
@@ -3204,17 +3204,17 @@ nsIFrame::BuildDisplayListForStackingCon
if (usingMask) {
DisplayListClipState::AutoSaveRestore maskClipState(aBuilder);
// The mask should move with aBuilder->CurrentActiveScrolledRoot(), so
// that's the ASR we prefer to use for the mask item. However, we can
// only do this if the mask if clipped with respect to that ASR, because
// an item always needs to have finite bounds with respect to its ASR.
// If we weren't able to compute a clip for the mask, we fall back to
// using containerItemASR, which is the lowest common ancestor clip of
- // the mask's contents. That's not entirely crrect, but it satisfies
+ // the mask's contents. That's not entirely correct, but it satisfies
// the base requirement of the ASR system (that items have finite bounds
// wrt. their ASR).
const ActiveScrolledRoot* maskASR = clipForMask.isSome()
? aBuilder->CurrentActiveScrolledRoot()
: containerItemASR;
/* List now emptied, so add the new list to the top. */
resultList.AppendToTop(MakeDisplayItem<nsDisplayMasksAndClipPaths>(
aBuilder, this, &resultList, maskASR));
--- a/layout/painting/DisplayItemClip.cpp
+++ b/layout/painting/DisplayItemClip.cpp
@@ -582,31 +582,15 @@ DisplayItemClip::ToString() const
}
void
DisplayItemClip::ToComplexClipRegions(
int32_t aAppUnitsPerDevPixel,
const layers::StackingContextHelper& aSc,
nsTArray<wr::ComplexClipRegion>& aOutArray) const
{
- for (uint32_t i = 0; i < mRoundedClipRects.Length(); i++) {
- wr::ComplexClipRegion* region = aOutArray.AppendElement();
- region->rect = wr::ToRoundedLayoutRect(LayoutDeviceRect::FromAppUnits(
- mRoundedClipRects[i].mRect, aAppUnitsPerDevPixel));
- const nscoord* radii = mRoundedClipRects[i].mRadii;
- region->radii = wr::ToBorderRadius(
- LayoutDeviceSize::FromAppUnits(
- nsSize(radii[eCornerTopLeftX], radii[eCornerTopLeftY]),
- aAppUnitsPerDevPixel),
- LayoutDeviceSize::FromAppUnits(
- nsSize(radii[eCornerTopRightX], radii[eCornerTopRightY]),
- aAppUnitsPerDevPixel),
- LayoutDeviceSize::FromAppUnits(
- nsSize(radii[eCornerBottomLeftX], radii[eCornerBottomLeftY]),
- aAppUnitsPerDevPixel),
- LayoutDeviceSize::FromAppUnits(
- nsSize(radii[eCornerBottomRightX], radii[eCornerBottomRightY]),
- aAppUnitsPerDevPixel));
- region->mode = wr::ClipMode::Clip;
+ for (const auto& clipRect : mRoundedClipRects) {
+ aOutArray.AppendElement(wr::ToComplexClipRegion(
+ clipRect.mRect, clipRect.mRadii, aAppUnitsPerDevPixel));
}
}
} // namespace mozilla
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -18,16 +18,17 @@
#include "gfxContext.h"
#include "gfxUtils.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/PLayerTransaction.h"
+#include "mozilla/ShapeUtils.h"
#include "nsCSSRendering.h"
#include "nsCSSRenderingGradients.h"
#include "nsISelectionController.h"
#include "nsIPresShell.h"
#include "nsRegion.h"
#include "nsStyleStructInlines.h"
#include "nsStyleTransformMatrix.h"
#include "gfxMatrix.h"
@@ -9958,40 +9959,116 @@ nsDisplayMasksAndClipPaths::PaintWithCon
nsSVGIntegrationUtils::PaintMaskAndClipPath(params, aPaintChildren);
context->PopClip();
nsDisplayMasksAndClipPathsGeometry::UpdateDrawResult(this, imgParams.result);
}
+static Maybe<wr::WrClipId>
+CreateSimpleClipRegion(const nsDisplayMasksAndClipPaths& aDisplayItem,
+ wr::DisplayListBuilder& aBuilder)
+{
+ 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();
+ if (shape->GetShapeType() != StyleBasicShapeType::Inset) {
+ return Nothing();
+ }
+
+ const nsRect refBox =
+ nsLayoutUtils::ComputeGeometryBox(frame, clipPath.GetReferenceBox());
+
+ const nsRect insetRect =
+ ShapeUtils::ComputeInsetRect(shape, refBox) + aDisplayItem.ToReferenceFrame();
+
+ auto appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
+
+ nscoord radii[8] = { 0 };
+ AutoTArray<wr::ComplexClipRegion, 1> clipRegions;
+ if (ShapeUtils::ComputeInsetRadii(shape, insetRect, refBox, radii)) {
+ clipRegions.AppendElement(wr::ToComplexClipRegion(
+ insetRect, radii, appUnitsPerDevPixel));
+ }
+
+ auto rect = wr::ToRoundedLayoutRect(
+ LayoutDeviceRect::FromAppUnits(insetRect, appUnitsPerDevPixel));
+ wr::WrClipId clipId =
+ aBuilder.DefineClip(Nothing(), rect, &clipRegions, nullptr);
+ return Some(clipId);
+}
+
+static Maybe<wr::WrClipId>
+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;
+ }
+
+ 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);
+}
bool
nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder)
{
bool snap;
- float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+ auto appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
nsRect displayBounds = GetBounds(aDisplayListBuilder, &snap);
LayoutDeviceRect bounds =
LayoutDeviceRect::FromAppUnits(displayBounds, appUnitsPerDevPixel);
- Maybe<wr::WrImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(
- this, aBuilder, aResources, aSc, aDisplayListBuilder, bounds);
+ Maybe<wr::WrClipId> clip =
+ CreateWRClipPathAndMasks(
+ this, bounds, aResources, aBuilder, aSc, aManager, aDisplayListBuilder);
+
Maybe<StackingContextHelper> layer;
const StackingContextHelper* sc = &aSc;
- if (mask) {
- auto layoutBounds = wr::ToRoundedLayoutRect(bounds);
- wr::WrClipId clipId =
- aBuilder.DefineClip(Nothing(), layoutBounds, nullptr, mask.ptr());
-
+ 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);
layer.emplace(aSc,
aBuilder,
@@ -10001,28 +10078,28 @@ nsDisplayMasksAndClipPaths::CreateWebRen
/*aAnimation: */ nullptr,
/*aOpacity: */ nullptr,
/*aTransform: */ nullptr,
/*aPerspective: */ nullptr,
/*aMixBlendMode: */ gfx::CompositionOp::OP_OVER,
/*aBackfaceVisible: */ true,
/*aIsPreserve3D: */ false,
/*aTransformForScrollData: */ Nothing(),
- /*aClipNodeId: */ &clipId);
+ /*aClipNodeId: */ clip.ptr());
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(
aBuilder, aResources, *sc, aManager, aDisplayListBuilder);
- if (mask) {
+ if (clip) {
aManager->CommandBuilder().PopOverrideForASR(GetActiveScrolledRoot());
}
return true;
}
Maybe<nsRect>
nsDisplayMasksAndClipPaths::GetClipWithRespectToASR(
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -46,16 +46,16 @@ fuzzy-if(webrender,64-64,1106-1106) == c
fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-008.html clip-path-ellipse-001-ref.html
== clip-path-inset-001a.html clip-path-inset-001-ref.html
== clip-path-inset-001b.html clip-path-inset-001-ref.html
== clip-path-inset-001c.html clip-path-inset-001-ref.html
# Anti-aliasing behavior for masking and borders is different
-fuzzy(0-64,0-146) fuzzy-if(webrender,90-90,132-132) == clip-path-inset-002a.html clip-path-inset-002-ref.html
-fuzzy(0-64,0-146) fuzzy-if(webrender,90-90,132-132) == clip-path-inset-002b.html clip-path-inset-002-ref.html
-fuzzy(0-64,0-146) fuzzy-if(webrender,90-90,132-132) == clip-path-inset-002c.html clip-path-inset-002-ref.html
+fuzzy-if(!webrender,0-64,0-146) == clip-path-inset-002a.html clip-path-inset-002-ref.html
+fuzzy-if(!webrender,0-64,0-146) == clip-path-inset-002b.html clip-path-inset-002-ref.html
+fuzzy-if(!webrender,0-64,0-146) == clip-path-inset-002c.html clip-path-inset-002-ref.html
fuzzy(0-64,0-340) fuzzy-if(webrender,104-104,311-311) == clip-path-inset-003.html clip-path-inset-003-ref.html
== clip-path-stroke-001.html clip-path-stroke-001-ref.html
== clip-path-transform-001.html clip-path-transform-001-ref.html
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -176,17 +176,17 @@ nsSVGIntegrationUtils::UsingEffectsForFr
const nsStyleSVGReset *style = aFrame->StyleSVGReset();
return aFrame->StyleEffects()->HasFilters() ||
style->HasClipPath() || style->HasMask();
}
bool
nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(const nsIFrame* aFrame)
{
- const nsStyleSVGReset *style = aFrame->StyleSVGReset();
+ const nsStyleSVGReset* style = aFrame->StyleSVGReset();
return style->HasClipPath() || style->HasMask();
}
nsPoint
nsSVGIntegrationUtils::GetOffsetToBoundingBox(nsIFrame* aFrame)
{
if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
// Do NOT call GetAllInFlowRectsUnion for SVG - it will get the