PassRefPtr<DisplayList> RenderSVGResourcePattern::asDisplayList(const FloatRect& tileBounds,
    const AffineTransform& tileTransform) const
{
    ASSERT(!m_shouldCollectPatternAttributes);

    AffineTransform contentTransform;
    if (m_attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
        contentTransform = tileTransform;

    // Draw the content into a DisplayList.
    GraphicsContext recordingContext(nullptr);
    recordingContext.beginRecording(FloatRect(FloatPoint(), tileBounds.size()));
    recordingContext.concatCTM(tileTransform);

    ASSERT(m_attributes.patternContentElement());
    RenderSVGResourceContainer* patternRenderer =
        toRenderSVGResourceContainer(m_attributes.patternContentElement()->renderer());
    ASSERT(patternRenderer);
    ASSERT(!patternRenderer->needsLayout());

    SubtreeContentTransformScope contentTransformScope(contentTransform);
    for (RenderObject* child = patternRenderer->firstChild(); child; child = child->nextSibling())
        SVGRenderingContext::renderSubtree(&recordingContext, child);

    return recordingContext.endRecording();
}
PassRefPtr<SkPicture> LayoutSVGResourcePattern::asPicture(const FloatRect& tileBounds,
    const AffineTransform& tileTransform) const
{
    ASSERT(!m_shouldCollectPatternAttributes);

    AffineTransform contentTransform;
    if (attributes().patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
        contentTransform = tileTransform;

    FloatRect bounds(FloatPoint(), tileBounds.size());
    SkPictureBuilder pictureBuilder(bounds);

    const LayoutSVGResourceContainer* patternLayoutObject = resolveContentElement();
    ASSERT(patternLayoutObject && !patternLayoutObject->needsLayout());

    SubtreeContentTransformScope contentTransformScope(contentTransform);

    {
        TransformRecorder transformRecorder(pictureBuilder.context(), *patternLayoutObject, tileTransform);
        for (LayoutObject* child = patternLayoutObject->firstChild(); child; child = child->nextSibling())
            SVGPaintContext::paintSubtree(pictureBuilder.context(), child);
    }

    return pictureBuilder.endRecording();
}
sk_sp<const SkPicture> LayoutSVGResourceMasker::createContentPicture(
    AffineTransform& contentTransformation,
    const FloatRect& targetBoundingBox,
    GraphicsContext& context) {
    SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())
            ->maskContentUnits()
            ->currentValue()
            ->enumValue();
    if (contentUnits == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
        contentTransformation.translate(targetBoundingBox.x(),
                                        targetBoundingBox.y());
        contentTransformation.scaleNonUniform(targetBoundingBox.width(),
                                              targetBoundingBox.height());
    }

    if (m_maskContentPicture)
        return m_maskContentPicture;

    SubtreeContentTransformScope contentTransformScope(contentTransformation);

    // Using strokeBoundingBox instead of visualRectInLocalCoordinates
    // to avoid the intersection with local clips/mask, which may yield incorrect
    // results when mixing objectBoundingBox and userSpaceOnUse units.
    // http://crbug.com/294900
    FloatRect bounds = strokeBoundingBox();

    SkPictureBuilder pictureBuilder(bounds, nullptr, &context);

    ColorFilter maskContentFilter =
        style()->svgStyle().colorInterpolation() == CI_LINEARRGB
        ? ColorFilterSRGBToLinearRGB
        : ColorFilterNone;
    pictureBuilder.context().setColorFilter(maskContentFilter);

    for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element());
            childElement;
            childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
        LayoutObject* layoutObject = childElement->layoutObject();
        if (!layoutObject)
            continue;
        const ComputedStyle* style = layoutObject->style();
        if (!style || style->display() == EDisplay::None ||
                style->visibility() != EVisibility::Visible)
            continue;

        SVGPaintContext::paintSubtree(pictureBuilder.context(), layoutObject);
    }

    m_maskContentPicture = pictureBuilder.endRecording();
    return m_maskContentPicture;
}
Example #4
0
bool SVGClipPainter::drawClipAsMask(
    GraphicsContext& context,
    const LayoutObject& layoutObject,
    const FloatRect& targetBoundingBox,
    const FloatRect& targetPaintInvalidationRect,
    const AffineTransform& localTransform,
    const FloatPoint& layerPositionOffset) {
  if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(
          context, layoutObject, DisplayItem::kSVGClip))
    return true;

  SkPictureBuilder maskPictureBuilder(targetPaintInvalidationRect, nullptr,
                                      &context);
  GraphicsContext& maskContext = maskPictureBuilder.context();
  {
    TransformRecorder recorder(maskContext, layoutObject, localTransform);

    // Apply any clip-path clipping this clipPath (nested shape/clipPath.)
    Optional<ClipPathClipper> nestedClipPathClipper;
    if (ClipPathOperation* clipPathOperation = m_clip.styleRef().clipPath())
      nestedClipPathClipper.emplace(maskContext, *clipPathOperation, m_clip,
                                    targetBoundingBox, layerPositionOffset);

    {
      AffineTransform contentTransform;
      if (m_clip.clipPathUnits() ==
          SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
        contentTransform.translate(targetBoundingBox.x(),
                                   targetBoundingBox.y());
        contentTransform.scaleNonUniform(targetBoundingBox.width(),
                                         targetBoundingBox.height());
      }
      SubtreeContentTransformScope contentTransformScope(contentTransform);

      TransformRecorder contentTransformRecorder(maskContext, layoutObject,
                                                 contentTransform);
      maskContext.getPaintController().createAndAppend<DrawingDisplayItem>(
          layoutObject, DisplayItem::kSVGClip, m_clip.createContentPicture());
    }
  }

  LayoutObjectDrawingRecorder drawingRecorder(context, layoutObject,
                                              DisplayItem::kSVGClip,
                                              targetPaintInvalidationRect);
  sk_sp<SkPicture> maskPicture = maskPictureBuilder.endRecording();
  context.drawPicture(maskPicture.get());
  return true;
}
void RenderSVGResourceClipper::drawClipMaskContent(GraphicsContext* context, const FloatRect& targetBoundingBox)
{
    ASSERT(context);

    AffineTransform contentTransformation;
    if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
        contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
        context->concatCTM(contentTransformation);
    }

    if (!m_clipContentPicture) {
        SubtreeContentTransformScope contentTransformScope(contentTransformation);
        createPicture(context);
    }

    context->drawPicture(m_clipContentPicture.get());
}
PassRefPtr<const SkPicture> LayoutSVGResourceMasker::createContentPicture(AffineTransform& contentTransformation, const FloatRect& targetBoundingBox)
{
    SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnits()->currentValue()->enumValue();
    if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
        contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
    }

    if (m_maskContentPicture)
        return m_maskContentPicture;

    SubtreeContentTransformScope contentTransformScope(contentTransformation);

    // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection
    // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and
    // userSpaceOnUse units (http://crbug.com/294900).
    FloatRect bounds = strokeBoundingBox();

    OwnPtr<DisplayItemList> displayItemList;
    if (RuntimeEnabledFeatures::slimmingPaintEnabled())
        displayItemList = DisplayItemList::create();
    GraphicsContext context(nullptr, displayItemList.get());
    context.beginRecording(bounds);

    ColorFilter maskContentFilter = style()->svgStyle().colorInterpolation() == CI_LINEARRGB
                                    ? ColorFilterSRGBToLinearRGB : ColorFilterNone;
    context.setColorFilter(maskContentFilter);

    for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
        LayoutObject* layoutObject = childElement->layoutObject();
        if (!layoutObject)
            continue;
        const ComputedStyle* style = layoutObject->style();
        if (!style || style->display() == NONE || style->visibility() != VISIBLE)
            continue;

        SVGPaintContext::paintSubtree(&context, layoutObject);
    }

    if (displayItemList)
        displayItemList->commitNewDisplayItemsAndReplay(context);
    m_maskContentPicture = context.endRecording();
    return m_maskContentPicture;
}
bool SVGClipPainter::drawClipAsMask(GraphicsContext& context, const LayoutObject& layoutObject, const FloatRect& targetBoundingBox, const FloatRect& targetPaintInvalidationRect, const AffineTransform& localTransform)
{
    if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, layoutObject, DisplayItem::SVGClip))
        return true;

    SkPictureBuilder maskPictureBuilder(targetPaintInvalidationRect, nullptr, &context);
    GraphicsContext& maskContext = maskPictureBuilder.context();
    {
        TransformRecorder recorder(maskContext, layoutObject, localTransform);

        // Create a clipPathClipper if this clipPath is clipped by another clipPath.
        SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_clip);
        LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : nullptr;
        ClipperState clipPathClipperState = ClipperNotApplied;
        if (clipPathClipper && !SVGClipPainter(*clipPathClipper).prepareEffect(m_clip, targetBoundingBox, targetPaintInvalidationRect, maskContext, clipPathClipperState))
            return false;

        {
            AffineTransform contentTransform;
            if (m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
                contentTransform.translate(targetBoundingBox.x(), targetBoundingBox.y());
                contentTransform.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
            }
            SubtreeContentTransformScope contentTransformScope(contentTransform);

            TransformRecorder contentTransformRecorder(maskContext, layoutObject, contentTransform);
            RefPtr<const SkPicture> clipContentPicture = m_clip.createContentPicture();
            maskContext.getPaintController().createAndAppend<DrawingDisplayItem>(layoutObject, DisplayItem::SVGClip, clipContentPicture.get());
        }

        if (clipPathClipper)
            SVGClipPainter(*clipPathClipper).finishEffect(m_clip, maskContext, clipPathClipperState);
    }

    LayoutObjectDrawingRecorder drawingRecorder(context, layoutObject, DisplayItem::SVGClip, targetPaintInvalidationRect);
    RefPtr<SkPicture> maskPicture = maskPictureBuilder.endRecording();
    context.drawPicture(maskPicture.get());
    return true;
}
PassRefPtr<const SkPicture> LayoutSVGResourceClipper::createContentPicture(AffineTransform& contentTransformation, const FloatRect& targetBoundingBox,
    GraphicsContext& context)
{
    ASSERT(frame());

    if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
        contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
    }

    if (m_clipContentPicture)
        return m_clipContentPicture;

    SubtreeContentTransformScope contentTransformScope(contentTransformation);

    // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection
    // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and
    // userSpaceOnUse units (http://crbug.com/294900).
    FloatRect bounds = strokeBoundingBox();

    SkPictureBuilder pictureBuilder(bounds, nullptr, &context);

    for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
        LayoutObject* layoutObject = childElement->layoutObject();
        if (!layoutObject)
            continue;

        const ComputedStyle* style = layoutObject->style();
        if (!style || style->display() == NONE || style->visibility() != VISIBLE)
            continue;

        bool isUseElement = isSVGUseElement(*childElement);
        if (isUseElement) {
            const SVGGraphicsElement* clippingElement = toSVGUseElement(*childElement).targetGraphicsElementForClipping();
            if (!clippingElement)
                continue;

            layoutObject = clippingElement->layoutObject();
            if (!layoutObject)
                continue;
        }

        // Only shapes, paths and texts are allowed for clipping.
        if (!layoutObject->isSVGShape() && !layoutObject->isSVGText())
            continue;

        if (isUseElement)
            layoutObject = childElement->layoutObject();

        // Switch to a paint behavior where all children of this <clipPath> will be laid out using special constraints:
        // - fill-opacity/stroke-opacity/opacity set to 1
        // - masker/filter not applied when laying out the children
        // - fill is set to the initial fill paint server (solid, black)
        // - stroke is set to the initial stroke paint server (none)
        PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), PaintPhaseForeground, GlobalPaintNormalPhase, PaintLayerPaintingRenderingClipPathAsMask);
        layoutObject->paint(info, IntPoint());
    }

    m_clipContentPicture = pictureBuilder.endRecording();
    return m_clipContentPicture;
}