Commit fb48c272 authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

Use GeometryMapper to map visual rect with filters for paint invalidation

Bug: 637313
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: Icad7f9354b7cb92ddfe8caa5224e3ba2540f7440
Reviewed-on: https://chromium-review.googlesource.com/667756
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#504287}
parent 943bceea
......@@ -8,7 +8,7 @@
"paintInvalidations": [
{
"object": "LayoutBlockFlow (positioned) DIV id='box' class='green box'",
"rect": [300, 8, 329, 329],
"rect": [300, 8, 330, 330],
"reason": "subtree"
},
{
......
......@@ -8,12 +8,12 @@
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='box'",
"rect": [8, 8, 429, 229],
"rect": [8, 8, 430, 230],
"reason": "subtree"
},
{
"object": "LayoutBlockFlow (positioned) DIV id='positioned'",
"rect": [400, 400, 379, 179],
"rect": [400, 400, 380, 180],
"reason": "subtree"
}
]
......
......@@ -8,7 +8,7 @@
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='box' class='green box blurry'",
"rect": [8, 8, 329, 329],
"rect": [8, 8, 330, 330],
"reason": "subtree"
}
]
......
......@@ -17,7 +17,7 @@
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='resize' class='drop-shadow'",
"rect": [-1, -1, 258, 258],
"rect": [-2, -2, 260, 260],
"reason": "geometry"
}
],
......
......@@ -8,7 +8,7 @@
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV class='box'",
"rect": [1, -7, 314, 314],
"rect": [-2, -10, 320, 320],
"reason": "style change"
}
]
......
......@@ -8,7 +8,7 @@
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV class='box'",
"rect": [1, 50, 314, 200],
"rect": [-2, 50, 320, 200],
"reason": "style change"
}
]
......
......@@ -8,7 +8,7 @@
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV class='box'",
"rect": [58, -7, 200, 314],
"rect": [58, -10, 200, 320],
"reason": "style change"
}
]
......
......@@ -28,22 +28,22 @@
},
{
"object": "LayoutSVGPath polygon",
"rect": [455, 165, 135, 134],
"rect": [183, 165, 134, 134],
"reason": "style change"
},
{
"object": "LayoutSVGPath polygon id='t3'",
"rect": [319, 165, 135, 134],
"object": "LayoutSVGPath polygon",
"rect": [456, 165, 133, 134],
"reason": "style change"
},
{
"object": "LayoutSVGPath polygon",
"rect": [46, 165, 135, 134],
"object": "LayoutSVGPath polygon id='t3'",
"rect": [320, 165, 133, 134],
"reason": "style change"
},
{
"object": "LayoutSVGPath polygon",
"rect": [183, 165, 134, 134],
"rect": [47, 165, 133, 134],
"reason": "style change"
},
{
......
......@@ -114,7 +114,9 @@ LayoutRect PaintInvalidator::MapLocalRectToVisualRectInBacking(
if (context.tree_builder_context_->current.transform ==
container_contents_properties.Transform() &&
context.tree_builder_context_->current.clip ==
container_contents_properties.Clip()) {
container_contents_properties.Clip() &&
context.tree_builder_context_->current_effect ==
container_contents_properties.Effect()) {
result = LayoutRect(rect);
} else {
// Use enclosingIntRect to ensure the final visual rect will cover the
......@@ -128,7 +130,8 @@ LayoutRect PaintInvalidator::MapLocalRectToVisualRectInBacking(
PropertyTreeState current_tree_state(
context.tree_builder_context_->current.transform,
context.tree_builder_context_->current.clip, nullptr);
context.tree_builder_context_->current.clip,
context.tree_builder_context_->current_effect);
FloatClipRect float_rect((FloatRect(rect)));
GeometryMapper::LocalToAncestorVisualRect(
......@@ -493,12 +496,9 @@ void PaintInvalidator::InvalidatePaint(
!RuntimeEnabledFeatures::PrintBrowserEnabled())
return; // Don't invalidate paints if we're printing.
// TODO(crbug.com/637313): Use GeometryMapper which now supports filter
// geometry effects, after skia optimizes filter's mapRect operation.
// TODO(crbug.com/648274): implement fast path for fragmented content.
if (object.HasFilterInducingProperty() || object.IsLayoutFlowThread()) {
if (object.IsLayoutFlowThread())
context.subtree_flags |= PaintInvalidatorContext::kSubtreeSlowPathRect;
}
UpdatePaintInvalidationContainer(object, context);
UpdateEmptyVisualRectFlag(object, context);
......
......@@ -361,7 +361,7 @@ void PaintLayerClipper::CalculateRects(
// FIXME: Does not do the right thing with columns yet, since we don't yet
// factor in the individual column boxes as overflow.
LayoutRect layer_bounds_with_visual_overflow = LocalVisualRect();
LayoutRect layer_bounds_with_visual_overflow = LocalVisualRect(context);
layer_bounds_with_visual_overflow.MoveBy(offset);
background_rect.Intersect(layer_bounds_with_visual_overflow);
}
......@@ -466,7 +466,7 @@ void PaintLayerClipper::CalculateBackgroundClipRectWithGeometryMapper(
// rects, so we should add methods to GeometryMapper that guarantee there
// are tight results, or else signal an error.
if (HasOverflowClip(layer_)) {
FloatClipRect clip_rect((FloatRect(LocalVisualRect())));
FloatClipRect clip_rect((FloatRect(LocalVisualRect(context))));
if (layer_.ShouldFragmentCompositedBounds(context.root_layer))
clip_rect.MoveBy(FloatPoint(fragment_data.PaintOffset()));
else
......@@ -523,7 +523,8 @@ void PaintLayerClipper::InitializeCommonClipRectState(
}
}
LayoutRect PaintLayerClipper::LocalVisualRect() const {
LayoutRect PaintLayerClipper::LocalVisualRect(
const ClipRectsContext& context) const {
const LayoutObject& layout_object = layer_.GetLayoutObject();
// The LayoutView is special since its overflow clipping rect may be larger
// than its box rect (crbug.com/492871).
......@@ -539,7 +540,10 @@ LayoutRect PaintLayerClipper::LocalVisualRect() const {
// At this point layer_bounds_with_visual_overflow only includes the visual
// overflow induced by paint, prior to applying filters. This function is
// expected the return the final visual rect after filtering.
if (layer_.PaintsWithFilters()) {
if (layer_.PaintsWithFilters() &&
// If we use GeometryMapper to map to an ancestor layer, GeometryMapper
// will handle filter effects.
(!use_geometry_mapper_ || context.root_layer == &layer_)) {
layer_bounds_with_visual_overflow =
layer_.MapLayoutRectForFilter(layer_bounds_with_visual_overflow);
}
......
......@@ -244,9 +244,9 @@ class CORE_EXPORT PaintLayerClipper {
ClipRect& foreground_rect,
const LayoutPoint* offset_from_root = 0) const;
// Returns the visual rect of m_layer in local space. This includes
// filter effects.
ALWAYS_INLINE LayoutRect LocalVisualRect() const;
// Returns the visual rect of |layer_| in local space. This includes
// filter effects if needed.
ALWAYS_INLINE LayoutRect LocalVisualRect(const ClipRectsContext&) const;
const PaintLayer& layer_;
bool use_geometry_mapper_;
......
......@@ -456,13 +456,15 @@ TEST_F(PaintLayerClipperTest, Filter) {
" * { margin: 0 }"
" #target { "
" filter: drop-shadow(0 3px 4px #333); overflow: hidden;"
" width: 100px; height: 200px;"
" width: 100px; height: 200px; border: 40px solid blue; margin: 50px;"
" }"
"</style>"
"<div id='target'></div>");
PaintLayer* target =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"))->Layer();
// First test clip rects in the target layer itself.
ClipRectsContext context(target, kUncachedClipRects);
LayoutRect infinite_rect(LayoutRect::InfiniteIntRect());
LayoutRect layer_bounds(infinite_rect);
......@@ -475,11 +477,44 @@ TEST_F(PaintLayerClipperTest, Filter) {
// The background rect is used to clip stacking context (layer) output.
// In this case, nothing is above us, thus the infinite rect. However we do
// clip to the layer's after-filter visual rect as an optimization
EXPECT_EQ(LayoutRect(-12, -9, 124, 224), background_rect.Rect());
// clip to the layer's after-filter visual rect as an optimization.
EXPECT_EQ(LayoutRect(-12, -9, 204, 304), background_rect.Rect());
// The foreground rect is used to clip the normal flow contents of the
// stacking context (layer) thus including the overflow clip.
EXPECT_EQ(LayoutRect(0, 0, 100, 200), foreground_rect.Rect());
EXPECT_EQ(LayoutRect(40, 40, 100, 200), foreground_rect.Rect());
// Test without GeometryMapper.
background_rect = infinite_rect;
foreground_rect = infinite_rect;
target->Clipper(PaintLayer::kDoNotUseGeometryMapper)
.CalculateRects(context, nullptr, infinite_rect, layer_bounds,
background_rect, foreground_rect);
// The non-GeometryMapper path applies the immediate filter effect in
// background rect.
EXPECT_EQ(LayoutRect(-12, -9, 204, 304), background_rect.Rect());
EXPECT_EQ(LayoutRect(40, 40, 100, 200), foreground_rect.Rect());
// Test mapping to the root layer.
ClipRectsContext root_context(GetLayoutView().Layer(), kUncachedClipRects);
background_rect = infinite_rect;
foreground_rect = infinite_rect;
target->Clipper(PaintLayer::kUseGeometryMapper)
.CalculateRects(root_context, target->GetLayoutObject().FirstFragment(),
infinite_rect, layer_bounds, background_rect,
foreground_rect);
// This includes the filter effect because it's applied before mapping the
// background rect to the root layer.
EXPECT_EQ(LayoutRect(38, 41, 204, 304), background_rect.Rect());
EXPECT_EQ(LayoutRect(90, 90, 100, 200), foreground_rect.Rect());
// Test mapping to the root layer without GeometryMapper.
background_rect = infinite_rect;
foreground_rect = infinite_rect;
target->Clipper(PaintLayer::kDoNotUseGeometryMapper)
.CalculateRects(root_context, nullptr, infinite_rect, layer_bounds,
background_rect, foreground_rect);
EXPECT_EQ(LayoutRect(38, 41, 204, 304), background_rect.Rect());
EXPECT_EQ(LayoutRect(90, 90, 100, 200), foreground_rect.Rect());
}
// Computed infinite clip rects may not match LayoutRect::InfiniteIntRect()
......
......@@ -628,7 +628,11 @@ void PaintPropertyTreeBuilder::UpdateEffect(
ColorFilter mask_color_filter;
bool has_mask = ComputeMaskParameters(
mask_clip, mask_color_filter, object, context.current.paint_offset);
if (has_mask) {
if (has_mask &&
// TODO(crbug.com/768691): Remove the following condition after mask
// clip doesn't fail fast/borders/inline-mask-overlay-image-outset-
// vertical-rl.html.
RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
FloatRoundedRect rounded_mask_clip(mask_clip);
if (properties.MaskClip() &&
rounded_mask_clip != properties.MaskClip()->ClipRect())
......@@ -648,8 +652,6 @@ void PaintPropertyTreeBuilder::UpdateEffect(
style.BlendMode())
: SkBlendMode::kSrcOver;
DCHECK(!style.HasCurrentOpacityAnimation() ||
compositing_reasons != kCompositingReasonNone);
auto result = properties.UpdateEffect(
context.current_effect, context.current.transform, output_clip,
kColorFilterNone, CompositorFilterOperations(), style.Opacity(),
......@@ -745,7 +747,8 @@ void PaintPropertyTreeBuilder::UpdateFilter(
kColorFilterNone, std::move(filter), 1.f, SkBlendMode::kSrcOver,
compositing_reasons,
CompositorElementIdFromUniqueObjectId(
object.UniqueId(), CompositorElementIdNamespace::kEffectFilter));
object.UniqueId(), CompositorElementIdNamespace::kEffectFilter),
FloatPoint(context.current.paint_offset));
force_subtree_update |= result.NewNodeCreated();
} else {
force_subtree_update |= properties.ClearFilter();
......@@ -1605,13 +1608,10 @@ void PaintPropertyTreeBuilder::UpdateFragmentPropertiesForSelf(
full_context.force_subtree_update);
UpdateCssClip(object, *properties, fragment_context,
full_context.force_subtree_update, full_context.clip_changed);
if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
UpdateEffect(object, *properties, fragment_context,
full_context.force_subtree_update,
full_context.clip_changed);
UpdateFilter(object, *properties, fragment_context,
full_context.force_subtree_update);
}
UpdateEffect(object, *properties, fragment_context,
full_context.force_subtree_update, full_context.clip_changed);
UpdateFilter(object, *properties, fragment_context,
full_context.force_subtree_update);
}
UpdateLocalBorderBoxContext(object, fragment_context, fragment_data,
full_context.force_subtree_update);
......
......@@ -3282,6 +3282,7 @@ TEST_P(PaintPropertyTreeBuilderTest, Reflection) {
EXPECT_EQ(FrameScrollTranslation(),
filter_properties->Filter()->LocalTransformSpace());
EXPECT_EQ(FrameContentClip(), filter_properties->Filter()->OutputClip());
EXPECT_EQ(FloatPoint(8, 8), filter_properties->Filter()->PaintOffset());
}
TEST_P(PaintPropertyTreeBuilderTest, SimpleFilter) {
......@@ -3294,6 +3295,7 @@ TEST_P(PaintPropertyTreeBuilderTest, SimpleFilter) {
EXPECT_EQ(FrameScrollTranslation(),
filter_properties->Filter()->LocalTransformSpace());
EXPECT_EQ(FrameContentClip(), filter_properties->Filter()->OutputClip());
EXPECT_EQ(FloatPoint(8, 8), filter_properties->Filter()->PaintOffset());
}
TEST_P(PaintPropertyTreeBuilderTest, FilterReparentClips) {
......@@ -3312,6 +3314,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FilterReparentClips) {
filter_properties->Filter()->LocalTransformSpace());
EXPECT_EQ(clip_properties->OverflowClip(),
filter_properties->Filter()->OutputClip());
EXPECT_EQ(FloatPoint(8, 8), filter_properties->Filter()->PaintOffset());
const PropertyTreeState& child_paint_state =
*GetLayoutObjectByElementId("child")
......
......@@ -96,6 +96,8 @@ class PLATFORM_EXPORT EffectPaintPropertyNode
return filter_.HasFilterThatMovesPixels();
}
FloatPoint PaintOffset() const { return paint_offset_; }
// Returns a rect covering the pixels that can be affected by pixels in
// |inputRect|. The rects are in the space of localTransformSpace.
FloatRect MapRect(const FloatRect& input_rect) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment