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

[PE] Properly handle subpixel accumulation across isolation

For pre-CompositeAfterPaint, we let subpixel accumulation propagate
through isolation to keep consistent with legacy compositing code.

For ComposteAfterPaint, we discard subpixel accumulation at
isolation.

Change-Id: Id9460dbb3c7c89931c38119e75f044b9079f3de8
Reviewed-on: https://chromium-review.googlesource.com/c/1488020Reviewed-by: default avatarvmpstr <vmpstr@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636642}
parent c13e7606
...@@ -443,28 +443,34 @@ void FragmentPaintPropertyTreeBuilder::UpdateForPaintOffsetTranslation( ...@@ -443,28 +443,34 @@ void FragmentPaintPropertyTreeBuilder::UpdateForPaintOffsetTranslation(
full_context_.direct_compositing_reasons)) full_context_.direct_compositing_reasons))
return; return;
// We should use the same subpixel paint offset values for snapping // We should use the same subpixel paint offset values for snapping regardless
// regardless of whether a transform is present. If there is a transform // of paint offset translation. If we create a paint offset translation we
// we round the paint offset but keep around the residual fractional // round the paint offset but keep around the residual fractional component
// component for the transformed content to paint with. In spv1 this was // (i.e. subpixel accumulation) for the transformed content to paint with.
// called "subpixel accumulation". For more information, see // In pre-CompositeAfterPaint, if the object has layer, this corresponds to
// PaintLayer::subpixelAccumulation() and // PaintLayer::SubpixelAccumulation().
// PaintLayerPainter::paintFragmentByApplyingTransform.
paint_offset_translation = RoundedIntPoint(context_.current.paint_offset); paint_offset_translation = RoundedIntPoint(context_.current.paint_offset);
LayoutPoint fractional_paint_offset = LayoutPoint subpixel_accumulation;
LayoutPoint(context_.current.paint_offset - *paint_offset_translation); // Don't propagate subpixel accumulation through paint isolation. In
if (fractional_paint_offset != LayoutPoint()) { // pre-CompositeAfterPaint we still need to keep consistence with the legacy
// If the object has a non-translation transform, discard the fractional // compositing code.
// paint offset which can't be transformed by the transform. if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
TransformationMatrix matrix; !NeedsIsolationNodes(object_)) {
object_.StyleRef().ApplyTransform( subpixel_accumulation =
matrix, LayoutSize(), ComputedStyle::kExcludeTransformOrigin, LayoutPoint(context_.current.paint_offset - *paint_offset_translation);
ComputedStyle::kIncludeMotionPath, if (subpixel_accumulation != LayoutPoint()) {
ComputedStyle::kIncludeIndependentTransformProperties); // If the object has a non-translation transform, discard the fractional
if (!matrix.IsIdentityOrTranslation()) // paint offset which can't be transformed by the transform.
fractional_paint_offset = LayoutPoint(); TransformationMatrix matrix;
} object_.StyleRef().ApplyTransform(
context_.current.paint_offset = fractional_paint_offset; matrix, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
if (!matrix.IsIdentityOrTranslation())
subpixel_accumulation = LayoutPoint();
}
}
context_.current.paint_offset = subpixel_accumulation;
} }
void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation( void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
...@@ -2220,12 +2226,21 @@ void FragmentPaintPropertyTreeBuilder::UpdateForObjectLocationAndSize( ...@@ -2220,12 +2226,21 @@ void FragmentPaintPropertyTreeBuilder::UpdateForObjectLocationAndSize(
UpdatePaintOffset(); UpdatePaintOffset();
UpdateForPaintOffsetTranslation(paint_offset_translation); UpdateForPaintOffsetTranslation(paint_offset_translation);
if (fragment_data_.PaintOffset() != context_.current.paint_offset) { LayoutSize paint_offset_delta =
fragment_data_.PaintOffset() - context_.current.paint_offset;
if (!paint_offset_delta.IsZero()) {
// Many paint properties depend on paint offset so we force an update of // Many paint properties depend on paint offset so we force an update of
// the entire subtree on paint offset changes. // the entire subtree on paint offset changes. However, they are blocked by
// However, they are blocked by isolation. // isolation if subpixel accumulation doesn't change or CompositeAfterPaint
full_context_.force_subtree_update_reasons |= // is enabled.
PaintPropertyTreeBuilderContext::kSubtreeUpdateIsolationBlocked; if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
paint_offset_delta == RoundedIntSize(paint_offset_delta)) {
full_context_.force_subtree_update_reasons |=
PaintPropertyTreeBuilderContext::kSubtreeUpdateIsolationBlocked;
} else {
full_context_.force_subtree_update_reasons |=
PaintPropertyTreeBuilderContext::kSubtreeUpdateIsolationPiercing;
}
object_.GetMutableForPainting().SetShouldCheckForPaintInvalidation(); object_.GetMutableForPainting().SetShouldCheckForPaintInvalidation();
fragment_data_.SetPaintOffset(context_.current.paint_offset); fragment_data_.SetPaintOffset(context_.current.paint_offset);
......
...@@ -1578,4 +1578,45 @@ TEST_P(PaintPropertyTreeUpdateTest, ChangingClipPath) { ...@@ -1578,4 +1578,45 @@ TEST_P(PaintPropertyTreeUpdateTest, ChangingClipPath) {
// Pass if no crash. // Pass if no crash.
} }
TEST_P(PaintPropertyTreeUpdateTest, SubpixelAccumulationAcrossIsolation) {
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0 }</style>
<div id="parent" style="margin-left: 10.25px">
<div id="isolation" style="contain: paint">
<div id="child"><div>
</div>
</div>
)HTML");
auto* parent_element = GetDocument().getElementById("parent");
auto* parent = parent_element->GetLayoutObject();
auto* isolation_properties = PaintPropertiesForElement("isolation");
auto* child = GetLayoutObjectByElementId("child");
EXPECT_EQ(LayoutPoint(LayoutUnit(10.25), LayoutUnit()),
parent->FirstFragment().PaintOffset());
EXPECT_EQ(FloatSize(10, 0), isolation_properties->PaintOffsetTranslation()
->Matrix()
.To2DTranslation());
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(LayoutPoint(), child->FirstFragment().PaintOffset());
} else {
EXPECT_EQ(LayoutPoint(LayoutUnit(0.25), LayoutUnit()),
child->FirstFragment().PaintOffset());
}
parent_element->setAttribute(html_names::kStyleAttr, "margin-left: 12.75px");
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(LayoutPoint(LayoutUnit(12.75), LayoutUnit()),
parent->FirstFragment().PaintOffset());
EXPECT_EQ(FloatSize(13, 0), isolation_properties->PaintOffsetTranslation()
->Matrix()
.To2DTranslation());
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_EQ(LayoutPoint(), child->FirstFragment().PaintOffset());
} else {
EXPECT_EQ(LayoutPoint(LayoutUnit(-0.25), LayoutUnit()),
child->FirstFragment().PaintOffset());
}
}
} // namespace blink } // namespace blink
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