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();
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 6
0
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();
}