Changeset 113341 in webkit
- Timestamp:
- Apr 5, 2012 11:24:16 AM (12 years ago)
- Location:
- trunk/Source
- Files:
-
- 2 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r113340 r113341 1 2012-04-05 Shawn Singh <shawnsingh@chromium.org> 2 3 [chromium] Need to clip to homogeneous w=0 plane when applying transforms. 4 https://bugs.webkit.org/show_bug.cgi?id=80806 5 6 Reviewed by Adrienne Walker. 7 8 Unit tests added to CCLayerTreeHostCommon. This change is also 9 covered by other existing unit tests and layout tests. 10 11 WebCore TransformationMatrix mapRect / mapQuad / projectQuad do 12 not properly handle the case where a surface is oriented partially 13 behind the camera, with a perspective projection. In this case, 14 projected points may appear to be valid in cartesian coordinates, 15 but they are indeed not valid, and this problem can only be 16 detected in homogeneous coordinates after applying the transform, 17 before the divide-by-w step. 18 19 The correct solution is to clip geometry where w < 0. This patch 20 makes this change local to chromium only, to fix rendering bugs 21 that arise from this problem. The primary fix is to correct 22 calculateVisibleLayerRect(), but other ancillary locations are 23 also fixed, in particular, the antialiasing code path is simply 24 skipped when this case arises. 25 26 Eventually this math needs to be merged into TransformationMatrix, 27 to fix hit-testing bugs that occur in both Chromium and Safari. 28 29 * WebCore.gypi: 30 * platform/graphics/chromium/LayerRendererChromium.cpp: 31 (WebCore::findTileProgramUniforms): 32 (WebCore::LayerRendererChromium::drawTileQuad): 33 * platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp: 34 (WebCore::CCLayerTreeHostCommon::calculateVisibleRect): 35 (WebCore::isScaleOrTranslation): 36 (WebCore::calculateDrawTransformsAndVisibilityInternal): 37 * platform/graphics/chromium/cc/CCMathUtil.cpp: Added. 38 (WebCore): 39 (WebCore::HomogeneousCoordinate::HomogeneousCoordinate): 40 (HomogeneousCoordinate): 41 (WebCore::HomogeneousCoordinate::shouldBeClipped): 42 (WebCore::HomogeneousCoordinate::cartesianPoint2d): 43 (WebCore::projectPoint): 44 (WebCore::mapPoint): 45 (WebCore::computeClippedPointForEdge): 46 (WebCore::expandBoundsToIncludePoint): 47 (WebCore::computeEnclosingRectOfClippedQuad): 48 (WebCore::computeEnclosingRect): 49 (WebCore::CCMathUtil::mapClippedRect): 50 (WebCore::CCMathUtil::projectClippedRect): 51 (WebCore::CCMathUtil::mapQuad): 52 (WebCore::CCMathUtil::projectQuad): 53 * platform/graphics/chromium/cc/CCMathUtil.h: Added. 54 (WebCore): 55 (CCMathUtil): 56 * platform/graphics/chromium/cc/CCOcclusionTracker.cpp: 57 (WebCore::computeUnoccludedContentRect): 58 1 59 2012-04-05 Jia Pu <jpu@apple.com> 2 60 -
trunk/Source/WebCore/WebCore.gypi
r113297 r113341 3608 3608 'platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp', 3609 3609 'platform/graphics/chromium/cc/CCLayerTreeHostImpl.h', 3610 'platform/graphics/chromium/cc/CCMathUtil.cpp', 3611 'platform/graphics/chromium/cc/CCMathUtil.h', 3610 3612 'platform/graphics/chromium/cc/CCOcclusionTracker.cpp', 3611 3613 'platform/graphics/chromium/cc/CCOcclusionTracker.h', -
trunk/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
r113248 r113341 56 56 #include "cc/CCLayerImpl.h" 57 57 #include "cc/CCLayerTreeHostCommon.h" 58 #include "cc/CCMathUtil.h" 58 59 #include "cc/CCProxy.h" 59 60 #include "cc/CCRenderPass.h" … … 565 566 } 566 567 567 static void findTileProgramUniforms(LayerRendererChromium* layerRenderer, const CCTileDrawQuad* quad, TileProgramUniforms& uniforms) 568 { 569 if (quad->isAntialiased()) { 568 static void findTileProgramUniforms(LayerRendererChromium* layerRenderer, const CCTileDrawQuad* quad, TileProgramUniforms& uniforms, bool quadIsClipped) 569 { 570 // For now, we simply skip anti-aliasing with the quad is clipped. This only happens 571 // on perspective transformed layers that go partially behind the camera. 572 if (quad->isAntialiased() && !quadIsClipped) { 570 573 if (quad->swizzleContents()) { 571 574 const CCTiledLayerImpl::ProgramSwizzleAA* program = layerRenderer->tilerProgramSwizzleAA(); … … 630 633 float fragmentTexScaleY = clampRect.height() / textureSize.height(); 631 634 635 636 FloatQuad localQuad; 637 TransformationMatrix deviceTransform = TransformationMatrix(windowMatrix() * projectionMatrix() * quad->quadTransform()).to2dTransform(); 638 if (!deviceTransform.isInvertible()) 639 return; 640 641 bool clipped = false; 642 FloatQuad deviceLayerQuad = CCMathUtil::mapQuad(deviceTransform, FloatQuad(quad->layerRect()), clipped); 643 632 644 TileProgramUniforms uniforms; 633 findTileProgramUniforms(this, quad, uniforms );645 findTileProgramUniforms(this, quad, uniforms, clipped); 634 646 635 647 GLC(context(), context()->useProgram(uniforms.program)); … … 640 652 GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, quad->textureFilter())); 641 653 642 FloatQuad localQuad; 643 if (quad->isAntialiased()) { 644 TransformationMatrix deviceTransform = TransformationMatrix(windowMatrix() * projectionMatrix() * quad->quadTransform()).to2dTransform(); 645 if (!deviceTransform.isInvertible()) 646 return; 647 648 FloatQuad deviceLayerQuad = deviceTransform.mapQuad(FloatQuad(quad->layerRect())); 654 655 if (!clipped && quad->isAntialiased()) { 649 656 650 657 CCLayerQuad deviceLayerBounds = CCLayerQuad(FloatQuad(deviceLayerQuad.boundingBox())); -
trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp
r112436 r113341 38 38 #include "cc/CCLayerIterator.h" 39 39 #include "cc/CCLayerSorter.h" 40 #include "cc/CCMathUtil.h" 40 41 #include "cc/CCRenderSurface.h" 41 42 … … 45 46 { 46 47 // Is this layer fully contained within the target surface? 47 IntRect layerInSurfaceSpace = transform.mapRect(layerBoundRect);48 IntRect layerInSurfaceSpace = CCMathUtil::mapClippedRect(transform, layerBoundRect); 48 49 if (targetSurfaceRect.contains(layerInSurfaceSpace)) 49 50 return layerBoundRect; … … 60 61 // Non-invertible transforms will create an empty rect here. 61 62 const TransformationMatrix surfaceToLayer = transform.inverse(); 62 IntRect layerRect = surfaceToLayer.projectQuad(FloatQuad(FloatRect(minimalSurfaceRect))).enclosingBoundingBox();63 IntRect layerRect = enclosingIntRect(CCMathUtil::projectClippedRect(surfaceToLayer, FloatRect(minimalSurfaceRect))); 63 64 layerRect.intersect(layerBoundRect); 64 65 return layerRect; … … 71 72 && !m.m31() && !m.m32() && !m.m43() 72 73 && m.m44(); 73 74 74 } 75 75 … … 410 410 layer->setDrawTransformIsAnimating(animatingTransformToTarget); 411 411 layer->setScreenSpaceTransformIsAnimating(animatingTransformToScreen); 412 transformedLayerRect = enclosingIntRect( layer->drawTransform().mapRect(layerRect));412 transformedLayerRect = enclosingIntRect(CCMathUtil::mapClippedRect(layer->drawTransform(), layerRect)); 413 413 414 414 layer->setDrawOpacity(drawOpacity); -
trunk/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp
r112548 r113341 32 32 #include "LayerChromium.h" 33 33 #include "cc/CCLayerImpl.h" 34 #include "cc/CCMathUtil.h" 34 35 35 36 #include <algorithm> … … 276 277 } 277 278 278 static FloatQuad projectQuad(const TransformationMatrix& transform, const FloatQuad& q, bool& clamped)279 {280 FloatQuad projectedQuad;281 bool clampedPoint;282 projectedQuad.setP1(transform.projectPoint(q.p1(), &clampedPoint));283 clamped = clampedPoint;284 projectedQuad.setP2(transform.projectPoint(q.p2(), &clampedPoint));285 clamped |= clampedPoint;286 projectedQuad.setP3(transform.projectPoint(q.p3(), &clampedPoint));287 clamped |= clampedPoint;288 projectedQuad.setP4(transform.projectPoint(q.p4(), &clampedPoint));289 clamped |= clampedPoint;290 291 return projectedQuad;292 }293 294 279 static inline IntRect computeUnoccludedContentRect(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const IntRect& scissorRect, const Region& occlusion) 295 280 { … … 300 285 // Take the enclosingIntRect at each step, as we want to contain any unoccluded partial pixels in the resulting IntRect. 301 286 IntRect shrunkRect = rectSubtractRegion(intersection(enclosingIntRect(transformedRect), scissorRect), occlusion); 302 bool cl amped; // FIXME: projectQuad returns invalid results when a point gets clamped. To be fixed in bug https://bugs.webkit.org/show_bug.cgi?id=80806.303 IntRect unoccludedRect = enclosingIntRect( projectQuad(contentSpaceTransform.inverse(), FloatQuad(FloatRect(shrunkRect)), clamped).boundingBox());304 if (cl amped)287 bool clipped; // FIXME: We should be able to use projectClippedQuad instead of forcing everything to be unoccluded. https://bugs.webkit.org/show_bug.cgi?id=83217. 288 IntRect unoccludedRect = enclosingIntRect(CCMathUtil::projectQuad(contentSpaceTransform.inverse(), FloatQuad(FloatRect(shrunkRect)), clipped).boundingBox()); 289 if (clipped) 305 290 return contentRect; 306 291 // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds. -
trunk/Source/WebKit/chromium/ChangeLog
r113332 r113341 1 2012-04-05 Shawn Singh <shawnsingh@chromium.org> 2 3 [chromium] Need to clip to homogeneous w=0 plane when applying transforms. 4 https://bugs.webkit.org/show_bug.cgi?id=80806 5 6 Reviewed by Adrienne Walker. 7 8 * tests/CCLayerTreeHostCommonTest.cpp: 9 (WebKitTests::TEST): 10 (WebKitTests): 11 1 12 2012-04-05 Sheriff Bot <webkit.review.bot@gmail.com> 2 13 -
trunk/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp
r112436 r113341 33 33 #include "TranslateTransformOperation.h" 34 34 #include "cc/CCLayerAnimationController.h" 35 #include "cc/CCMathUtil.h" 35 36 36 37 #include <gmock/gmock.h> … … 980 981 } 981 982 983 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectForIdentityTransform) 984 { 985 // Test the calculateVisibleRect() function works correctly for identity transforms. 986 987 IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 988 TransformationMatrix layerToSurfaceTransform; 989 990 // Case 1: Layer is contained within the surface. 991 IntRect layerContentRect = IntRect(IntPoint(10, 10), IntSize(30, 30)); 992 IntRect expected = IntRect(IntPoint(10, 10), IntSize(30, 30)); 993 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 994 EXPECT_INT_RECT_EQ(expected, actual); 995 996 // Case 2: Layer is outside the surface rect. 997 layerContentRect = IntRect(IntPoint(120, 120), IntSize(30, 30)); 998 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 999 EXPECT_TRUE(actual.isEmpty()); 1000 1001 // Case 3: Layer is partially overlapping the surface rect. 1002 layerContentRect = IntRect(IntPoint(80, 80), IntSize(30, 30)); 1003 expected = IntRect(IntPoint(80, 80), IntSize(20, 20)); 1004 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1005 EXPECT_INT_RECT_EQ(expected, actual); 1006 } 1007 1008 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectForTranslations) 1009 { 1010 // Test the calculateVisibleRect() function works correctly for scaling transforms. 1011 1012 IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1013 IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(30, 30)); 1014 TransformationMatrix layerToSurfaceTransform; 1015 1016 // Case 1: Layer is contained within the surface. 1017 layerToSurfaceTransform.makeIdentity(); 1018 layerToSurfaceTransform.translate(10, 10); 1019 IntRect expected = IntRect(IntPoint(0, 0), IntSize(30, 30)); 1020 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1021 EXPECT_INT_RECT_EQ(expected, actual); 1022 1023 // Case 2: Layer is outside the surface rect. 1024 layerToSurfaceTransform.makeIdentity(); 1025 layerToSurfaceTransform.translate(120, 120); 1026 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1027 EXPECT_TRUE(actual.isEmpty()); 1028 1029 // Case 3: Layer is partially overlapping the surface rect. 1030 layerToSurfaceTransform.makeIdentity(); 1031 layerToSurfaceTransform.translate(80, 80); 1032 expected = IntRect(IntPoint(0, 0), IntSize(20, 20)); 1033 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1034 EXPECT_INT_RECT_EQ(expected, actual); 1035 } 1036 1037 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor2DRotations) 1038 { 1039 // Test the calculateVisibleRect() function works correctly for rotations about z-axis (i.e. 2D rotations). 1040 // Remember that calculateVisibleRect() should return the visible rect in the layer's space. 1041 1042 IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1043 IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(30, 30)); 1044 TransformationMatrix layerToSurfaceTransform; 1045 1046 // Case 1: Layer is contained within the surface. 1047 layerToSurfaceTransform.makeIdentity(); 1048 layerToSurfaceTransform.translate(50, 50); 1049 layerToSurfaceTransform.rotate(45); 1050 IntRect expected = IntRect(IntPoint(0, 0), IntSize(30, 30)); 1051 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1052 EXPECT_INT_RECT_EQ(expected, actual); 1053 1054 // Case 2: Layer is outside the surface rect. 1055 layerToSurfaceTransform.makeIdentity(); 1056 layerToSurfaceTransform.translate(-50, 0); 1057 layerToSurfaceTransform.rotate(45); 1058 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1059 EXPECT_TRUE(actual.isEmpty()); 1060 1061 // Case 3: The layer is rotated about its top-left corner. In surface space, the layer 1062 // is oriented diagonally, with the left half outside of the renderSurface. In 1063 // this case, the visible rect should still be the entire layer (remember the 1064 // visible rect is computed in layer space); both the top-left and 1065 // bottom-right corners of the layer are still visible. 1066 layerToSurfaceTransform.makeIdentity(); 1067 layerToSurfaceTransform.rotate(45); 1068 expected = IntRect(IntPoint(0, 0), IntSize(30, 30)); 1069 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1070 EXPECT_INT_RECT_EQ(expected, actual); 1071 1072 // Case 4: The layer is rotated about its top-left corner, and translated upwards. In 1073 // surface space, the layer is oriented diagonally, with only the top corner 1074 // of the surface overlapping the layer. In layer space, the render surface 1075 // overlaps the right side of the layer. The visible rect should be the 1076 // layer's right half. 1077 layerToSurfaceTransform.makeIdentity(); 1078 layerToSurfaceTransform.translate(0, -sqrt(2) * 15); 1079 layerToSurfaceTransform.rotate(45); 1080 expected = IntRect(IntPoint(15, 0), IntSize(15, 30)); // right half of layer bounds. 1081 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1082 EXPECT_INT_RECT_EQ(expected, actual); 1083 } 1084 1085 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dOrthographicTransform) 1086 { 1087 // Test that the calculateVisibleRect() function works correctly for 3d transforms. 1088 1089 IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1090 IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1091 TransformationMatrix layerToSurfaceTransform; 1092 1093 // Case 1: Orthographic projection of a layer rotated about y-axis by 45 degrees, should be fully contained in the renderSurface. 1094 layerToSurfaceTransform.makeIdentity(); 1095 layerToSurfaceTransform.rotate3d(0, 45, 0); 1096 IntRect expected = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1097 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1098 EXPECT_INT_RECT_EQ(expected, actual); 1099 1100 // Case 2: Orthographic projection of a layer rotated about y-axis by 45 degrees, but 1101 // shifted to the side so only the right-half the layer would be visible on 1102 // the surface. 1103 double halfWidthOfRotatedLayer = (100.0 / sqrt(2)) * 0.5; // 100.0 is the un-rotated layer width; divided by sqrt(2) is the rotated width. 1104 layerToSurfaceTransform.makeIdentity(); 1105 layerToSurfaceTransform.translate(-halfWidthOfRotatedLayer, 0); 1106 layerToSurfaceTransform.rotate3d(0, 45, 0); // rotates about the left edge of the layer 1107 expected = IntRect(IntPoint(50, 0), IntSize(50, 100)); // right half of the layer. 1108 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1109 EXPECT_INT_RECT_EQ(expected, actual); 1110 } 1111 1112 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dPerspectiveTransform) 1113 { 1114 // Test the calculateVisibleRect() function works correctly when the layer has a 1115 // perspective projection onto the target surface. 1116 1117 IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1118 IntRect layerContentRect = IntRect(IntPoint(-50, -50), IntSize(200, 200)); 1119 TransformationMatrix layerToSurfaceTransform; 1120 1121 // Case 1: Even though the layer is twice as large as the surface, due to perspective 1122 // foreshortening, the layer will fit fully in the surface when its translated 1123 // more than the perspective amount. 1124 layerToSurfaceTransform.makeIdentity(); 1125 1126 // The following sequence of transforms applies the perspective about the center of the surface. 1127 layerToSurfaceTransform.translate(50, 50); 1128 layerToSurfaceTransform.applyPerspective(9); 1129 layerToSurfaceTransform.translate(-50, -50); 1130 1131 // This translate places the layer in front of the surface's projection plane. 1132 layerToSurfaceTransform.translate3d(0, 0, -27); 1133 1134 IntRect expected = IntRect(IntPoint(-50, -50), IntSize(200, 200)); 1135 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1136 EXPECT_INT_RECT_EQ(expected, actual); 1137 1138 // Case 2: same projection as before, except that the layer is also translated to the 1139 // side, so that only the right half of the layer should be visible. 1140 // 1141 // Explanation of expected result: 1142 // The perspective ratio is (z distance between layer and camera origin) / (z distance between projection plane and camera origin) == ((-27 - 9) / 9) 1143 // Then, by similar triangles, if we want to move a layer by translating -50 units in projected surface units (so that only half of it is 1144 // visible), then we would need to translate by (-36 / 9) * -50 == -200 in the layer's units. 1145 // 1146 layerToSurfaceTransform.translate3d(-200, 0, 0); 1147 expected = IntRect(IntPoint(50, -50), IntSize(100, 200)); // The right half of the layer's bounding rect. 1148 actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1149 EXPECT_INT_RECT_EQ(expected, actual); 1150 } 1151 1152 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dOrthographicIsNotClippedBehindSurface) 1153 { 1154 // There is currently no explicit concept of an orthographic projection plane in our 1155 // code (nor in the CSS spec to my knowledge). Therefore, layers that are technically 1156 // behind the surface in an orthographic world should not be clipped when they are 1157 // flattened to the surface. 1158 1159 IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1160 IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1161 TransformationMatrix layerToSurfaceTransform; 1162 1163 // This sequence of transforms effectively rotates the layer about the y-axis at the 1164 // center of the layer. 1165 layerToSurfaceTransform.makeIdentity(); 1166 layerToSurfaceTransform.translate(50, 0); 1167 layerToSurfaceTransform.rotate3d(0, 45, 0); 1168 layerToSurfaceTransform.translate(-50, 0); 1169 1170 IntRect expected = IntRect(IntPoint(0, 0), IntSize(100, 100)); 1171 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1172 EXPECT_INT_RECT_EQ(expected, actual); 1173 } 1174 1175 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dPerspectiveIsClipped) 1176 { 1177 // Test the calculateVisibleRect() function works correctly when projecting a surface 1178 // onto a layer, but the layer is partially behind the camera (not just behind the 1179 // projection plane). In this case, the cartesian coordinates may seem to be valid, 1180 // but actually they are not. The visibleRect needs to be properly clipped by the 1181 // w = 0 plane in homogeneous coordinates before converting to cartesian coordinates. 1182 1183 IntRect targetSurfaceRect = IntRect(IntPoint(-50, -50), IntSize(100, 100)); 1184 IntRect layerContentRect = IntRect(IntPoint(-10, -1), IntSize(20, 2)); 1185 TransformationMatrix layerToSurfaceTransform; 1186 1187 // The layer is positioned so that the right half of the layer should be in front of 1188 // the camera, while the other half is behind the surface's projection plane. The 1189 // following sequence of transforms applies the perspective and rotation about the 1190 // center of the layer. 1191 layerToSurfaceTransform.makeIdentity(); 1192 layerToSurfaceTransform.applyPerspective(1); 1193 layerToSurfaceTransform.translate3d(0, 0, 1); 1194 layerToSurfaceTransform.rotate3d(0, 45, 0); 1195 1196 // Sanity check that this transform does indeed cause w < 0 when applying the 1197 // transform, otherwise this code is not testing the intended scenario. 1198 bool clipped = false; 1199 CCMathUtil::mapQuad(layerToSurfaceTransform, FloatQuad(FloatRect(layerContentRect)), clipped); 1200 ASSERT_TRUE(clipped); 1201 1202 int expectedXPosition = -10; 1203 int expectedWidth = 10; 1204 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1205 EXPECT_EQ(expectedXPosition, actual.x()); 1206 EXPECT_EQ(expectedWidth, actual.width()); 1207 } 1208 1209 TEST(CCLayerTreeHostCommonTest, verifyVisibleRectForPerspectiveUnprojection) 1210 { 1211 // To determine visibleRect in layer space, there needs to be an un-projection from 1212 // surface space to layer space. When the original transform was a perspective 1213 // projection that was clipped, it returns a rect that encloses the clipped bounds. 1214 // Un-projecting this new rect may require clipping again. 1215 1216 // This sequence of transforms causes one corner of the layer to protrude across the w = 0 plane, and should be clipped. 1217 IntRect targetSurfaceRect = IntRect(IntPoint(-50, -50), IntSize(100, 100)); 1218 IntRect layerContentRect = IntRect(IntPoint(-10, -10), IntSize(20, 20)); 1219 TransformationMatrix layerToSurfaceTransform; 1220 layerToSurfaceTransform.makeIdentity(); 1221 layerToSurfaceTransform.applyPerspective(1); 1222 layerToSurfaceTransform.translate3d(0, 0, -5); 1223 layerToSurfaceTransform.rotate3d(0, 45, 0); 1224 layerToSurfaceTransform.rotate3d(80, 0, 0); 1225 1226 // Sanity check that un-projection does indeed cause w < 0, otherwise this code is not 1227 // testing the intended scenario. 1228 bool clipped = false; 1229 FloatRect clippedRect = CCMathUtil::mapClippedRect(layerToSurfaceTransform, layerContentRect); 1230 CCMathUtil::projectQuad(layerToSurfaceTransform.inverse(), FloatQuad(clippedRect), clipped); 1231 ASSERT_TRUE(clipped); 1232 1233 // Only the corner of the layer is not visible on the surface because of being 1234 // clipped. But, the net result of rounding visible region to an axis-aligned rect is 1235 // that the entire layer should still be considered visible. 1236 IntRect expected = IntRect(IntPoint(-10, -10), IntSize(20, 20)); 1237 IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); 1238 EXPECT_INT_RECT_EQ(expected, actual); 1239 } 1240 982 1241 // FIXME: 983 1242 // continue working on https://bugs.webkit.org/show_bug.cgi?id=68942
Note: See TracChangeset
for help on using the changeset viewer.