Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp

Issue 1774193002: New paint invalidation using paint property tree walk (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/layout/LayoutTestHelper.h"
6 #include "core/layout/LayoutTreeAsText.h"
7 #include "core/layout/LayoutView.h"
8 #include "core/paint/ObjectPaintProperties.h"
9 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
10 #include "platform/testing/UnitTestHelpers.h"
11 #include "platform/text/TextStream.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "wtf/HashMap.h"
14 #include "wtf/Vector.h"
15
16 namespace blink {
17
18 class PaintPropertyTreeBuilderTest : public RenderingTest {
19 public:
20 PaintPropertyTreeBuilderTest()
21 : RenderingTest(SingleChildFrameLoaderClient::create())
22 , m_originalSlimmingPaintV2Enabled(RuntimeEnabledFeatures::slimmingPaint V2Enabled()) { }
23
24 void loadTestData(const char* fileName)
25 {
26 String fullPath = testing::blinkRootDir();
27 fullPath.append("/Source/core/paint/test_data/");
28 fullPath.append(fileName);
29 RefPtr<SharedBuffer> inputBuffer = testing::readFromFile(fullPath);
30 setBodyInnerHTML(String(inputBuffer->data(), inputBuffer->size()));
31 }
32
33 private:
34 void SetUp() override
35 {
36 RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
37 Settings::setMockScrollbarsEnabled(true);
38
39 RenderingTest::SetUp();
40 enableCompositing();
41 }
42
43 void TearDown() override
44 {
45 RenderingTest::TearDown();
46
47 Settings::setMockScrollbarsEnabled(false);
48 RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(m_originalSlimmingPain tV2Enabled);
49 }
50
51 bool m_originalSlimmingPaintV2Enabled;
52 };
53
54 TEST_F(PaintPropertyTreeBuilderTest, FixedPosition)
55 {
56 loadTestData("fixed-position.html");
57
58 FrameView* frameView = document().view();
59
60 // target1 is a fixed-position element inside an absolute-position scrolling element.
61 // It should be attached under the viewport to skip scrolling and offset of the parent.
62 Element* target1 = document().getElementById("target1");
63 ObjectPaintProperties* target1Properties = target1->layoutObject()->objectPa intProperties();
64 EXPECT_EQ(TransformationMatrix().translate(200, 150), target1Properties->pai ntOffsetTranslation()->matrix());
65 EXPECT_EQ(frameView->preTranslation(), target1Properties->paintOffsetTransla tion()->parent());
66 EXPECT_EQ(target1Properties->paintOffsetTranslation(), target1Properties->ov erflowClip()->localTransformSpace());
67 EXPECT_EQ(FloatRoundedRect(0, 0, 100, 100), target1Properties->overflowClip( )->clipRect());
68 // Likewise, it inherits clip from the viewport, skipping overflow clip of t he scroller.
69 EXPECT_EQ(frameView->contentClip(), target1Properties->overflowClip()->paren t());
70
71 // target2 is a fixed-position element inside a transformed scrolling elemen t.
72 // It should be attached under the scrolled box of the transformed element.
73 Element* target2 = document().getElementById("target2");
74 ObjectPaintProperties* target2Properties = target2->layoutObject()->objectPa intProperties();
75 Element* scroller = document().getElementById("scroller");
76 ObjectPaintProperties* scrollerProperties = scroller->layoutObject()->object PaintProperties();
77 EXPECT_EQ(TransformationMatrix().translate(200, 150), target2Properties->pai ntOffsetTranslation()->matrix());
78 EXPECT_EQ(scrollerProperties->scrollTranslation(), target2Properties->paintO ffsetTranslation()->parent());
79 EXPECT_EQ(target2Properties->paintOffsetTranslation(), target2Properties->ov erflowClip()->localTransformSpace());
80 EXPECT_EQ(FloatRoundedRect(0, 0, 100, 100), target2Properties->overflowClip( )->clipRect());
81 EXPECT_EQ(scrollerProperties->overflowClip(), target2Properties->overflowCli p()->parent());
82 }
83
84 TEST_F(PaintPropertyTreeBuilderTest, PositionAndScroll)
85 {
86 loadTestData("position-and-scroll.html");
87
88 Element* scroller = document().getElementById("scroller");
89 scroller->scrollTo(0, 100);
90 FrameView* frameView = document().view();
91 frameView->updateAllLifecyclePhases();
92 ObjectPaintProperties* scrollerProperties = scroller->layoutObject()->object PaintProperties();
93 EXPECT_EQ(TransformationMatrix().translate(0, -100), scrollerProperties->scr ollTranslation()->matrix());
94 EXPECT_EQ(frameView->scrollTranslation(), scrollerProperties->scrollTranslat ion()->parent());
95 EXPECT_EQ(frameView->scrollTranslation(), scrollerProperties->overflowClip() ->localTransformSpace());
96 EXPECT_EQ(FloatRoundedRect(120, 340, 400, 300), scrollerProperties->overflow Clip()->clipRect());
97 EXPECT_EQ(frameView->contentClip(), scrollerProperties->overflowClip()->pare nt());
98
99 // The relative-positioned element should have accumulated box offset (exclu de scrolling),
100 // and should be affected by ancestor scroll transforms.
101 Element* relPos = document().getElementById("rel-pos");
102 ObjectPaintProperties* relPosProperties = relPos->layoutObject()->objectPain tProperties();
103 EXPECT_EQ(TransformationMatrix().translate(680, 1120), relPosProperties->pai ntOffsetTranslation()->matrix());
104 EXPECT_EQ(scrollerProperties->scrollTranslation(), relPosProperties->paintOf fsetTranslation()->parent());
105 EXPECT_EQ(relPosProperties->transform(), relPosProperties->overflowClip()->l ocalTransformSpace());
106 EXPECT_EQ(FloatRoundedRect(0, 0, 400, 0), relPosProperties->overflowClip()-> clipRect());
107 EXPECT_EQ(scrollerProperties->overflowClip(), relPosProperties->overflowClip ()->parent());
108
109 // The absolute-positioned element should not be affected by non-positioned scroller at all.
110 Element* absPos = document().getElementById("abs-pos");
111 ObjectPaintProperties* absPosProperties = absPos->layoutObject()->objectPain tProperties();
112 EXPECT_EQ(TransformationMatrix().translate(123, 456), absPosProperties->pain tOffsetTranslation()->matrix());
113 EXPECT_EQ(frameView->scrollTranslation(), absPosProperties->paintOffsetTrans lation()->parent());
114 EXPECT_EQ(absPosProperties->transform(), absPosProperties->overflowClip()->l ocalTransformSpace());
115 EXPECT_EQ(FloatRoundedRect(), absPosProperties->overflowClip()->clipRect());
116 EXPECT_EQ(frameView->contentClip(), absPosProperties->overflowClip()->parent ());
117 }
118
119 TEST_F(PaintPropertyTreeBuilderTest, FrameScrollingTraditional)
120 {
121 setBodyInnerHTML("<style> body { height: 10000px; } </style>");
122
123 document().domWindow()->scrollTo(0, 100);
124
125 FrameView* frameView = document().view();
126 frameView->updateAllLifecyclePhases();
127 EXPECT_EQ(TransformationMatrix(), frameView->preTranslation()->matrix());
128 EXPECT_EQ(nullptr, frameView->preTranslation()->parent());
129 EXPECT_EQ(TransformationMatrix().translate(0, -100), frameView->scrollTransl ation()->matrix());
130 EXPECT_EQ(frameView->preTranslation(), frameView->scrollTranslation()->paren t());
131 EXPECT_EQ(frameView->preTranslation(), frameView->contentClip()->localTransf ormSpace());
132 EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameView->contentClip()->clipRe ct());
133 EXPECT_EQ(nullptr, frameView->contentClip()->parent());
134
135 LayoutView* layoutView = document().layoutView();
136 ObjectPaintProperties* layoutViewProperties = layoutView->objectPaintPropert ies();
137 EXPECT_EQ(nullptr, layoutViewProperties->scrollTranslation());
138 }
139
140 // TODO(trchen): Settings::rootLayerScrolls cannot be switched after main frame being created.
141 // Need to set it during test setup. Besides that, the test still won't work bec ause
142 // root layer scrolling mode is not compatible with SPv2 at this moment.
143 // (Duplicate display item ID for FrameView and LayoutView.)
144 TEST_F(PaintPropertyTreeBuilderTest, DISABLED_FrameScrollingRootLayerScrolls)
145 {
146 document().settings()->setRootLayerScrolls(true);
147
148 setBodyInnerHTML("<style> body { height: 10000px; } </style>");
149
150 document().domWindow()->scrollTo(0, 100);
151
152 FrameView* frameView = document().view();
153 frameView->updateAllLifecyclePhases();
154 EXPECT_EQ(TransformationMatrix(), frameView->preTranslation()->matrix());
155 EXPECT_EQ(nullptr, frameView->preTranslation()->parent());
156 EXPECT_EQ(TransformationMatrix(), frameView->scrollTranslation()->matrix());
157 EXPECT_EQ(frameView->preTranslation(), frameView->scrollTranslation()->paren t());
158
159 LayoutView* layoutView = document().layoutView();
160 ObjectPaintProperties* layoutViewProperties = layoutView->objectPaintPropert ies();
161 EXPECT_EQ(TransformationMatrix().translate(0, -100), layoutViewProperties->s crollTranslation()->matrix());
162 EXPECT_EQ(frameView->scrollTranslation(), layoutViewProperties->scrollTransl ation()->parent());
163 }
164
165 TEST_F(PaintPropertyTreeBuilderTest, Perspective)
166 {
167 loadTestData("perspective.html");
168
169 Element* perspective = document().getElementById("perspective");
170 ObjectPaintProperties* perspectiveProperties = perspective->layoutObject()-> objectPaintProperties();
171 EXPECT_EQ(TransformationMatrix().applyPerspective(100), perspectivePropertie s->perspective()->matrix());
172 // The perspective origin is the center of the border box plus accumulated p aint offset.
173 EXPECT_EQ(FloatPoint3D(250, 250, 0), perspectiveProperties->perspective()->o rigin());
174 EXPECT_EQ(document().view()->scrollTranslation(), perspectiveProperties->per spective()->parent());
175
176 // Adding perspective doesn't clear paint offset. The paint offset will be p assed down to children.
177 Element* inner = document().getElementById("inner");
178 ObjectPaintProperties* innerProperties = inner->layoutObject()->objectPaintP roperties();
179 EXPECT_EQ(TransformationMatrix().translate(50, 100), innerProperties->paintO ffsetTranslation()->matrix());
180 EXPECT_EQ(perspectiveProperties->perspective(), innerProperties->paintOffset Translation()->parent());
181 }
182
183 TEST_F(PaintPropertyTreeBuilderTest, Transform)
184 {
185 loadTestData("transform.html");
186
187 Element* transform = document().getElementById("transform");
188 ObjectPaintProperties* transformProperties = transform->layoutObject()->obje ctPaintProperties();
189 EXPECT_EQ(TransformationMatrix().translate3d(123, 456, 789), transformProper ties->transform()->matrix());
190 EXPECT_EQ(FloatPoint3D(200, 150, 0), transformProperties->transform()->origi n());
191 EXPECT_EQ(transformProperties->paintOffsetTranslation(), transformProperties ->transform()->parent());
192 EXPECT_EQ(TransformationMatrix().translate(50, 100), transformProperties->pa intOffsetTranslation()->matrix());
193 EXPECT_EQ(document().view()->scrollTranslation(), transformProperties->paint OffsetTranslation()->parent());
194 }
195
196 TEST_F(PaintPropertyTreeBuilderTest, RelativePositionInline)
197 {
198 loadTestData("relative-position-inline.html");
199
200 Element* inlineBlock = document().getElementById("inline-block");
201 ObjectPaintProperties* inlineBlockProperties = inlineBlock->layoutObject()-> objectPaintProperties();
202 EXPECT_EQ(TransformationMatrix().translate(135, 490), inlineBlockProperties- >paintOffsetTranslation()->matrix());
203 EXPECT_EQ(document().view()->scrollTranslation(), inlineBlockProperties->pai ntOffsetTranslation()->parent());
204 }
205
206 TEST_F(PaintPropertyTreeBuilderTest, NestedOpacityEffect)
207 {
208 setBodyInnerHTML(
209 "<div id='nodeWithoutOpacity'>"
210 " <div id='childWithOpacity' style='opacity: 0.5'>"
211 " <div id='grandChildWithoutOpacity'>"
212 " <div id='greatGrandChildWithOpacity' style='opacity: 0.2'/>"
213 " </div>"
214 " </div>"
215 "</div>");
216
217 LayoutObject& nodeWithoutOpacity = *document().getElementById("nodeWithoutOp acity")->layoutObject();
218 ObjectPaintProperties* nodeWithoutOpacityProperties = nodeWithoutOpacity.obj ectPaintProperties();
219 EXPECT_EQ(nullptr, nodeWithoutOpacityProperties);
220
221 LayoutObject& childWithOpacity = *document().getElementById("childWithOpacit y")->layoutObject();
222 ObjectPaintProperties* childWithOpacityProperties = childWithOpacity.objectP aintProperties();
223 EXPECT_EQ(0.5f, childWithOpacityProperties->effect()->opacity());
224 // childWithOpacity is the root effect node.
225 EXPECT_EQ(nullptr, childWithOpacityProperties->effect()->parent());
226
227 LayoutObject& grandChildWithoutOpacity = *document().getElementById("grandCh ildWithoutOpacity")->layoutObject();
228 EXPECT_EQ(nullptr, grandChildWithoutOpacity.objectPaintProperties());
229
230 LayoutObject& greatGrandChildWithOpacity = *document().getElementById("great GrandChildWithOpacity")->layoutObject();
231 ObjectPaintProperties* greatGrandChildWithOpacityProperties = greatGrandChil dWithOpacity.objectPaintProperties();
232 EXPECT_EQ(0.2f, greatGrandChildWithOpacityProperties->effect()->opacity());
233 EXPECT_EQ(childWithOpacityProperties->effect(), greatGrandChildWithOpacityPr operties->effect()->parent());
234 }
235
236 TEST_F(PaintPropertyTreeBuilderTest, TransformNodeDoesNotAffectEffectNodes)
237 {
238 setBodyInnerHTML(
239 "<div id='nodeWithOpacity' style='opacity: 0.6'>"
240 " <div id='childWithTransform' style='transform: translate3d(10px, 10px , 0px);'>"
241 " <div id='grandChildWithOpacity' style='opacity: 0.4'/>"
242 " </div>"
243 "</div>");
244
245 LayoutObject& nodeWithOpacity = *document().getElementById("nodeWithOpacity" )->layoutObject();
246 ObjectPaintProperties* nodeWithOpacityProperties = nodeWithOpacity.objectPai ntProperties();
247 EXPECT_EQ(0.6f, nodeWithOpacityProperties->effect()->opacity());
248 EXPECT_EQ(nullptr, nodeWithOpacityProperties->effect()->parent());
249 EXPECT_EQ(nullptr, nodeWithOpacityProperties->transform());
250
251 LayoutObject& childWithTransform = *document().getElementById("childWithTran sform")->layoutObject();
252 ObjectPaintProperties* childWithTransformProperties = childWithTransform.obj ectPaintProperties();
253 EXPECT_EQ(nullptr, childWithTransformProperties->effect());
254 EXPECT_EQ(TransformationMatrix().translate(10, 10), childWithTransformProper ties->transform()->matrix());
255
256 LayoutObject& grandChildWithOpacity = *document().getElementById("grandChild WithOpacity")->layoutObject();
257 ObjectPaintProperties* grandChildWithOpacityProperties = grandChildWithOpaci ty.objectPaintProperties();
258 EXPECT_EQ(0.4f, grandChildWithOpacityProperties->effect()->opacity());
259 EXPECT_EQ(nodeWithOpacityProperties->effect(), grandChildWithOpacityProperti es->effect()->parent());
260 EXPECT_EQ(nullptr, grandChildWithOpacityProperties->transform());
261 }
262
263 TEST_F(PaintPropertyTreeBuilderTest, EffectNodesAcrossStackingContext)
264 {
265 setBodyInnerHTML(
266 "<div id='nodeWithOpacity' style='opacity: 0.6'>"
267 " <div id='childWithStackingContext' style='position:absolute;'>"
268 " <div id='grandChildWithOpacity' style='opacity: 0.4'/>"
269 " </div>"
270 "</div>");
271
272 LayoutObject& nodeWithOpacity = *document().getElementById("nodeWithOpacity" )->layoutObject();
273 ObjectPaintProperties* nodeWithOpacityProperties = nodeWithOpacity.objectPai ntProperties();
274 EXPECT_EQ(0.6f, nodeWithOpacityProperties->effect()->opacity());
275 EXPECT_EQ(nullptr, nodeWithOpacityProperties->effect()->parent());
276 EXPECT_EQ(nullptr, nodeWithOpacityProperties->transform());
277
278 LayoutObject& childWithStackingContext = *document().getElementById("childWi thStackingContext")->layoutObject();
279 ObjectPaintProperties* childWithStackingContextProperties = childWithStackin gContext.objectPaintProperties();
280 EXPECT_EQ(nullptr, childWithStackingContextProperties->effect());
281 EXPECT_EQ(nullptr, childWithStackingContextProperties->transform());
282
283 LayoutObject& grandChildWithOpacity = *document().getElementById("grandChild WithOpacity")->layoutObject();
284 ObjectPaintProperties* grandChildWithOpacityProperties = grandChildWithOpaci ty.objectPaintProperties();
285 EXPECT_EQ(0.4f, grandChildWithOpacityProperties->effect()->opacity());
286 EXPECT_EQ(nodeWithOpacityProperties->effect(), grandChildWithOpacityProperti es->effect()->parent());
287 EXPECT_EQ(nullptr, grandChildWithOpacityProperties->transform());
288 }
289
290 TEST_F(PaintPropertyTreeBuilderTest, EffectNodesInSVG)
291 {
292 setBodyInnerHTML(
293 "<svg id='svgRoot'>"
294 " <g id='groupWithOpacity' opacity='0.6'>"
295 " <rect id='rectWithoutOpacity' />"
296 " <rect id='rectWithOpacity' opacity='0.4' />"
297 " <text id='textWithOpacity' opacity='0.2'>"
298 " <tspan id='tspanWithOpacity' opacity='0.1' />"
299 " </text>"
300 " </g>"
301 "</svg>");
302
303 LayoutObject& groupWithOpacity = *document().getElementById("groupWithOpacit y")->layoutObject();
304 ObjectPaintProperties* groupWithOpacityProperties = groupWithOpacity.objectP aintProperties();
305 EXPECT_EQ(0.6f, groupWithOpacityProperties->effect()->opacity());
306 EXPECT_EQ(nullptr, groupWithOpacityProperties->effect()->parent());
307
308 LayoutObject& rectWithoutOpacity = *document().getElementById("rectWithoutOp acity")->layoutObject();
309 ObjectPaintProperties* rectWithoutOpacityProperties = rectWithoutOpacity.obj ectPaintProperties();
310 EXPECT_EQ(nullptr, rectWithoutOpacityProperties);
311
312 LayoutObject& rectWithOpacity = *document().getElementById("rectWithOpacity" )->layoutObject();
313 ObjectPaintProperties* rectWithOpacityProperties = rectWithOpacity.objectPai ntProperties();
314 EXPECT_EQ(0.4f, rectWithOpacityProperties->effect()->opacity());
315 EXPECT_EQ(groupWithOpacityProperties->effect(), rectWithOpacityProperties->e ffect()->parent());
316
317 // Ensure that opacity nodes are created for LayoutSVGText which inherits fr om LayoutSVGBlock instead of LayoutSVGModelObject.
318 LayoutObject& textWithOpacity = *document().getElementById("textWithOpacity" )->layoutObject();
319 ObjectPaintProperties* textWithOpacityProperties = textWithOpacity.objectPai ntProperties();
320 EXPECT_EQ(0.2f, textWithOpacityProperties->effect()->opacity());
321 EXPECT_EQ(groupWithOpacityProperties->effect(), textWithOpacityProperties->e ffect()->parent());
322
323 // Ensure that opacity nodes are created for LayoutSVGTSpan which inherits f rom LayoutSVGInline instead of LayoutSVGModelObject.
324 LayoutObject& tspanWithOpacity = *document().getElementById("tspanWithOpacit y")->layoutObject();
325 ObjectPaintProperties* tspanWithOpacityProperties = tspanWithOpacity.objectP aintProperties();
326 EXPECT_EQ(0.1f, tspanWithOpacityProperties->effect()->opacity());
327 EXPECT_EQ(textWithOpacityProperties->effect(), tspanWithOpacityProperties->e ffect()->parent());
328 }
329
330 TEST_F(PaintPropertyTreeBuilderTest, EffectNodesAcrossHTMLSVGBoundary)
331 {
332 setBodyInnerHTML(
333 "<div id='divWithOpacity' style='opacity: 0.2;'>"
334 " <svg id='svgRootWithOpacity' style='opacity: 0.3;'>"
335 " <rect id='rectWithOpacity' opacity='0.4' />"
336 " </svg>"
337 "</div>");
338
339 LayoutObject& divWithOpacity = *document().getElementById("divWithOpacity")- >layoutObject();
340 ObjectPaintProperties* divWithOpacityProperties = divWithOpacity.objectPaint Properties();
341 EXPECT_EQ(0.2f, divWithOpacityProperties->effect()->opacity());
342 EXPECT_EQ(nullptr, divWithOpacityProperties->effect()->parent());
343
344 LayoutObject& svgRootWithOpacity = *document().getElementById("svgRootWithOp acity")->layoutObject();
345 ObjectPaintProperties* svgRootWithOpacityProperties = svgRootWithOpacity.obj ectPaintProperties();
346 EXPECT_EQ(0.3f, svgRootWithOpacityProperties->effect()->opacity());
347 EXPECT_EQ(divWithOpacityProperties->effect(), svgRootWithOpacityProperties-> effect()->parent());
348
349 LayoutObject& rectWithOpacity = *document().getElementById("rectWithOpacity" )->layoutObject();
350 ObjectPaintProperties* rectWithOpacityProperties = rectWithOpacity.objectPai ntProperties();
351 EXPECT_EQ(0.4f, rectWithOpacityProperties->effect()->opacity());
352 EXPECT_EQ(svgRootWithOpacityProperties->effect(), rectWithOpacityProperties- >effect()->parent());
353 }
354
355 TEST_F(PaintPropertyTreeBuilderTest, EffectNodesAcrossSVGHTMLBoundary)
356 {
357 setBodyInnerHTML(
358 "<svg id='svgRootWithOpacity' style='opacity: 0.3;'>"
359 " <foreignObject id='foreignObjectWithOpacity' opacity='0.4'>"
360 " <body>"
361 " <span id='spanWithOpacity' style='opacity: 0.5'/>"
362 " </body>"
363 " </foreignObject>"
364 "</svg>");
365
366 LayoutObject& svgRootWithOpacity = *document().getElementById("svgRootWithOp acity")->layoutObject();
367 ObjectPaintProperties* svgRootWithOpacityProperties = svgRootWithOpacity.obj ectPaintProperties();
368 EXPECT_EQ(0.3f, svgRootWithOpacityProperties->effect()->opacity());
369 EXPECT_EQ(nullptr, svgRootWithOpacityProperties->effect()->parent());
370
371 LayoutObject& foreignObjectWithOpacity = *document().getElementById("foreign ObjectWithOpacity")->layoutObject();
372 ObjectPaintProperties* foreignObjectWithOpacityProperties = foreignObjectWit hOpacity.objectPaintProperties();
373 EXPECT_EQ(0.4f, foreignObjectWithOpacityProperties->effect()->opacity());
374 EXPECT_EQ(svgRootWithOpacityProperties->effect(), foreignObjectWithOpacityPr operties->effect()->parent());
375
376 LayoutObject& spanWithOpacity = *document().getElementById("spanWithOpacity" )->layoutObject();
377 ObjectPaintProperties* spanWithOpacityProperties = spanWithOpacity.objectPai ntProperties();
378 EXPECT_EQ(0.5f, spanWithOpacityProperties->effect()->opacity());
379 EXPECT_EQ(foreignObjectWithOpacityProperties->effect(), spanWithOpacityPrope rties->effect()->parent());
380 }
381
382 TEST_F(PaintPropertyTreeBuilderTest, TransformNodesInSVG)
383 {
384 setBodyInnerHTML(
385 "<style>"
386 " body {"
387 " margin: 0px;"
388 " }"
389 " svg {"
390 " margin-left: 50px;"
391 " transform: translate3d(1px, 2px, 3px);"
392 " position: absolute;"
393 " left: 20px;"
394 " top: 25px;"
395 " }"
396 " rect {"
397 " transform: translate(100px, 100px) rotate(45deg);"
398 " transform-origin: 50px 25px;"
399 " }"
400 "</style>"
401 "<svg id='svgRootWith3dTransform' width='100px' height='100px'>"
402 " <rect id='rectWith2dTransform' width='100px' height='100px' />"
403 "</svg>");
404
405 LayoutObject& svgRootWith3dTransform = *document().getElementById("svgRootWi th3dTransform")->layoutObject();
406 ObjectPaintProperties* svgRootWith3dTransformProperties = svgRootWith3dTrans form.objectPaintProperties();
407 EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), svgRootWith3dTransfor mProperties->transform()->matrix());
408 EXPECT_EQ(FloatPoint3D(50, 50, 0), svgRootWith3dTransformProperties->transfo rm()->origin());
409 EXPECT_EQ(svgRootWith3dTransformProperties->paintOffsetTranslation(), svgRoo tWith3dTransformProperties->transform()->parent());
410 EXPECT_EQ(TransformationMatrix().translate(70, 25), svgRootWith3dTransformPr operties->paintOffsetTranslation()->matrix());
411 EXPECT_EQ(document().view()->scrollTranslation(), svgRootWith3dTransformProp erties->paintOffsetTranslation()->parent());
412
413 LayoutObject& rectWith2dTransform = *document().getElementById("rectWith2dTr ansform")->layoutObject();
414 ObjectPaintProperties* rectWith2dTransformProperties = rectWith2dTransform.o bjectPaintProperties();
415 TransformationMatrix matrix;
416 matrix.translate(100, 100);
417 matrix.rotate(45);
418 // SVG's transform origin is baked into the transform.
419 matrix.applyTransformOrigin(50, 25, 0);
420 EXPECT_EQ(matrix, rectWith2dTransformProperties->transform()->matrix());
421 EXPECT_EQ(FloatPoint3D(0, 0, 0), rectWith2dTransformProperties->transform()- >origin());
422 // SVG does not use paint offset.
423 EXPECT_EQ(nullptr, rectWith2dTransformProperties->paintOffsetTranslation());
424 }
425
426 TEST_F(PaintPropertyTreeBuilderTest, SVGRootPaintOffsetTransformNode)
427 {
428 setBodyInnerHTML(
429 "<style>body { margin: 0px; } </style>"
430 "<svg id='svg' style='margin-left: 50px; margin-top: 25px; width: 100px; height: 100px;' />");
431
432 LayoutObject& svg = *document().getElementById("svg")->layoutObject();
433 ObjectPaintProperties* svgProperties = svg.objectPaintProperties();
434 // Ensure that a paint offset transform is emitted for SVG, even without a C SS transform.
435 EXPECT_EQ(nullptr, svgProperties->transform());
436 EXPECT_EQ(TransformationMatrix().translate(50, 25), svgProperties->paintOffs etTranslation()->matrix());
437 EXPECT_EQ(document().view()->scrollTranslation(), svgProperties->paintOffset Translation()->parent());
438 }
439
440 TEST_F(PaintPropertyTreeBuilderTest, TransformNodesAcrossSVGHTMLBoundary)
441 {
442 setBodyInnerHTML(
443 "<style> body { margin: 0px; } </style>"
444 "<svg id='svgWithTransform' style='transform: translate3d(1px, 2px, 3px) ;'>"
445 " <foreignObject>"
446 " <body>"
447 " <div id='divWithTransform' style='transform: translate3d(3px, 4px , 5px);'></div>"
448 " </body>"
449 " </foreignObject>"
450 "</svg>");
451
452 LayoutObject& svgWithTransform = *document().getElementById("svgWithTransfor m")->layoutObject();
453 ObjectPaintProperties* svgWithTransformProperties = svgWithTransform.objectP aintProperties();
454 EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), svgWithTransformPrope rties->transform()->matrix());
455
456 LayoutObject& divWithTransform = *document().getElementById("divWithTransfor m")->layoutObject();
457 ObjectPaintProperties* divWithTransformProperties = divWithTransform.objectP aintProperties();
458 EXPECT_EQ(TransformationMatrix().translate3d(3, 4, 5), divWithTransformPrope rties->transform()->matrix());
459 // Ensure the div's transform node is a child of the svg's transform node.
460 EXPECT_EQ(svgWithTransformProperties->transform(), divWithTransformPropertie s->transform()->parent());
461 }
462
463 TEST_F(PaintPropertyTreeBuilderTest, FixedTransformAncestorAcrossSVGHTMLBoundary )
464 {
465 setBodyInnerHTML(
466 "<style> body { margin: 0px; } </style>"
467 "<svg id='svg' style='transform: translate3d(1px, 2px, 3px);'>"
468 " <g id='container' transform='translate(20 30)'>"
469 " <foreignObject>"
470 " <body>"
471 " <div id='fixed' style='position: fixed; left: 200px; top: 150px ;'></div>"
472 " </body>"
473 " </foreignObject>"
474 " </g>"
475 "</svg>");
476
477 LayoutObject& svg = *document().getElementById("svg")->layoutObject();
478 ObjectPaintProperties* svgProperties = svg.objectPaintProperties();
479 EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), svgProperties->transf orm()->matrix());
480
481 LayoutObject& container = *document().getElementById("container")->layoutObj ect();
482 ObjectPaintProperties* containerProperties = container.objectPaintProperties ();
483 EXPECT_EQ(TransformationMatrix().translate(20, 30), containerProperties->tra nsform()->matrix());
484 EXPECT_EQ(svgProperties->transform(), containerProperties->transform()->pare nt());
485
486 Element* fixed = document().getElementById("fixed");
487 ObjectPaintProperties* fixedProperties = fixed->layoutObject()->objectPaintP roperties();
488 EXPECT_EQ(TransformationMatrix().translate(200, 150), fixedProperties->paint OffsetTranslation()->matrix());
489 // Ensure the fixed position element is rooted at the nearest transform cont ainer.
490 EXPECT_EQ(containerProperties->transform(), fixedProperties->paintOffsetTran slation()->parent());
491 }
492
493 TEST_F(PaintPropertyTreeBuilderTest, ControlClip)
494 {
495 setBodyInnerHTML(
496 "<style>"
497 " body {"
498 " margin: 0;"
499 " }"
500 " input {"
501 " border-width: 5px;"
502 " padding: 0;"
503 " }"
504 "</style>"
505 "<input id='button' type='button' style='width:345px; height:123px' valu e='some text'/>");
506
507 FrameView* frameView = document().view();
508 LayoutObject& button = *document().getElementById("button")->layoutObject();
509 ObjectPaintProperties* buttonProperties = button.objectPaintProperties();
510 EXPECT_EQ(frameView->scrollTranslation(), buttonProperties->overflowClip()-> localTransformSpace());
511 EXPECT_EQ(FloatRoundedRect(5, 5, 335, 113), buttonProperties->overflowClip() ->clipRect());
512 EXPECT_EQ(frameView->contentClip(), buttonProperties->overflowClip()->parent ());
513 }
514
515 TEST_F(PaintPropertyTreeBuilderTest, BorderRadiusClip)
516 {
517 setBodyInnerHTML(
518 "<style>"
519 " body {"
520 " margin: 0px;"
521 " }"
522 " #div {"
523 " border-radius: 12px 34px 56px 78px;"
524 " border-top: 45px solid;"
525 " border-right: 50px solid;"
526 " border-bottom: 55px solid;"
527 " border-left: 60px solid;"
528 " width: 500px;"
529 " height: 400px;"
530 " overflow: scroll;"
531 " }"
532 "</style>"
533 "<div id='div'></div>");
534
535 FrameView* frameView = document().view();
536 LayoutObject& div = *document().getElementById("div")->layoutObject();
537 ObjectPaintProperties* divProperties = div.objectPaintProperties();
538 EXPECT_EQ(frameView->scrollTranslation(), divProperties->overflowClip()->loc alTransformSpace());
539 // The overflow clip rect includes only the padding box.
540 // padding box = border box(500+60+50, 400+45+55) - border outset(60+50, 45+ 55) - scrollbars(15, 15)
541 EXPECT_EQ(FloatRoundedRect(60, 45, 500, 400), divProperties->overflowClip()- >clipRect());
542 const ClipPaintPropertyNode* borderRadiusClip = divProperties->overflowClip( )->parent();
543 EXPECT_EQ(frameView->scrollTranslation(), borderRadiusClip->localTransformSp ace());
544 // The border radius clip is the area enclosed by inner border edge, includi ng the scrollbars.
545 // As the border-radius is specified in outer radius, the inner radius is ca lculated by:
546 // inner radius = max(outer radius - border width, 0)
547 // In the case that two adjacent borders have different width, the inner rad ius of the corner
548 // may transition from one value to the other. i.e. being an ellipse.
549 EXPECT_EQ(
550 FloatRoundedRect(
551 FloatRect(60, 45, 500, 400), // = border box(610, 500) - border outs et(110, 100)
552 FloatSize(0, 0), // (top left) = max((12, 12) - (60, 45), (0, 0))
553 FloatSize(0, 0), // (top right) = max((34, 34) - (50, 45), (0, 0))
554 FloatSize(18, 23), // (bottom left) = max((78, 78) - (60, 55), (0, 0))
555 FloatSize(6, 1)), // (bottom right) = max((56, 56) - (50, 55), (0, 0))
556 borderRadiusClip->clipRect());
557 EXPECT_EQ(frameView->contentClip(), borderRadiusClip->parent());
558 }
559
560 TEST_F(PaintPropertyTreeBuilderTest, TransformNodesAcrossSubframes)
561 {
562 setBodyInnerHTML(
563 "<style>body { margin: 0; }</style>"
564 "<div id='divWithTransform' style='transform: translate3d(1px, 2px, 3px) ;'>"
565 " <iframe id='frame'></iframe>"
566 "</div>");
567 Document& frameDocument = setupChildIframe("frame", "<style>body { margin: 0 ; }</style><div id='transform' style='transform: translate3d(4px, 5px, 6px);'></ div>");
568 document().view()->updateAllLifecyclePhases();
569
570 LayoutObject& divWithTransform = *document().getElementById("divWithTransfor m")->layoutObject();
571 ObjectPaintProperties* divWithTransformProperties = divWithTransform.objectP aintProperties();
572 EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), divWithTransformPrope rties->transform()->matrix());
573
574 LayoutObject* innerDivWithTransform = frameDocument.getElementById("transfor m")->layoutObject();
575 ObjectPaintProperties* innerDivWithTransformProperties = innerDivWithTransfo rm->objectPaintProperties();
576 auto* innerDivTransform = innerDivWithTransformProperties->transform();
577 EXPECT_EQ(TransformationMatrix().translate3d(4, 5, 6), innerDivTransform->ma trix());
578
579 // Ensure that the inner div's transform is correctly rooted in the root fra me's transform tree.
580 // This asserts that we have the following tree structure:
581 // ...
582 // Transform transform=translation=1.000000,2.000000,3.000000
583 // PreTranslation transform=translation=2.000000,2.000000,0.000000
584 // ScrollTranslation transform=translation=0.000000,0.000000,0.000000
585 // Transform transform=translation=4.000000,5.000000,6.000000
586 auto* innerDocumentScrollTranslation = innerDivTransform->parent();
587 EXPECT_EQ(TransformationMatrix().translate3d(0, 0, 0), innerDocumentScrollTr anslation->matrix());
588 auto* iframePreTranslation = innerDocumentScrollTranslation->parent();
589 EXPECT_EQ(TransformationMatrix().translate3d(2, 2, 0), iframePreTranslation- >matrix());
590 EXPECT_EQ(divWithTransformProperties->transform(), iframePreTranslation->par ent());
591 }
592
593 TEST_F(PaintPropertyTreeBuilderTest, TransformNodesInTransformedSubframes)
594 {
595 setBodyInnerHTML(
596 "<style>body { margin: 0; }</style>"
597 "<div id='divWithTransform' style='transform: translate3d(1px, 2px, 3px) ;'>"
598 " <iframe id='frame' style='transform: translate3d(4px, 5px, 6px); bord er: 42px solid; margin: 7px;'></iframe>"
599 "</div>");
600 Document& frameDocument = setupChildIframe("frame", "<style>body { margin: 3 1px; }</style><div id='transform' style='transform: translate3d(7px, 8px, 9px);' ></div>");
601 document().view()->updateAllLifecyclePhases();
602
603 // Assert that we have the following tree structure:
604 // ...
605 // Transform transform=translation=1.000000,2.000000,3.000000
606 // PaintOffsetTranslation transform=translation=7.000000,7.000000,0.0000 00
607 // Transform transform=translation=4.000000,5.000000,6.000000
608 // PreTranslation transform=translation=42.000000,42.000000,0.000000
609 // ScrollTranslation transform=translation=0.000000,0.000000,0.000 000
610 // PaintOffsetTranslation transform=translation=31.000000,31.000 000,0.000000
611 // Transform transform=translation=7.000000,8.000000,9.000000
612
613 LayoutObject* innerDivWithTransform = frameDocument.getElementById("transfor m")->layoutObject();
614 auto* innerDivTransform = innerDivWithTransform->objectPaintProperties()->tr ansform();
615 EXPECT_EQ(TransformationMatrix().translate3d(7, 8, 9), innerDivTransform->ma trix());
616
617 auto* innerDocumentPaintOffsetTranslation = innerDivTransform->parent();
618 EXPECT_EQ(TransformationMatrix().translate3d(31, 31, 0), innerDocumentPaintO ffsetTranslation->matrix());
619 auto* innerDocumentScrollTranslation = innerDocumentPaintOffsetTranslation-> parent();
620 EXPECT_EQ(TransformationMatrix().translate3d(0, 0, 0), innerDocumentScrollTr anslation->matrix());
621 auto* iframePreTranslation = innerDocumentScrollTranslation->parent();
622 EXPECT_EQ(TransformationMatrix().translate3d(42, 42, 0), iframePreTranslatio n->matrix());
623 auto* iframeTransform = iframePreTranslation->parent();
624 EXPECT_EQ(TransformationMatrix().translate3d(4, 5, 6), iframeTransform->matr ix());
625 auto* iframePaintOffsetTranslation = iframeTransform->parent();
626 EXPECT_EQ(TransformationMatrix().translate3d(7, 7, 0), iframePaintOffsetTran slation->matrix());
627 auto* divWithTransformTransform = iframePaintOffsetTranslation->parent();
628 EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), divWithTransformTrans form->matrix());
629
630 LayoutObject& divWithTransform = *document().getElementById("divWithTransfor m")->layoutObject();
631 EXPECT_EQ(divWithTransformTransform, divWithTransform.objectPaintProperties( )->transform());
632 }
633
634 TEST_F(PaintPropertyTreeBuilderTest, TreeContextClipByNonStackingContext)
635 {
636 // This test verifies the tree builder correctly computes and records the pr operty tree context
637 // for a (pseudo) stacking context that is scrolled by a containing block th at is not one of
638 // the painting ancestors.
639 setBodyInnerHTML(
640 "<style>body { margin: 0; }</style>"
641 "<div id='scroller' style='overflow:scroll; width:400px; height:300px;'> "
642 " <div id='child' style='position:relative;'></div>"
643 " <div style='height:10000px;'></div>"
644 "</div>"
645 );
646
647 LayoutObject& scroller = *document().getElementById("scroller")->layoutObjec t();
648 ObjectPaintProperties* scrollerProperties = scroller.objectPaintProperties() ;
649 LayoutObject& child = *document().getElementById("child")->layoutObject();
650 ObjectPaintProperties* childProperties = child.objectPaintProperties();
651
652 EXPECT_EQ(scrollerProperties->overflowClip(), childProperties->localBorderBo xProperties()->clip);
653 EXPECT_EQ(scrollerProperties->scrollTranslation(), childProperties->localBor derBoxProperties()->transform);
654 EXPECT_EQ(nullptr, childProperties->localBorderBoxProperties()->effect);
655 }
656
657 TEST_F(PaintPropertyTreeBuilderTest, TreeContextUnclipFromParentStackingContext)
658 {
659 // This test verifies the tree builder correctly computes and records the pr operty tree context
660 // for a (pseudo) stacking context that has a scrolling painting ancestor th at is not its
661 // containing block (thus should not be scrolled by it).
662
663 setBodyInnerHTML(
664 "<style>body { margin: 0; }</style>"
665 "<div id='scroller' style='overflow:scroll; opacity:0.5;'>"
666 " <div id='child' style='position:absolute; left:0; top:0;'></div>"
667 " <div style='height:10000px;'></div>"
668 "</div>"
669 );
670
671 FrameView* frameView = document().view();
672 LayoutObject& scroller = *document().getElementById("scroller")->layoutObjec t();
673 ObjectPaintProperties* scrollerProperties = scroller.objectPaintProperties() ;
674 LayoutObject& child = *document().getElementById("child")->layoutObject();
675 ObjectPaintProperties* childProperties = child.objectPaintProperties();
676
677 EXPECT_EQ(frameView->contentClip(), childProperties->localBorderBoxPropertie s()->clip);
678 EXPECT_EQ(frameView->scrollTranslation(), childProperties->localBorderBoxPro perties()->transform);
679 EXPECT_EQ(scrollerProperties->effect(), childProperties->localBorderBoxPrope rties()->effect);
680 }
681
682 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698