static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { if (object.isSVG() && !object.isSVGRoot()) { const AffineTransform& transform = object.localToParentTransform(); if (transform.isIdentity()) return nullptr; // SVG's transform origin is baked into the localToParentTransform. RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformPaintPropertyNode::create( transform, FloatPoint3D(0, 0, 0), context.currentTransform); context.currentTransform = newTransformNodeForTransform.get(); return newTransformNodeForTransform.release(); } const ComputedStyle& style = object.styleRef(); if (!object.isBox() || !style.hasTransform()) return nullptr; ASSERT(context.paintOffset == LayoutPoint()); TransformationMatrix matrix; style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformPaintPropertyNode::create( matrix, transformOrigin(toLayoutBox(object)), context.currentTransform); context.currentTransform = newTransformNodeForTransform.get(); return newTransformNodeForTransform.release(); }
void PaintPropertyTreeBuilder::updateTransform(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { if (object.isSVG() && !object.isSVGRoot()) { // SVG does not use paint offset internally. DCHECK(context.paintOffset == LayoutPoint()); // FIXME(pdr): Check for the presence of a transform instead of the value. Checking for an // identity matrix will cause the property tree structure to change during animations if // the animation passes through the identity matrix. // FIXME(pdr): Refactor this so all non-root SVG objects use the same transform function. const AffineTransform& transform = object.isSVGForeignObject() ? object.localSVGTransform() : object.localToSVGParentTransform(); if (transform.isIdentity()) return; // The origin is included in the local transform, so use an empty origin. RefPtr<TransformPaintPropertyNode> svgTransform = TransformPaintPropertyNode::create( transform, FloatPoint3D(0, 0, 0), context.currentTransform); context.currentTransform = svgTransform.get(); object.getMutableForPainting().ensureObjectPaintProperties().setTransform(svgTransform.release()); return; } const ComputedStyle& style = object.styleRef(); if (!object.isBox() || !style.hasTransform()) return; TransformationMatrix matrix; style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); RefPtr<TransformPaintPropertyNode> transformNode = TransformPaintPropertyNode::create( matrix, transformOrigin(toLayoutBox(object)), context.currentTransform); context.currentTransform = transformNode.get(); object.getMutableForPainting().ensureObjectPaintProperties().setTransform(transformNode.release()); }
static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context) { const ComputedStyle& style = object.styleRef(); if (!object.isBox() || !style.hasTransform()) return nullptr; ASSERT(context.paintOffset == LayoutPoint()); TransformationMatrix matrix; style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformPaintPropertyNode::create( matrix, transformOrigin(toLayoutBox(object)), context.currentTransform); context.currentTransform = newTransformNodeForTransform.get(); return newTransformNodeForTransform.release(); }
void PaintPropertyTreeBuilder::updateTransform( const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { if (object.isSVG() && !object.isSVGRoot()) { updateTransformForNonRootSVG(object, context); return; } const ComputedStyle& style = object.styleRef(); if (object.isBox() && (style.hasTransform() || style.preserves3D())) { TransformationMatrix matrix; style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); // TODO(trchen): transform-style should only be respected if a PaintLayer // is created. // If a node with transform-style: preserve-3d does not exist in an // existing rendering context, it establishes a new one. unsigned renderingContextID = context.current.renderingContextID; if (style.preserves3D() && !renderingContextID) renderingContextID = PtrHash<const LayoutObject>::hash(&object); object.getMutableForPainting().ensurePaintProperties().updateTransform( context.current.transform, matrix, transformOrigin(toLayoutBox(object)), context.current.shouldFlattenInheritedTransform, renderingContextID); } else { if (auto* properties = object.getMutableForPainting().paintProperties()) properties->clearTransform(); } const auto* properties = object.paintProperties(); if (properties && properties->transform()) { context.current.transform = properties->transform(); if (object.styleRef().preserves3D()) { context.current.renderingContextID = properties->transform()->renderingContextID(); context.current.shouldFlattenInheritedTransform = false; } else { context.current.renderingContextID = 0; context.current.shouldFlattenInheritedTransform = true; } } }
TEST_F(DisplayItemPropertyTreeBuilderTest, TransformTreeIncludesTransformOrigin) { FloatPoint3D transformOrigin(1, 2, 3); TransformationMatrix matrix; matrix.scale3d(2, 2, 2); auto transformClient = processBeginTransform3D(matrix, transformOrigin); processDummyDisplayItem(); processEndTransform3D(transformClient); finishPropertyTrees(); // There should be two transform nodes. ASSERT_EQ(2u, transformTree().nodeCount()); EXPECT_TRUE(transformTree().nodeAt(0).isRoot()); // And the non-root node should have both the matrix and the origin, // separately. const auto& transformNode = transformTree().nodeAt(1); EXPECT_EQ(0u, transformNode.parentNodeIndex); EXPECT_EQ(TransformationMatrix::toSkMatrix44(matrix), transformNode.matrix); EXPECT_EQ(transformOrigin, transformNode.transformOrigin); }
void PaintPropertyTreeBuilder::updateTransform( const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { if (object.isSVG() && !object.isSVGRoot()) { // SVG (other than SVGForeignObject) does not use paint offset internally. DCHECK(object.isSVGForeignObject() || context.current.paintOffset == LayoutPoint()); // FIXME(pdr): Check for the presence of a transform instead of the value. // Checking for an identity matrix will cause the property tree structure to // change during animations if the animation passes through the identity // matrix. // FIXME(pdr): Refactor this so all non-root SVG objects use the same // transform function. const AffineTransform& transform = object.isSVGForeignObject() ? object.localSVGTransform() : object.localToSVGParentTransform(); if (!transform.isIdentity()) { // The origin is included in the local transform, so leave origin empty. context.current.transform = object.getMutableForPainting() .ensurePaintProperties() .updateTransform(context.current.transform, TransformationMatrix(transform), FloatPoint3D()); context.current.renderingContextID = 0; context.current.shouldFlattenInheritedTransform = false; return; } } else { const ComputedStyle& style = object.styleRef(); if (object.isBox() && (style.hasTransform() || style.preserves3D())) { TransformationMatrix matrix; style.applyTransform( matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); FloatPoint3D origin = transformOrigin(toLayoutBox(object)); unsigned renderingContextID = context.current.renderingContextID; unsigned renderingContextIDForChildren = 0; bool flattensInheritedTransform = context.current.shouldFlattenInheritedTransform; bool childrenFlattenInheritedTransform = true; // TODO(trchen): transform-style should only be respected if a PaintLayer // is created. if (style.preserves3D()) { // If a node with transform-style: preserve-3d does not exist in an // existing rendering context, it establishes a new one. if (!renderingContextID) renderingContextID = PtrHash<const LayoutObject>::hash(&object); renderingContextIDForChildren = renderingContextID; childrenFlattenInheritedTransform = false; } context.current.transform = object.getMutableForPainting() .ensurePaintProperties() .updateTransform(context.current.transform, matrix, origin, flattensInheritedTransform, renderingContextID); context.current.renderingContextID = renderingContextIDForChildren; context.current.shouldFlattenInheritedTransform = childrenFlattenInheritedTransform; return; } } if (auto* properties = object.getMutableForPainting().paintProperties()) properties->clearTransform(); }