bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext& context, const AffineTransform& animatedLocalTransform, const FloatRect& objectBoundingBox) { // If the current clip-path gets clipped itself, we have to fallback to masking. if (!style().svgStyle().clipperResource().isEmpty()) return false; WindRule clipRule = RULE_NONZERO; Path clipPath = Path(); // If clip-path only contains one visible shape or path, we can use path-based clipping. Invisible // shapes don't affect the clipping and can be ignored. If clip-path contains more than one // visible shape, the additive clipping may not work, caused by the clipRule. EvenOdd // as well as NonZero can cause self-clipping of the elements. // See also http://www.w3.org/TR/SVG/painting.html#FillRuleProperty for (Node* childNode = clipPathElement().firstChild(); childNode; childNode = childNode->nextSibling()) { RenderObject* renderer = childNode->renderer(); if (!renderer) continue; // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts. if (renderer->isSVGText()) return false; if (!childNode->isSVGElement() || !downcast<SVGElement>(*childNode).isSVGGraphicsElement()) continue; SVGGraphicsElement& styled = downcast<SVGGraphicsElement>(*childNode); const RenderStyle& style = renderer->style(); if (style.display() == NONE || style.visibility() != VISIBLE) continue; const SVGRenderStyle& svgStyle = style.svgStyle(); // Current shape in clip-path gets clipped too. Fallback to masking. if (!svgStyle.clipperResource().isEmpty()) return false; // Fallback to masking, if there is more than one clipping path. if (clipPath.isEmpty()) { styled.toClipPath(clipPath); clipRule = svgStyle.clipRule(); } else return false; } // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary. if (clipPathElement().clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); clipPath.transform(transform); } // Transform path by animatedLocalTransform. clipPath.transform(animatedLocalTransform); // The SVG specification wants us to clip everything, if clip-path doesn't have a child. if (clipPath.isEmpty()) clipPath.addRect(FloatRect()); context.clipPath(clipPath, clipRule); return true; }
void BeginClipPathDisplayItem::replay(GraphicsContext& context) const { context.save(); context.clipPath(m_clipPath, AntiAliased); }
void ClipPath::apply(GraphicsContext& context) const { context.clipPath(m_path, m_windRule); }