bool RenderSVGResourceClipper::drawContentIntoMaskImage(const ClipperMaskImage& clipperMaskImage, const FloatRect& objectBoundingBox) { ASSERT(clipperMaskImage); GraphicsContext& maskContext = clipperMaskImage->context(); AffineTransform maskContentTransformation; if (clipPathElement().clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y()); maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); maskContext.concatCTM(maskContentTransformation); } // Switch to a paint behavior where all children of this <clipPath> will be rendered using special constraints: // - fill-opacity/stroke-opacity/opacity set to 1 // - masker/filter not applied when rendering the children // - fill is set to the initial fill paint server (solid, black) // - stroke is set to the initial stroke paint server (none) PaintBehavior oldBehavior = view().frameView().paintBehavior(); view().frameView().setPaintBehavior(oldBehavior | PaintBehaviorRenderingSVGMask); // Draw all clipPath children into a global mask. for (auto& child : childrenOfType<SVGElement>(clipPathElement())) { auto renderer = child.renderer(); if (!renderer) continue; if (renderer->needsLayout()) { view().frameView().setPaintBehavior(oldBehavior); return false; } const RenderStyle& style = renderer->style(); if (style.display() == NONE || style.visibility() != VISIBLE) continue; WindRule newClipRule = style.svgStyle().clipRule(); bool isUseElement = child.hasTagName(SVGNames::useTag); if (isUseElement) { SVGUseElement& useElement = downcast<SVGUseElement>(child); renderer = useElement.rendererClipChild(); if (!renderer) continue; if (!useElement.hasAttributeWithoutSynchronization(SVGNames::clip_ruleAttr)) newClipRule = renderer->style().svgStyle().clipRule(); } // Only shapes, paths and texts are allowed for clipping. if (!renderer->isSVGShape() && !renderer->isSVGText()) continue; maskContext.setFillRule(newClipRule); // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule. // We have to pass the <use> renderer itself to renderSubtreeToImageBuffer() to apply it's x/y/transform/etc. values when rendering. // So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above. SVGRenderingContext::renderSubtreeToImageBuffer(clipperMaskImage.get(), isUseElement ? *child.renderer() : *renderer, maskContentTransformation); } view().frameView().setPaintBehavior(oldBehavior); return true; }
RenderPtr<RenderText> Text::createTextRenderer(const RenderStyle& style) { if (isSVGText(this) || isSVGShadowText(this)) return createRenderer<RenderSVGInlineText>(*this, data()); if (style.hasTextCombine()) return createRenderer<RenderCombineText>(*this, data()); return createRenderer<RenderText>(*this, data()); }
LayoutText* Text::createTextLayoutObject(const ComputedStyle& style) { if (isSVGText(this)) return new LayoutSVGInlineText(this, dataImpl()); if (style.hasTextCombine()) return new LayoutTextCombine(this, dataImpl()); return new LayoutText(this, dataImpl()); }
RenderText* Text::createTextRenderer(RenderStyle* style) { if (isSVGText(this)) return new RenderSVGInlineText(this, dataImpl()); if (style->hasTextCombine()) return new RenderCombineText(this, dataImpl()); return new RenderText(this, dataImpl()); }
RenderText* Text::createTextRenderer(RenderArena* arena, RenderStyle* style) { #if ENABLE(SVG) if (isSVGText(this) || isSVGShadowText(this)) return new (arena) RenderSVGInlineText(this, dataImpl()); #endif if (style->hasTextCombine()) return new (arena) RenderCombineText(this, dataImpl()); return new (arena) RenderText(this, dataImpl()); }