| 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 |