Bug 1500575 - Map inset clip paths to WR complex clip regions. r=kats

Differential Revision: https://phabricator.services.mozilla.com/D9412

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2018-10-23 00:10:00 +00:00
Родитель ba7599486e
Коммит d62a793992
6 изменённых файлов: 121 добавлений и 35 удалений

Просмотреть файл

@ -503,6 +503,31 @@ static inline wr::BorderRadius ToBorderRadius(const mozilla::LayoutDeviceSize& t
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;

Просмотреть файл

@ -3185,7 +3185,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
* 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) {
@ -3209,7 +3209,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
// 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()

Просмотреть файл

@ -587,25 +587,9 @@ DisplayItemClip::ToComplexClipRegions(
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));
}
}

Просмотреть файл

@ -23,6 +23,7 @@
#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"
@ -9963,6 +9964,84 @@ nsDisplayMasksAndClipPaths::PaintWithContentsPaintCallback(
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(
@ -9973,20 +10052,18 @@ nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
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.
@ -10006,7 +10083,7 @@ nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
/*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.
@ -10017,7 +10094,7 @@ nsDisplayMasksAndClipPaths::CreateWebRenderCommands(
nsDisplayEffectsBase::CreateWebRenderCommands(
aBuilder, aResources, *sc, aManager, aDisplayListBuilder);
if (mask) {
if (clip) {
aManager->CommandBuilder().PopOverrideForASR(GetActiveScrolledRoot());
}

Просмотреть файл

@ -51,9 +51,9 @@ fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-008.html clip-path-elli
== 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

Просмотреть файл

@ -181,7 +181,7 @@ nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
bool
nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(const nsIFrame* aFrame)
{
const nsStyleSVGReset *style = aFrame->StyleSVGReset();
const nsStyleSVGReset* style = aFrame->StyleSVGReset();
return style->HasClipPath() || style->HasMask();
}