Commit 763e9101 authored by wangxianzhu's avatar wangxianzhu Committed by Commit bot

Revert of Don't pass subpixel offsets through non-translation transforms...

Revert of Don't pass subpixel offsets through non-translation transforms (patchset #7 id:120001 of https://codereview.chromium.org/2847873002/ )

Reason for revert:
BUG=717882

Original issue's description:
> Don't pass subpixel offsets through non-translation transforms
>
> Non-translation transforms will change direction and/or scale, etc.
> of offsets thus making subpixel accumulation through the transform
> meaningless.
>
> This CL addresses the issue in PaintLayerPainter and
> PaintPropertyTreeBuilder. We still need to address the issue in
> CompositedLayerMapping (crbug.com/716163).
>
> BUG=710665
> CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
>
> Review-Url: https://codereview.chromium.org/2847873002
> Cr-Commit-Position: refs/heads/master@{#468516}
> Committed: https://chromium.googlesource.com/chromium/src/+/098430b33423191b06dc32f13de764076cf60394

TBR=chrishtr@chromium.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=710665

Review-Url: https://codereview.chromium.org/2859483004
Cr-Commit-Position: refs/heads/master@{#469054}
parent e16cd144
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<head> <head>
<style> <style>
#list { #list {
width: 639px; width: 639px;
} }
.item { .item {
width: 256px; width: 256px;
...@@ -27,10 +27,9 @@ ...@@ -27,10 +27,9 @@
</style> </style>
</head> </head>
<body> <body>
<div id="list"> <div id="list">
<div class="item"> <div class="item"><img class="icon" style="transform: scaleX(-1);">
<img class="icon">
<div id="layer"></div> <div id="layer"></div>
</div> </div>
</div> </div>
</body> </body>
\ No newline at end of file
<!DOCTYPE html>
<style>
.container { position: relative; width: 0; height: 0; }
.scale { transform-origin: 0 0; transform: scale(40); }
.child { width: 1px; height: 1px; background: blue; position: relative; left: 0.4px }
</style>
<div class="container scale">
<div class="child"></div>
</div>
<div class="container" style="top: 50px">
<div class="child scale"></div>
</div>
<script src="resources/text-based-repaint.js"></script>
<script>
function repaintTest() {
for (var container of document.getElementsByClassName('container'))
container.style.left = '0.3px';
}
onload = runRepaintAndPixelTest;
</script>
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
}, },
{ {
"object": "LayoutText #text", "object": "LayoutText #text",
"rect": [23, 51, 72, 110], "rect": [23, 51, 71, 109],
"reason": "full" "reason": "full"
} }
] ]
......
...@@ -29,12 +29,12 @@ ...@@ -29,12 +29,12 @@
}, },
{ {
"object": "LayoutSVGRect rect id='rect'", "object": "LayoutSVGRect rect id='rect'",
"rect": [354, 127, 105, 102], "rect": [354, 127, 105, 103],
"reason": "full" "reason": "full"
}, },
{ {
"object": "LayoutSVGRect rect id='rect'", "object": "LayoutSVGRect rect id='rect'",
"rect": [111, 84, 101, 102], "rect": [110, 84, 103, 102],
"reason": "full" "reason": "full"
}, },
{ {
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
"object": "LayoutText #text", "object": "LayoutText #text",
"rect": [300, 302, 80, 177], "rect": [300, 302, 80, 177],
"reason": "subtree" "reason": "subtree"
},
{
"object": "LayoutText #text",
"rect": [151, 87, 1, 1],
"reason": "subtree"
} }
] ]
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
}, },
{ {
"object": "LayoutText #text", "object": "LayoutText #text",
"rect": [52, 51, 43, 32], "rect": [52, 51, 42, 31],
"reason": "full" "reason": "full"
} }
] ]
......
...@@ -29,12 +29,12 @@ ...@@ -29,12 +29,12 @@
}, },
{ {
"object": "LayoutSVGRect rect id='rect'", "object": "LayoutSVGRect rect id='rect'",
"rect": [354, 125, 105, 102], "rect": [354, 125, 105, 103],
"reason": "full" "reason": "full"
}, },
{ {
"object": "LayoutSVGRect rect id='rect'", "object": "LayoutSVGRect rect id='rect'",
"rect": [111, 82, 101, 102], "rect": [110, 82, 103, 102],
"reason": "full" "reason": "full"
}, },
{ {
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
"object": "LayoutInline (relative positioned) SPAN id='child'", "object": "LayoutInline (relative positioned) SPAN id='child'",
"rect": [300, 300, 80, 162], "rect": [300, 300, 80, 162],
"reason": "subtree" "reason": "subtree"
},
{
"object": "LayoutText #text",
"rect": [147, 85, 1, 1],
"reason": "subtree"
} }
] ]
} }
......
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"contentsOpaque": true,
"drawsContent": true,
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [22, 50, 226, 167],
"reason": "forced by layout"
},
{
"object": "LayoutText #text",
"rect": [23, 51, 70, 109],
"reason": "full"
}
]
}
],
"objectPaintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"reason": "forced by layout"
},
{
"object": "RootInlineBox",
"reason": "forced by layout"
},
{
"object": "LayoutText #text",
"reason": "full"
},
{
"object": "InlineTextBox 'PASS'",
"reason": "full"
}
]
}
...@@ -29,12 +29,12 @@ ...@@ -29,12 +29,12 @@
}, },
{ {
"object": "LayoutSVGRect rect id='rect'", "object": "LayoutSVGRect rect id='rect'",
"rect": [354, 127, 105, 102], "rect": [354, 127, 105, 103],
"reason": "full" "reason": "full"
}, },
{ {
"object": "LayoutSVGRect rect id='rect'", "object": "LayoutSVGRect rect id='rect'",
"rect": [111, 84, 101, 102], "rect": [110, 84, 103, 102],
"reason": "full" "reason": "full"
}, },
{ {
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
"object": "LayoutText #text", "object": "LayoutText #text",
"rect": [300, 301, 80, 178], "rect": [300, 301, 80, 178],
"reason": "subtree" "reason": "subtree"
},
{
"object": "LayoutText #text",
"rect": [151, 87, 1, 1],
"reason": "subtree"
} }
] ]
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
}, },
{ {
"object": "LayoutText #text", "object": "LayoutText #text",
"rect": [52, 51, 42, 31], "rect": [52, 51, 41, 31],
"reason": "full" "reason": "full"
} }
] ]
......
...@@ -7,23 +7,13 @@ ...@@ -7,23 +7,13 @@
"drawsContent": true, "drawsContent": true,
"paintInvalidations": [ "paintInvalidations": [
{ {
"object": "LayoutBlockFlow (relative positioned) DIV class='child'", "object": "LayoutBlockFlow (positioned) DIV id='target'",
"rect": [8, 8, 81, 40], "rect": [85, 70, 91, 91],
"reason": "bounds change" "reason": "bounds change"
}, },
{ {
"object": "LayoutBlockFlow (relative positioned) DIV class='child'", "object": "LayoutBlockFlow (positioned) DIV id='target'",
"rect": [8, 8, 80, 40], "rect": [84, 70, 91, 91],
"reason": "bounds change"
},
{
"object": "LayoutBlockFlow (relative positioned) DIV class='child scale'",
"rect": [8, 58, 41, 40],
"reason": "bounds change"
},
{
"object": "LayoutBlockFlow (relative positioned) DIV class='child scale'",
"rect": [8, 58, 41, 40],
"reason": "bounds change" "reason": "bounds change"
} }
] ]
...@@ -31,11 +21,7 @@ ...@@ -31,11 +21,7 @@
], ],
"objectPaintInvalidations": [ "objectPaintInvalidations": [
{ {
"object": "LayoutBlockFlow (relative positioned) DIV class='child'", "object": "LayoutBlockFlow (positioned) DIV id='target'",
"reason": "bounds change"
},
{
"object": "LayoutBlockFlow (relative positioned) DIV class='child scale'",
"reason": "bounds change" "reason": "bounds change"
} }
] ]
......
...@@ -1177,11 +1177,11 @@ bool LayoutBox::MapVisualRectToContainer( ...@@ -1177,11 +1177,11 @@ bool LayoutBox::MapVisualRectToContainer(
const LayoutObject* ancestor, const LayoutObject* ancestor,
VisualRectFlags visual_rect_flags, VisualRectFlags visual_rect_flags,
TransformState& transform_state) const { TransformState& transform_state) const {
bool container_preserve_3d = container_object->Style()->Preserves3D(); bool preserve3D = container_object->Style()->Preserves3D();
TransformState::TransformAccumulation accumulation = TransformState::TransformAccumulation accumulation =
container_preserve_3d ? TransformState::kAccumulateTransform preserve3D ? TransformState::kAccumulateTransform
: TransformState::kFlattenTransform; : TransformState::kFlattenTransform;
// If there is no transform on this box, adjust for container offset and // If there is no transform on this box, adjust for container offset and
// container scrolling, then apply container clip. // container scrolling, then apply container clip.
...@@ -1195,48 +1195,32 @@ bool LayoutBox::MapVisualRectToContainer( ...@@ -1195,48 +1195,32 @@ bool LayoutBox::MapVisualRectToContainer(
return true; return true;
} }
// Otherwise, do the following: // Otherwise, apply the following:
// 1. Expand for pixel snapping. // 1. Transform.
// 2. Generate transformation matrix combining, in this order // 2. Container offset.
// a) transform, // 3. Container scroll offset.
// b) container offset, // 4. Perspective applied by container.
// c) container scroll offset, // 5. Transform flattening.
// d) perspective applied by container. // 6. Expansion for pixel snapping.
// 3. Apply transform Transform+flattening. // 7. Container clip.
// 4. Apply container clip.
// 1. Expand for pixel snapping. // 1. Transform.
// Use EnclosingBoundingBox because we cannot properly compute pixel
// snapping for painted elements within the transform since we don't know
// the desired subpixel accumulation at this point, and the transform may
// include a scale. This only makes sense for non-preserve3D, and it's
// applicable only for SPv1 paint invalidation use cases when the slow-path
// is used to map visual rect/location.
if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() &&
!StyleRef().Preserves3D()) {
transform_state.Flatten();
transform_state.SetQuad(
FloatQuad(transform_state.LastPlanarQuad().EnclosingBoundingBox()));
}
// 2. Generate transformation matrix.
// a) Transform.
TransformationMatrix transform; TransformationMatrix transform;
if (Layer() && Layer()->Transform()) if (Layer() && Layer()->Transform())
transform.Multiply(Layer()->CurrentTransform()); transform.Multiply(Layer()->CurrentTransform());
// b) Container offset. // 2. Container offset.
transform.PostTranslate(container_offset.X().ToFloat(), transform.PostTranslate(container_offset.X().ToFloat(),
container_offset.Y().ToFloat()); container_offset.Y().ToFloat());
// c) Container scroll offset. // 3. Container scroll offset.
if (container_object->IsBox() && container_object != ancestor && if (container_object->IsBox() && container_object != ancestor &&
container_object->HasOverflowClip()) { container_object->HasOverflowClip()) {
IntSize offset = -ToLayoutBox(container_object)->ScrolledContentOffset(); IntSize offset = -ToLayoutBox(container_object)->ScrolledContentOffset();
transform.PostTranslate(offset.Width(), offset.Height()); transform.PostTranslate(offset.Width(), offset.Height());
} }
// d) Perspective applied by container. // 4. Perspective applied by container.
if (container_object && container_object->HasLayer() && if (container_object && container_object->HasLayer() &&
container_object->Style()->HasPerspective()) { container_object->Style()->HasPerspective()) {
// Perspective on the container affects us, so we have to factor it in here. // Perspective on the container affects us, so we have to factor it in here.
...@@ -1253,12 +1237,21 @@ bool LayoutBox::MapVisualRectToContainer( ...@@ -1253,12 +1237,21 @@ bool LayoutBox::MapVisualRectToContainer(
transform = perspective_matrix * transform; transform = perspective_matrix * transform;
} }
// 3. Apply transform and flatten. // 5. Transform flattening.
transform_state.ApplyTransform(transform, accumulation); transform_state.ApplyTransform(transform, accumulation);
if (!container_preserve_3d)
// 6. Expansion for pixel snapping.
// Use enclosingBoundingBox because we cannot properly compute pixel
// snapping for painted elements within the transform since we don't know
// the desired subpixel accumulation at this point, and the transform may
// include a scale.
if (!preserve3D) {
transform_state.Flatten(); transform_state.Flatten();
transform_state.SetQuad(
FloatQuad(transform_state.LastPlanarQuad().EnclosingBoundingBox()));
}
// 4. Apply container clip. // 7. Container clip.
if (container_object->IsBox() && container_object != ancestor && if (container_object->IsBox() && container_object != ancestor &&
container_object->HasClipRelatedProperty()) { container_object->HasClipRelatedProperty()) {
return ToLayoutBox(container_object) return ToLayoutBox(container_object)
......
...@@ -835,18 +835,10 @@ PaintResult PaintLayerPainter::PaintFragmentByApplyingTransform( ...@@ -835,18 +835,10 @@ PaintResult PaintLayerPainter::PaintFragmentByApplyingTransform(
delta.MoveBy(fragment_translation); delta.MoveBy(fragment_translation);
TransformationMatrix transform( TransformationMatrix transform(
paint_layer_.RenderableTransform(painting_info.GetGlobalPaintFlags())); paint_layer_.RenderableTransform(painting_info.GetGlobalPaintFlags()));
LayoutSize adjusted_sub_pixel_accumulation; IntPoint rounded_delta = RoundedIntPoint(delta);
if (transform.IsIdentityOrTranslation()) { transform.PostTranslate(rounded_delta.X(), rounded_delta.Y());
IntPoint rounded_delta = RoundedIntPoint(delta); LayoutSize adjusted_sub_pixel_accumulation =
transform.PostTranslate(rounded_delta.X(), rounded_delta.Y()); painting_info.sub_pixel_accumulation + (delta - rounded_delta);
adjusted_sub_pixel_accumulation =
painting_info.sub_pixel_accumulation + (delta - rounded_delta);
} else {
// We can't pass subpixel offsets through a non-translation transform.
// Bake the offsets into the transform instead.
delta += painting_info.sub_pixel_accumulation;
transform.PostTranslate(delta.X().ToDouble(), delta.Y().ToDouble());
}
// TODO(jbroman): Put the real transform origin here, instead of using a // TODO(jbroman): Put the real transform origin here, instead of using a
// matrix with the origin baked in. // matrix with the origin baked in.
......
...@@ -265,40 +265,26 @@ void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation( ...@@ -265,40 +265,26 @@ void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
// called "subpixel accumulation". For more information, see // called "subpixel accumulation". For more information, see
// PaintLayer::subpixelAccumulation() and // PaintLayer::subpixelAccumulation() and
// PaintLayerPainter::paintFragmentByApplyingTransform. // PaintLayerPainter::paintFragmentByApplyingTransform.
LayoutPoint used_paint_offset(context.current.paint_offset.X().Round(), IntPoint rounded_paint_offset =
context.current.paint_offset.Y().Round()); RoundedIntPoint(context.current.paint_offset);
LayoutPoint remainder_paint_offset = LayoutPoint fractional_paint_offset =
LayoutPoint(context.current.paint_offset - used_paint_offset); LayoutPoint(context.current.paint_offset - rounded_paint_offset);
if (remainder_paint_offset != LayoutPoint()) {
// However, if the object has a non-translation transform, we can't pass
// subpixel offsets through the transform to descendants.
TransformationMatrix matrix;
object.StyleRef().ApplyTransform(
matrix, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
ComputedStyle::kIncludeMotionPath,
ComputedStyle::kIncludeIndependentTransformProperties);
if (!matrix.IsIdentityOrTranslation()) {
remainder_paint_offset = LayoutPoint();
used_paint_offset = context.current.paint_offset;
}
}
force_subtree_update |= properties.UpdatePaintOffsetTranslation( force_subtree_update |= properties.UpdatePaintOffsetTranslation(
context.current.transform, context.current.transform,
TransformationMatrix().Translate(used_paint_offset.X().ToDouble(), TransformationMatrix().Translate(rounded_paint_offset.X(),
used_paint_offset.Y().ToDouble()), rounded_paint_offset.Y()),
FloatPoint3D(), context.current.should_flatten_inherited_transform, FloatPoint3D(), context.current.should_flatten_inherited_transform,
context.current.rendering_context_id); context.current.rendering_context_id);
context.current.transform = properties.PaintOffsetTranslation(); context.current.transform = properties.PaintOffsetTranslation();
context.current.paint_offset = remainder_paint_offset; context.current.paint_offset = fractional_paint_offset;
if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() && if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
object.IsLayoutView()) { object.IsLayoutView()) {
context.absolute_position.transform = properties.PaintOffsetTranslation(); context.absolute_position.transform = properties.PaintOffsetTranslation();
context.fixed_position.transform = properties.PaintOffsetTranslation(); context.fixed_position.transform = properties.PaintOffsetTranslation();
context.absolute_position.paint_offset = remainder_paint_offset; context.absolute_position.paint_offset = LayoutPoint();
context.fixed_position.paint_offset = remainder_paint_offset; context.fixed_position.paint_offset = LayoutPoint();
} }
} else { } else {
if (auto* properties = object.GetMutableForPainting().PaintProperties()) if (auto* properties = object.GetMutableForPainting().PaintProperties())
......
...@@ -1767,67 +1767,6 @@ TEST_P(PaintPropertyTreeBuilderTest, ...@@ -1767,67 +1767,6 @@ TEST_P(PaintPropertyTreeBuilderTest,
c, frame_view->GetLayoutView(), 1); c, frame_view->GetLayoutView(), 1);
} }
TEST_P(PaintPropertyTreeBuilderTest,
NonTranslationTransformShouldResetSubpixelPaintOffset) {
SetBodyInnerHTML(
"<style>"
" * { margin: 0; }"
" div { position: relative; }"
" #a {"
" width: 70px;"
" height: 70px;"
" left: 0.8px;"
" top: 0.8px;"
" }"
" #b {"
" width: 40px;"
" height: 40px;"
" transform: scale(10);"
" transform-origin: 0 0;"
" }"
" #c {"
" width: 40px;"
" height: 40px;"
" left: 0.6px;"
" top: 0.6px;"
" }"
"</style>"
"<div id='a'>"
" <div id='b'>"
" <div id='c'></div>"
" </div>"
"</div>");
FrameView* frame_view = GetDocument().View();
LayoutUnit a_offset = LayoutUnit(0.8);
LayoutUnit c_offset = LayoutUnit(0.6);
LayoutObject* b = GetDocument().getElementById("b")->GetLayoutObject();
const ObjectPaintProperties* b_properties = b->PaintProperties();
EXPECT_EQ(TransformationMatrix().Scale(10),
b_properties->Transform()->Matrix());
// The paint offset transform should not be snapped.
EXPECT_EQ(TransformationMatrix().Translate(a_offset.ToDouble(),
a_offset.ToDouble()),
b_properties->Transform()->Parent()->Matrix());
EXPECT_EQ(LayoutPoint(), b->PaintOffset());
CHECK_EXACT_VISUAL_RECT(
LayoutRect(a_offset, a_offset, LayoutUnit(400), LayoutUnit(400)), b,
frame_view->GetLayoutView());
// c's painting should start at c_offset.
LayoutObject* c = GetDocument().getElementById("c")->GetLayoutObject();
EXPECT_EQ(LayoutPoint(c_offset, c_offset), c->PaintOffset());
// Visual rects via the non-paint properties system use enclosingIntRect
// before applying transforms, because they are computed bottom-up and
// therefore can't apply pixel snapping. Therefore apply a slop of
// c_offset * 10 + 1px.
CHECK_VISUAL_RECT(
LayoutRect(c_offset * 10 + a_offset, c_offset * 10 + a_offset,
LayoutUnit(400), LayoutUnit(400)),
c, frame_view->GetLayoutView(), c_offset * 10 + 1);
}
TEST_P(PaintPropertyTreeBuilderTest, TEST_P(PaintPropertyTreeBuilderTest,
PaintOffsetWithPixelSnappingThroughMultipleTransforms) { PaintOffsetWithPixelSnappingThroughMultipleTransforms) {
SetBodyInnerHTML( SetBodyInnerHTML(
......
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