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(
full_context_.direct_compositing_reasons))
return;
// We should use the same subpixel paint offset values for snapping
// regardless of whether a transform is present. If there is a transform
// we round the paint offset but keep around the residual fractional
// component for the transformed content to paint with. In spv1 this was
// called "subpixel accumulation". For more information, see
// PaintLayer::subpixelAccumulation() and
// PaintLayerPainter::paintFragmentByApplyingTransform.
// We should use the same subpixel paint offset values for snapping regardless
// of paint offset translation. If we create a paint offset translation we
// round the paint offset but keep around the residual fractional component
// (i.e. subpixel accumulation) for the transformed content to paint with.
// In pre-CompositeAfterPaint, if the object has layer, this corresponds to
// PaintLayer::SubpixelAccumulation().
paint_offset_translation = RoundedIntPoint(context_.current.paint_offset);
LayoutPoint fractional_paint_offset =
LayoutPoint(context_.current.paint_offset - *paint_offset_translation);
if (fractional_paint_offset != LayoutPoint()) {
// If the object has a non-translation transform, discard the fractional
// paint offset which can't be transformed by the transform.
TransformationMatrix matrix;
object_.StyleRef().ApplyTransform(
matrix, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
if (!matrix.IsIdentityOrTranslation())
fractional_paint_offset = LayoutPoint();
}
context_.current.paint_offset = fractional_paint_offset;
LayoutPoint subpixel_accumulation;
// Don't propagate subpixel accumulation through paint isolation. In
// pre-CompositeAfterPaint we still need to keep consistence with the legacy
// compositing code.
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
!NeedsIsolationNodes(object_)) {
subpixel_accumulation =
LayoutPoint(context_.current.paint_offset - *paint_offset_translation);
if (subpixel_accumulation != LayoutPoint()) {
// If the object has a non-translation transform, discard the fractional
// paint offset which can't be transformed by the transform.
TransformationMatrix matrix;
object_.StyleRef().ApplyTransform(
matrix, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
if (!matrix.IsIdentityOrTranslation())
subpixel_accumulation = LayoutPoint();
}
}
context_.current.paint_offset = subpixel_accumulation;
}
void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
......@@ -2220,12 +2226,21 @@ void FragmentPaintPropertyTreeBuilder::UpdateForObjectLocationAndSize(
UpdatePaintOffset();
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
// the entire subtree on paint offset changes.
// However, they are blocked by isolation.
full_context_.force_subtree_update_reasons |=
PaintPropertyTreeBuilderContext::kSubtreeUpdateIsolationBlocked;
// the entire subtree on paint offset changes. However, they are blocked by
// isolation if subpixel accumulation doesn't change or CompositeAfterPaint
// is enabled.
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();
fragment_data_.SetPaintOffset(context_.current.paint_offset);
......
......@@ -1578,4 +1578,45 @@ TEST_P(PaintPropertyTreeUpdateTest, ChangingClipPath) {
// 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
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