void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    if (object.isBoxModelObject()) {
        // TODO(trchen): Eliminate PaintLayer dependency.
        PaintLayer* layer = toLayoutBoxModelObject(object).layer();
        if (!layer || !layer->paintsWithTransform(GlobalPaintNormalPhase))
            return;
    }

    if (context.paintOffset == LayoutPoint())
        return;

    // We should use the same subpixel paint offset values for snapping regardless of whether a
    // transform is present. If there is a transform we round the paint offset but keep around
    // the residual fractional component for the transformed content to paint with.
    // In spv1 this was called "subpixel accumulation". For more information, see
    // PaintLayer::subpixelAccumulation() and PaintLayerPainter::paintFragmentByApplyingTransform.
    IntPoint roundedPaintOffset = roundedIntPoint(context.paintOffset);
    LayoutPoint fractionalPaintOffset = LayoutPoint(context.paintOffset - roundedPaintOffset);

    RefPtr<TransformPaintPropertyNode> paintOffsetTranslation = TransformPaintPropertyNode::create(
        TransformationMatrix().translate(roundedPaintOffset.x(), roundedPaintOffset.y()),
        FloatPoint3D(), context.currentTransform);
    context.currentTransform = paintOffsetTranslation.get();
    context.paintOffset = fractionalPaintOffset;
    object.getMutableForPainting().ensureObjectPaintProperties().setPaintOffsetTranslation(paintOffsetTranslation.release());
}
void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(
    const LayoutObject& object,
    PaintPropertyTreeBuilderContext& context) {
  bool usesPaintOffsetTranslation = false;
  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
      object.isLayoutView()) {
    // Root layer scrolling always creates a translation node for LayoutView to
    // ensure fixed and absolute contexts use the correct transform space.
    usesPaintOffsetTranslation = true;
  } else if (object.isBoxModelObject() &&
             context.current.paintOffset != LayoutPoint()) {
    // TODO(trchen): Eliminate PaintLayer dependency.
    PaintLayer* layer = toLayoutBoxModelObject(object).layer();
    if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase))
      usesPaintOffsetTranslation = true;
  }

  // We should use the same subpixel paint offset values for snapping
  // regardless of whether a transform is present. If there is a transform
  // we round the paint offset but keep around the residual fractional
  // component for the transformed content to paint with.  In spv1 this was
  // called "subpixel accumulation". For more information, see
  // PaintLayer::subpixelAccumulation() and
  // PaintLayerPainter::paintFragmentByApplyingTransform.
  IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
  LayoutPoint fractionalPaintOffset =
      LayoutPoint(context.current.paintOffset - roundedPaintOffset);

  if (usesPaintOffsetTranslation) {
    object.getMutableForPainting()
        .ensurePaintProperties()
        .updatePaintOffsetTranslation(
            context.current.transform,
            TransformationMatrix().translate(roundedPaintOffset.x(),
                                             roundedPaintOffset.y()),
            FloatPoint3D(), context.current.shouldFlattenInheritedTransform,
            context.current.renderingContextID);
  } else {
    if (auto* properties = object.getMutableForPainting().paintProperties())
      properties->clearPaintOffsetTranslation();
  }

  const auto* properties = object.paintProperties();
  if (properties && properties->paintOffsetTranslation()) {
    context.current.transform = properties->paintOffsetTranslation();
    context.current.paintOffset = fractionalPaintOffset;
    if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
        object.isLayoutView()) {
      context.absolutePosition.transform = properties->paintOffsetTranslation();
      context.fixedPosition.transform = properties->paintOffsetTranslation();
      context.absolutePosition.paintOffset = LayoutPoint();
      context.fixedPosition.paintOffset = LayoutPoint();
    }
  }
}
void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(
    const LayoutObject& object,
    PaintPropertyTreeBuilderContext& context) {
  if (object.isBoxModelObject() &&
      context.current.paintOffset != LayoutPoint()) {
    // TODO(trchen): Eliminate PaintLayer dependency.
    PaintLayer* layer = toLayoutBoxModelObject(object).layer();
    if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase)) {
      // We should use the same subpixel paint offset values for snapping
      // regardless of whether a transform is present. If there is a transform
      // we round the paint offset but keep around the residual fractional
      // component for the transformed content to paint with.  In spv1 this was
      // called "subpixel accumulation". For more information, see
      // PaintLayer::subpixelAccumulation() and
      // PaintLayerPainter::paintFragmentByApplyingTransform.
      IntPoint roundedPaintOffset =
          roundedIntPoint(context.current.paintOffset);
      LayoutPoint fractionalPaintOffset =
          LayoutPoint(context.current.paintOffset - roundedPaintOffset);

      context.current.transform =
          object.getMutableForPainting()
              .ensurePaintProperties()
              .updatePaintOffsetTranslation(
                  context.current.transform,
                  TransformationMatrix().translate(roundedPaintOffset.x(),
                                                   roundedPaintOffset.y()),
                  FloatPoint3D(),
                  context.current.shouldFlattenInheritedTransform,
                  context.current.renderingContextID);
      context.current.paintOffset = fractionalPaintOffset;
      return;
    }
  }

  if (object.isLayoutView())
    return;

  if (auto* properties = object.getMutableForPainting().paintProperties())
    properties->clearPaintOffsetTranslation();
}
static PassRefPtr<TransformPaintPropertyNode> createPaintOffsetTranslationIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
{
    bool shouldCreatePaintOffsetTranslationNode = false;
    if (object.isSVGRoot()) {
        // SVG doesn't use paint offset internally so emit a paint offset at the html->svg boundary.
        shouldCreatePaintOffsetTranslationNode = true;
    } else if (object.isBoxModelObject()) {
        // TODO(trchen): Eliminate PaintLayer dependency.
        PaintLayer* layer = toLayoutBoxModelObject(object).layer();
        shouldCreatePaintOffsetTranslationNode = layer && layer->paintsWithTransform(GlobalPaintNormalPhase);
    }

    if (context.paintOffset == LayoutPoint() || !shouldCreatePaintOffsetTranslationNode)
        return nullptr;

    RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = TransformPaintPropertyNode::create(
        TransformationMatrix().translate(context.paintOffset.x(), context.paintOffset.y()),
        FloatPoint3D(), context.currentTransform);
    context.currentTransform = newTransformNodeForPaintOffsetTranslation.get();
    context.paintOffset = LayoutPoint();
    return newTransformNodeForPaintOffsetTranslation.release();
}