OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "CCLayerSorter.h" | |
8 | |
9 #include "CCLayerImpl.h" | |
10 #include "CCMathUtil.h" | |
11 #include "CCSingleThreadProxy.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 #include <public/WebTransformationMatrix.h> | |
14 | |
15 using namespace cc; | |
16 using WebKit::WebTransformationMatrix; | |
17 | |
18 namespace { | |
19 | |
20 // Note: In the following overlap tests, the "camera" is looking down the negati
ve Z axis, | |
21 // meaning that layers with smaller z values (more negative) are further from th
e camera | |
22 // and therefore must be drawn before layers with higher z values. | |
23 | |
24 TEST(CCLayerSorterTest, BasicOverlap) | |
25 { | |
26 CCLayerSorter::ABCompareResult overlapResult; | |
27 const float zThreshold = 0.1f; | |
28 float weight = 0; | |
29 | |
30 // Trivial test, with one layer directly obscuring the other. | |
31 WebTransformationMatrix neg4Translate; | |
32 neg4Translate.translate3d(0, 0, -4); | |
33 CCLayerSorter::LayerShape front(2, 2, neg4Translate); | |
34 | |
35 WebTransformationMatrix neg5Translate; | |
36 neg5Translate.translate3d(0, 0, -5); | |
37 CCLayerSorter::LayerShape back(2, 2, neg5Translate); | |
38 | |
39 overlapResult = CCLayerSorter::checkOverlap(&front, &back, zThreshold, weigh
t); | |
40 EXPECT_EQ(CCLayerSorter::BBeforeA, overlapResult); | |
41 EXPECT_EQ(1, weight); | |
42 | |
43 overlapResult = CCLayerSorter::checkOverlap(&back, &front, zThreshold, weigh
t); | |
44 EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult); | |
45 EXPECT_EQ(1, weight); | |
46 | |
47 // One layer translated off to the right. No overlap should be detected. | |
48 WebTransformationMatrix rightTranslate; | |
49 rightTranslate.translate3d(10, 0, -5); | |
50 CCLayerSorter::LayerShape backRight(2, 2, rightTranslate); | |
51 overlapResult = CCLayerSorter::checkOverlap(&front, &backRight, zThreshold,
weight); | |
52 EXPECT_EQ(CCLayerSorter::None, overlapResult); | |
53 | |
54 // When comparing a layer with itself, z difference is always 0. | |
55 overlapResult = CCLayerSorter::checkOverlap(&front, &front, zThreshold, weig
ht); | |
56 EXPECT_EQ(0, weight); | |
57 } | |
58 | |
59 TEST(CCLayerSorterTest, RightAngleOverlap) | |
60 { | |
61 CCLayerSorter::ABCompareResult overlapResult; | |
62 const float zThreshold = 0.1f; | |
63 float weight = 0; | |
64 | |
65 WebTransformationMatrix perspectiveMatrix; | |
66 perspectiveMatrix.applyPerspective(1000); | |
67 | |
68 // Two layers forming a right angle with a perspective viewing transform. | |
69 WebTransformationMatrix leftFaceMatrix; | |
70 leftFaceMatrix.rotate3d(0, 1, 0, -90); | |
71 leftFaceMatrix.translateRight3d(-1, 0, -5); | |
72 leftFaceMatrix.translate(-1, -1); | |
73 CCLayerSorter::LayerShape leftFace(2, 2, perspectiveMatrix * leftFaceMatrix)
; | |
74 WebTransformationMatrix frontFaceMatrix; | |
75 frontFaceMatrix.translate3d(0, 0, -4); | |
76 frontFaceMatrix.translate(-1, -1); | |
77 CCLayerSorter::LayerShape frontFace(2, 2, perspectiveMatrix * frontFaceMatri
x); | |
78 | |
79 overlapResult = CCLayerSorter::checkOverlap(&frontFace, &leftFace, zThreshol
d, weight); | |
80 EXPECT_EQ(CCLayerSorter::BBeforeA, overlapResult); | |
81 } | |
82 | |
83 TEST(CCLayerSorterTest, IntersectingLayerOverlap) | |
84 { | |
85 CCLayerSorter::ABCompareResult overlapResult; | |
86 const float zThreshold = 0.1f; | |
87 float weight = 0; | |
88 | |
89 WebTransformationMatrix perspectiveMatrix; | |
90 perspectiveMatrix.applyPerspective(1000); | |
91 | |
92 // Intersecting layers. An explicit order will be returned based on relative
z | |
93 // values at the overlapping features but the weight returned should be zero
. | |
94 WebTransformationMatrix frontFaceMatrix; | |
95 frontFaceMatrix.translate3d(0, 0, -4); | |
96 frontFaceMatrix.translate(-1, -1); | |
97 CCLayerSorter::LayerShape frontFace(2, 2, perspectiveMatrix * frontFaceMatri
x); | |
98 | |
99 WebTransformationMatrix throughMatrix; | |
100 throughMatrix.rotate3d(0, 1, 0, 45); | |
101 throughMatrix.translateRight3d(0, 0, -4); | |
102 throughMatrix.translate(-1, -1); | |
103 CCLayerSorter::LayerShape rotatedFace(2, 2, perspectiveMatrix * throughMatri
x); | |
104 overlapResult = CCLayerSorter::checkOverlap(&frontFace, &rotatedFace, zThres
hold, weight); | |
105 EXPECT_NE(CCLayerSorter::None, overlapResult); | |
106 EXPECT_EQ(0, weight); | |
107 } | |
108 | |
109 TEST(CCLayerSorterTest, LayersAtAngleOverlap) | |
110 { | |
111 CCLayerSorter::ABCompareResult overlapResult; | |
112 const float zThreshold = 0.1f; | |
113 float weight = 0; | |
114 | |
115 // Trickier test with layers at an angle. | |
116 // | |
117 // -x . . . . 0 . . . . +x | |
118 // -z / | |
119 // : /----B---- | |
120 // 0 C | |
121 // : ----A----/ | |
122 // +z / | |
123 // | |
124 // C is in front of A and behind B (not what you'd expect by comparing cente
rs). | |
125 // A and B don't overlap, so they're incomparable. | |
126 | |
127 WebTransformationMatrix transformA; | |
128 transformA.translate3d(-6, 0, 1); | |
129 transformA.translate(-4, -10); | |
130 CCLayerSorter::LayerShape layerA(8, 20, transformA); | |
131 | |
132 WebTransformationMatrix transformB; | |
133 transformB.translate3d(6, 0, -1); | |
134 transformB.translate(-4, -10); | |
135 CCLayerSorter::LayerShape layerB(8, 20, transformB); | |
136 | |
137 WebTransformationMatrix transformC; | |
138 transformC.rotate3d(0, 1, 0, 40); | |
139 transformC.translate(-4, -10); | |
140 CCLayerSorter::LayerShape layerC(8, 20, transformC); | |
141 | |
142 overlapResult = CCLayerSorter::checkOverlap(&layerA, &layerC, zThreshold, we
ight); | |
143 EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult); | |
144 overlapResult = CCLayerSorter::checkOverlap(&layerC, &layerB, zThreshold, we
ight); | |
145 EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult); | |
146 overlapResult = CCLayerSorter::checkOverlap(&layerA, &layerB, zThreshold, we
ight); | |
147 EXPECT_EQ(CCLayerSorter::None, overlapResult); | |
148 } | |
149 | |
150 TEST(CCLayerSorterTest, LayersUnderPathologicalPerspectiveTransform) | |
151 { | |
152 CCLayerSorter::ABCompareResult overlapResult; | |
153 const float zThreshold = 0.1f; | |
154 float weight = 0; | |
155 | |
156 // On perspective projection, if w becomes negative, the re-projected point
will be | |
157 // invalid and un-usable. Correct code needs to clip away portions of the ge
ometry | |
158 // where w < 0. If the code uses the invalid value, it will think that a lay
er has | |
159 // different bounds than it really does, which can cause things to sort inco
rrectly. | |
160 | |
161 WebTransformationMatrix perspectiveMatrix; | |
162 perspectiveMatrix.applyPerspective(1); | |
163 | |
164 WebTransformationMatrix transformA; | |
165 transformA.translate3d(-15, 0, -2); | |
166 transformA.translate(-5, -5); | |
167 CCLayerSorter::LayerShape layerA(10, 10, perspectiveMatrix * transformA); | |
168 | |
169 // With this sequence of transforms, when layer B is correctly clipped, it w
ill be | |
170 // visible on the left half of the projection plane, in front of layerA. Whe
n it is | |
171 // not clipped, its bounds will actually incorrectly appear much smaller and
the | |
172 // correct sorting dependency will not be found. | |
173 WebTransformationMatrix transformB; | |
174 transformB.translate3d(0, 0, 0.7); | |
175 transformB.rotate3d(0, 45, 0); | |
176 transformB.translate(-5, -5); | |
177 CCLayerSorter::LayerShape layerB(10, 10, perspectiveMatrix * transformB); | |
178 | |
179 // Sanity check that the test case actually covers the intended scenario, wh
ere part | |
180 // of layer B go behind the w = 0 plane. | |
181 FloatQuad testQuad = FloatQuad(FloatRect(FloatPoint(-0.5, -0.5), FloatSize(1
, 1))); | |
182 bool clipped = false; | |
183 CCMathUtil::mapQuad(perspectiveMatrix * transformB, testQuad, clipped); | |
184 ASSERT_TRUE(clipped); | |
185 | |
186 overlapResult = CCLayerSorter::checkOverlap(&layerA, &layerB, zThreshold, we
ight); | |
187 EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult); | |
188 } | |
189 | |
190 TEST(CCLayerSorterTest, verifyExistingOrderingPreservedWhenNoZDiff) | |
191 { | |
192 DebugScopedSetImplThread thisScopeIsOnImplThread; | |
193 | |
194 // If there is no reason to re-sort the layers (i.e. no 3d z difference), th
en the | |
195 // existing ordering provided on input should be retained. This test covers
the fix in | |
196 // https://bugs.webkit.org/show_bug.cgi?id=75046. Before this fix, ordering
was | |
197 // accidentally reversed, causing bugs in z-index ordering on websites when | |
198 // preserves3D triggered the CCLayerSorter. | |
199 | |
200 // Input list of layers: [1, 2, 3, 4, 5]. | |
201 // Expected output: [3, 4, 1, 2, 5]. | |
202 // - 1, 2, and 5 do not have a 3d z difference, and therefore their relat
ive ordering should be retained. | |
203 // - 3 and 4 do not have a 3d z difference, and therefore their relative
ordering should be retained. | |
204 // - 3 and 4 should be re-sorted so they are in front of 1, 2, and 5. | |
205 | |
206 scoped_ptr<CCLayerImpl> layer1 = CCLayerImpl::create(1); | |
207 scoped_ptr<CCLayerImpl> layer2 = CCLayerImpl::create(2); | |
208 scoped_ptr<CCLayerImpl> layer3 = CCLayerImpl::create(3); | |
209 scoped_ptr<CCLayerImpl> layer4 = CCLayerImpl::create(4); | |
210 scoped_ptr<CCLayerImpl> layer5 = CCLayerImpl::create(5); | |
211 | |
212 WebTransformationMatrix BehindMatrix; | |
213 BehindMatrix.translate3d(0, 0, 2); | |
214 WebTransformationMatrix FrontMatrix; | |
215 FrontMatrix.translate3d(0, 0, 1); | |
216 | |
217 layer1->setBounds(IntSize(10, 10)); | |
218 layer1->setContentBounds(IntSize(10, 10)); | |
219 layer1->setDrawTransform(BehindMatrix); | |
220 layer1->setDrawsContent(true); | |
221 | |
222 layer2->setBounds(IntSize(20, 20)); | |
223 layer2->setContentBounds(IntSize(20, 20)); | |
224 layer2->setDrawTransform(BehindMatrix); | |
225 layer2->setDrawsContent(true); | |
226 | |
227 layer3->setBounds(IntSize(30, 30)); | |
228 layer3->setContentBounds(IntSize(30, 30)); | |
229 layer3->setDrawTransform(FrontMatrix); | |
230 layer3->setDrawsContent(true); | |
231 | |
232 layer4->setBounds(IntSize(40, 40)); | |
233 layer4->setContentBounds(IntSize(40, 40)); | |
234 layer4->setDrawTransform(FrontMatrix); | |
235 layer4->setDrawsContent(true); | |
236 | |
237 layer5->setBounds(IntSize(50, 50)); | |
238 layer5->setContentBounds(IntSize(50, 50)); | |
239 layer5->setDrawTransform(BehindMatrix); | |
240 layer5->setDrawsContent(true); | |
241 | |
242 std::vector<CCLayerImpl*> layerList; | |
243 layerList.push_back(layer1.get()); | |
244 layerList.push_back(layer2.get()); | |
245 layerList.push_back(layer3.get()); | |
246 layerList.push_back(layer4.get()); | |
247 layerList.push_back(layer5.get()); | |
248 | |
249 ASSERT_EQ(static_cast<size_t>(5), layerList.size()); | |
250 EXPECT_EQ(1, layerList[0]->id()); | |
251 EXPECT_EQ(2, layerList[1]->id()); | |
252 EXPECT_EQ(3, layerList[2]->id()); | |
253 EXPECT_EQ(4, layerList[3]->id()); | |
254 EXPECT_EQ(5, layerList[4]->id()); | |
255 | |
256 CCLayerSorter layerSorter; | |
257 layerSorter.sort(layerList.begin(), layerList.end()); | |
258 | |
259 ASSERT_EQ(static_cast<size_t>(5), layerList.size()); | |
260 EXPECT_EQ(3, layerList[0]->id()); | |
261 EXPECT_EQ(4, layerList[1]->id()); | |
262 EXPECT_EQ(1, layerList[2]->id()); | |
263 EXPECT_EQ(2, layerList[3]->id()); | |
264 EXPECT_EQ(5, layerList[4]->id()); | |
265 } | |
266 | |
267 } // namespace | |
OLD | NEW |