1 // Copyright 2011 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.
5 #include "cc/layer_sorter.h"
7 #include "cc/layer_impl.h"
8 #include "cc/math_util.h"
9 #include "cc/single_thread_proxy.h"
10 #include "cc/test/fake_impl_proxy.h"
11 #include "cc/test/fake_layer_tree_host_impl.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "ui/gfx/transform.h"
18 // Note: In the following overlap tests, the "camera" is looking down the negative Z axis,
19 // meaning that layers with smaller z values (more negative) are further from the camera
20 // and therefore must be drawn before layers with higher z values.
22 TEST(LayerSorterTest
, BasicOverlap
)
24 LayerSorter::ABCompareResult overlapResult
;
25 const float zThreshold
= 0.1f
;
28 // Trivial test, with one layer directly obscuring the other.
29 gfx::Transform neg4Translate
;
30 neg4Translate
.Translate3d(0, 0, -4);
31 LayerShape
front(2, 2, neg4Translate
);
33 gfx::Transform neg5Translate
;
34 neg5Translate
.Translate3d(0, 0, -5);
35 LayerShape
back(2, 2, neg5Translate
);
37 overlapResult
= LayerSorter::checkOverlap(&front
, &back
, zThreshold
, weight
);
38 EXPECT_EQ(LayerSorter::BBeforeA
, overlapResult
);
41 overlapResult
= LayerSorter::checkOverlap(&back
, &front
, zThreshold
, weight
);
42 EXPECT_EQ(LayerSorter::ABeforeB
, overlapResult
);
45 // One layer translated off to the right. No overlap should be detected.
46 gfx::Transform rightTranslate
;
47 rightTranslate
.Translate3d(10, 0, -5);
48 LayerShape
backRight(2, 2, rightTranslate
);
49 overlapResult
= LayerSorter::checkOverlap(&front
, &backRight
, zThreshold
, weight
);
50 EXPECT_EQ(LayerSorter::None
, overlapResult
);
52 // When comparing a layer with itself, z difference is always 0.
53 overlapResult
= LayerSorter::checkOverlap(&front
, &front
, zThreshold
, weight
);
57 TEST(LayerSorterTest
, RightAngleOverlap
)
59 LayerSorter::ABCompareResult overlapResult
;
60 const float zThreshold
= 0.1f
;
63 gfx::Transform perspectiveMatrix
;
64 perspectiveMatrix
.ApplyPerspectiveDepth(1000);
66 // Two layers forming a right angle with a perspective viewing transform.
67 gfx::Transform leftFaceMatrix
;
68 leftFaceMatrix
.Translate3d(-1, 0, -5);
69 leftFaceMatrix
.RotateAboutYAxis(-90);
70 leftFaceMatrix
.Translate(-1, -1);
71 LayerShape
leftFace(2, 2, perspectiveMatrix
* leftFaceMatrix
);
72 gfx::Transform frontFaceMatrix
;
73 frontFaceMatrix
.Translate3d(0, 0, -4);
74 frontFaceMatrix
.Translate(-1, -1);
75 LayerShape
frontFace(2, 2, perspectiveMatrix
* frontFaceMatrix
);
77 overlapResult
= LayerSorter::checkOverlap(&frontFace
, &leftFace
, zThreshold
, weight
);
78 EXPECT_EQ(LayerSorter::BBeforeA
, overlapResult
);
81 TEST(LayerSorterTest
, IntersectingLayerOverlap
)
83 LayerSorter::ABCompareResult overlapResult
;
84 const float zThreshold
= 0.1f
;
87 gfx::Transform perspectiveMatrix
;
88 perspectiveMatrix
.ApplyPerspectiveDepth(1000);
90 // Intersecting layers. An explicit order will be returned based on relative z
91 // values at the overlapping features but the weight returned should be zero.
92 gfx::Transform frontFaceMatrix
;
93 frontFaceMatrix
.Translate3d(0, 0, -4);
94 frontFaceMatrix
.Translate(-1, -1);
95 LayerShape
frontFace(2, 2, perspectiveMatrix
* frontFaceMatrix
);
97 gfx::Transform throughMatrix
;
98 throughMatrix
.Translate3d(0, 0, -4);
99 throughMatrix
.RotateAboutYAxis(45);
100 throughMatrix
.Translate(-1, -1);
101 LayerShape
rotatedFace(2, 2, perspectiveMatrix
* throughMatrix
);
102 overlapResult
= LayerSorter::checkOverlap(&frontFace
, &rotatedFace
, zThreshold
, weight
);
103 EXPECT_NE(LayerSorter::None
, overlapResult
);
104 EXPECT_EQ(0, weight
);
107 TEST(LayerSorterTest
, LayersAtAngleOverlap
)
109 LayerSorter::ABCompareResult overlapResult
;
110 const float zThreshold
= 0.1f
;
113 // Trickier test with layers at an angle.
115 // -x . . . . 0 . . . . +x
122 // C is in front of A and behind B (not what you'd expect by comparing centers).
123 // A and B don't overlap, so they're incomparable.
125 gfx::Transform transformA
;
126 transformA
.Translate3d(-6, 0, 1);
127 transformA
.Translate(-4, -10);
128 LayerShape
layerA(8, 20, transformA
);
130 gfx::Transform transformB
;
131 transformB
.Translate3d(6, 0, -1);
132 transformB
.Translate(-4, -10);
133 LayerShape
layerB(8, 20, transformB
);
135 gfx::Transform transformC
;
136 transformC
.RotateAboutYAxis(40);
137 transformC
.Translate(-4, -10);
138 LayerShape
layerC(8, 20, transformC
);
140 overlapResult
= LayerSorter::checkOverlap(&layerA
, &layerC
, zThreshold
, weight
);
141 EXPECT_EQ(LayerSorter::ABeforeB
, overlapResult
);
142 overlapResult
= LayerSorter::checkOverlap(&layerC
, &layerB
, zThreshold
, weight
);
143 EXPECT_EQ(LayerSorter::ABeforeB
, overlapResult
);
144 overlapResult
= LayerSorter::checkOverlap(&layerA
, &layerB
, zThreshold
, weight
);
145 EXPECT_EQ(LayerSorter::None
, overlapResult
);
148 TEST(LayerSorterTest
, LayersUnderPathologicalPerspectiveTransform
)
150 LayerSorter::ABCompareResult overlapResult
;
151 const float zThreshold
= 0.1f
;
154 // On perspective projection, if w becomes negative, the re-projected point will be
155 // invalid and un-usable. Correct code needs to clip away portions of the geometry
156 // where w < 0. If the code uses the invalid value, it will think that a layer has
157 // different bounds than it really does, which can cause things to sort incorrectly.
159 gfx::Transform perspectiveMatrix
;
160 perspectiveMatrix
.ApplyPerspectiveDepth(1);
162 gfx::Transform transformA
;
163 transformA
.Translate3d(-15, 0, -2);
164 transformA
.Translate(-5, -5);
165 LayerShape
layerA(10, 10, perspectiveMatrix
* transformA
);
167 // With this sequence of transforms, when layer B is correctly clipped, it will be
168 // visible on the left half of the projection plane, in front of layerA. When it is
169 // not clipped, its bounds will actually incorrectly appear much smaller and the
170 // correct sorting dependency will not be found.
171 gfx::Transform transformB
;
172 transformB
.Translate3d(0, 0, 0.7);
173 MathUtil::rotateEulerAngles(&transformB
, 0, 45, 0);
174 transformB
.Translate(-5, -5);
175 LayerShape
layerB(10, 10, perspectiveMatrix
* transformB
);
177 // Sanity check that the test case actually covers the intended scenario, where part
178 // of layer B go behind the w = 0 plane.
179 gfx::QuadF testQuad
= gfx::QuadF(gfx::RectF(-0.5, -0.5, 1, 1));
180 bool clipped
= false;
181 MathUtil::mapQuad(perspectiveMatrix
* transformB
, testQuad
, clipped
);
182 ASSERT_TRUE(clipped
);
184 overlapResult
= LayerSorter::checkOverlap(&layerA
, &layerB
, zThreshold
, weight
);
185 EXPECT_EQ(LayerSorter::ABeforeB
, overlapResult
);
188 TEST(LayerSorterTest
, verifyExistingOrderingPreservedWhenNoZDiff
)
190 // If there is no reason to re-sort the layers (i.e. no 3d z difference), then the
191 // existing ordering provided on input should be retained. This test covers the fix in
192 // https://bugs.webkit.org/show_bug.cgi?id=75046. Before this fix, ordering was
193 // accidentally reversed, causing bugs in z-index ordering on websites when
194 // preserves3D triggered the LayerSorter.
196 // Input list of layers: [1, 2, 3, 4, 5].
197 // Expected output: [3, 4, 1, 2, 5].
198 // - 1, 2, and 5 do not have a 3d z difference, and therefore their relative ordering should be retained.
199 // - 3 and 4 do not have a 3d z difference, and therefore their relative ordering should be retained.
200 // - 3 and 4 should be re-sorted so they are in front of 1, 2, and 5.
203 FakeLayerTreeHostImpl
hostImpl(&proxy
);
205 scoped_ptr
<LayerImpl
> layer1
= LayerImpl::create(&hostImpl
, 1);
206 scoped_ptr
<LayerImpl
> layer2
= LayerImpl::create(&hostImpl
, 2);
207 scoped_ptr
<LayerImpl
> layer3
= LayerImpl::create(&hostImpl
, 3);
208 scoped_ptr
<LayerImpl
> layer4
= LayerImpl::create(&hostImpl
, 4);
209 scoped_ptr
<LayerImpl
> layer5
= LayerImpl::create(&hostImpl
, 5);
211 gfx::Transform BehindMatrix
;
212 BehindMatrix
.Translate3d(0, 0, 2);
213 gfx::Transform FrontMatrix
;
214 FrontMatrix
.Translate3d(0, 0, 1);
216 layer1
->setBounds(gfx::Size(10, 10));
217 layer1
->setContentBounds(gfx::Size(10, 10));
218 layer1
->drawProperties().target_space_transform
= BehindMatrix
;
219 layer1
->setDrawsContent(true);
221 layer2
->setBounds(gfx::Size(20, 20));
222 layer2
->setContentBounds(gfx::Size(20, 20));
223 layer2
->drawProperties().target_space_transform
= BehindMatrix
;
224 layer2
->setDrawsContent(true);
226 layer3
->setBounds(gfx::Size(30, 30));
227 layer3
->setContentBounds(gfx::Size(30, 30));
228 layer3
->drawProperties().target_space_transform
= FrontMatrix
;
229 layer3
->setDrawsContent(true);
231 layer4
->setBounds(gfx::Size(40, 40));
232 layer4
->setContentBounds(gfx::Size(40, 40));
233 layer4
->drawProperties().target_space_transform
= FrontMatrix
;
234 layer4
->setDrawsContent(true);
236 layer5
->setBounds(gfx::Size(50, 50));
237 layer5
->setContentBounds(gfx::Size(50, 50));
238 layer5
->drawProperties().target_space_transform
= BehindMatrix
;
239 layer5
->setDrawsContent(true);
241 std::vector
<LayerImpl
*> layerList
;
242 layerList
.push_back(layer1
.get());
243 layerList
.push_back(layer2
.get());
244 layerList
.push_back(layer3
.get());
245 layerList
.push_back(layer4
.get());
246 layerList
.push_back(layer5
.get());
248 ASSERT_EQ(static_cast<size_t>(5), layerList
.size());
249 EXPECT_EQ(1, layerList
[0]->id());
250 EXPECT_EQ(2, layerList
[1]->id());
251 EXPECT_EQ(3, layerList
[2]->id());
252 EXPECT_EQ(4, layerList
[3]->id());
253 EXPECT_EQ(5, layerList
[4]->id());
255 LayerSorter layerSorter
;
256 layerSorter
.sort(layerList
.begin(), layerList
.end());
258 ASSERT_EQ(static_cast<size_t>(5), layerList
.size());
259 EXPECT_EQ(3, layerList
[0]->id());
260 EXPECT_EQ(4, layerList
[1]->id());
261 EXPECT_EQ(1, layerList
[2]->id());
262 EXPECT_EQ(2, layerList
[3]->id());
263 EXPECT_EQ(5, layerList
[4]->id());