static TransformationMatrix totalTransform(const TransformPaintPropertyNode* currentSpace) { TransformationMatrix matrix; for (; currentSpace; currentSpace = currentSpace->parent()) { TransformationMatrix localMatrix = currentSpace->matrix(); localMatrix.applyTransformOrigin(currentSpace->origin()); matrix = localMatrix * matrix; } return matrix; }
TEST(TransformationMatrixTest, ApplyTransformOrigin) { TransformationMatrix matrix; // (0,0,0) is a fixed point of this scale. // (1,1,1) should be scaled appropriately. matrix.scale3d(2, 3, 4); EXPECT_EQ(FloatPoint3D(0, 0, 0), matrix.mapPoint(FloatPoint3D(0, 0, 0))); EXPECT_EQ(FloatPoint3D(2, 3, -4), matrix.mapPoint(FloatPoint3D(1, 1, -1))); // With the transform origin applied, (1,2,3) is the fixed point. // (0,0,0) should be scaled according to its distance from (1,2,3). matrix.applyTransformOrigin(1, 2, 3); EXPECT_EQ(FloatPoint3D(1, 2, 3), matrix.mapPoint(FloatPoint3D(1, 2, 3))); EXPECT_EQ(FloatPoint3D(-1, -4, -9), matrix.mapPoint(FloatPoint3D(0, 0, 0))); }
TEST_F(PaintPropertyTreeBuilderTest, TransformNodesInSVG) { setBodyInnerHTML( "<style>" " body {" " margin: 0px;" " }" " svg {" " margin-left: 50px;" " transform: translate3d(1px, 2px, 3px);" " position: absolute;" " left: 20px;" " top: 25px;" " }" " rect {" " transform: translate(100px, 100px) rotate(45deg);" " transform-origin: 50px 25px;" " }" "</style>" "<svg id='svgRootWith3dTransform' width='100px' height='100px'>" " <rect id='rectWith2dTransform' width='100px' height='100px' />" "</svg>"); LayoutObject& svgRootWith3dTransform = *document().getElementById("svgRootWith3dTransform")->layoutObject(); ObjectPaintProperties* svgRootWith3dTransformProperties = svgRootWith3dTransform.objectPaintProperties(); EXPECT_EQ(TransformationMatrix().translate3d(1, 2, 3), svgRootWith3dTransformProperties->transform()->matrix()); EXPECT_EQ(FloatPoint3D(50, 50, 0), svgRootWith3dTransformProperties->transform()->origin()); EXPECT_EQ(svgRootWith3dTransformProperties->paintOffsetTranslation(), svgRootWith3dTransformProperties->transform()->parent()); EXPECT_EQ(TransformationMatrix().translate(70, 25), svgRootWith3dTransformProperties->paintOffsetTranslation()->matrix()); EXPECT_EQ(document().view()->scrollTranslation(), svgRootWith3dTransformProperties->paintOffsetTranslation()->parent()); LayoutObject& rectWith2dTransform = *document().getElementById("rectWith2dTransform")->layoutObject(); ObjectPaintProperties* rectWith2dTransformProperties = rectWith2dTransform.objectPaintProperties(); TransformationMatrix matrix; matrix.translate(100, 100); matrix.rotate(45); // SVG's transform origin is baked into the transform. matrix.applyTransformOrigin(50, 25, 0); EXPECT_EQ(matrix, rectWith2dTransformProperties->transform()->matrix()); EXPECT_EQ(FloatPoint3D(0, 0, 0), rectWith2dTransformProperties->transform()->origin()); // SVG does not use paint offset. EXPECT_EQ(nullptr, rectWith2dTransformProperties->paintOffsetTranslation()); }