diff options
Diffstat (limited to 'Source/WebCore/rendering/svg/RenderSVGShape.cpp')
-rw-r--r-- | Source/WebCore/rendering/svg/RenderSVGShape.cpp | 144 |
1 files changed, 79 insertions, 65 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.cpp b/Source/WebCore/rendering/svg/RenderSVGShape.cpp index b93a028b5..d46734084 100644 --- a/Source/WebCore/rendering/svg/RenderSVGShape.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGShape.cpp @@ -26,8 +26,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGShape.h" #include "FloatPoint.h" @@ -42,7 +40,6 @@ #include "SVGRenderingContext.h" #include "SVGResources.h" #include "SVGResourcesCache.h" -#include "SVGTransformList.h" #include "SVGURIReference.h" #include "StrokeStyleApplier.h" #include <wtf/StackStats.h> @@ -56,7 +53,7 @@ public: { } - virtual void strokeStyle(GraphicsContext* context) override + void strokeStyle(GraphicsContext* context) override { SVGRenderSupport::applyStrokeStyleToContext(context, m_renderer.style(), m_renderer); } @@ -65,8 +62,8 @@ private: const RenderSVGShape& m_renderer; }; -RenderSVGShape::RenderSVGShape(SVGGraphicsElement& element, PassRef<RenderStyle> style) - : RenderSVGModelObject(element, std::move(style)) +RenderSVGShape::RenderSVGShape(SVGGraphicsElement& element, RenderStyle&& style) + : RenderSVGModelObject(element, WTFMove(style)) , m_needsBoundariesUpdate(false) // Default is false, the cached rects are empty from the beginning. , m_needsShapeUpdate(true) // Default is true, so we grab a Path object once from SVGGraphicsElement. , m_needsTransformUpdate(true) // Default is true, so we grab a AffineTransform object once from SVGGraphicsElement. @@ -79,8 +76,7 @@ RenderSVGShape::~RenderSVGShape() void RenderSVGShape::updateShapeFromElement() { - m_path.clear(); - m_path = adoptPtr(new Path); + m_path = std::make_unique<Path>(); ASSERT(RenderSVGShape::isEmpty()); updatePathFromGraphicsElement(&graphicsElement(), path()); @@ -92,15 +88,19 @@ void RenderSVGShape::updateShapeFromElement() bool RenderSVGShape::isEmpty() const { - return path().isEmpty(); + // This function should never be called before assigning a new Path to m_path. + // But this bug can happen if this renderer was created and its layout was not + // done before painting. Assert this did not happen but do not crash. + ASSERT(hasPath()); + return !hasPath() || path().isEmpty(); } -void RenderSVGShape::fillShape(GraphicsContext* context) const +void RenderSVGShape::fillShape(GraphicsContext& context) const { - context->fillPath(path()); + context.fillPath(path()); } -void RenderSVGShape::strokeShape(GraphicsContext* context) const +void RenderSVGShape::strokeShape(GraphicsContext& context) const { ASSERT(m_path); Path* usePath = m_path.get(); @@ -108,7 +108,7 @@ void RenderSVGShape::strokeShape(GraphicsContext* context) const if (hasNonScalingStroke()) usePath = nonScalingStrokePath(usePath, nonScalingStrokeTransform()); - context->strokePath(*usePath); + context.strokePath(*usePath); } bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point) @@ -190,21 +190,22 @@ void RenderSVGShape::layout() Path* RenderSVGShape::nonScalingStrokePath(const Path* path, const AffineTransform& strokeTransform) const { - DEFINE_STATIC_LOCAL(Path, tempPath, ()); + static NeverDestroyed<Path> tempPath; - tempPath = *path; - tempPath.transform(strokeTransform); + tempPath.get() = *path; + tempPath.get().transform(strokeTransform); - return &tempPath; + return &tempPath.get(); } bool RenderSVGShape::setupNonScalingStrokeContext(AffineTransform& strokeTransform, GraphicsContextStateSaver& stateSaver) { - if (!strokeTransform.isInvertible()) + std::optional<AffineTransform> inverse = strokeTransform.inverse(); + if (!inverse) return false; stateSaver.save(); - stateSaver.context()->concatCTM(strokeTransform.inverse()); + stateSaver.context()->concatCTM(inverse.value()); return true; } @@ -221,15 +222,16 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const if (!graphicsElement().supportsMarkers()) return false; - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources) return false; return resources->markerStart() || resources->markerMid() || resources->markerEnd(); } -void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext* context) +void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext& originalContext) { + GraphicsContext* context = &originalContext; Color fallbackColor; if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(*this, style, fallbackColor)) { if (fillPaintingResource->applyResource(*this, style, context, ApplyToFillMode)) @@ -243,8 +245,9 @@ void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext* contex } } -void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext* context) +void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext& originalContext) { + GraphicsContext* context = &originalContext; Color fallbackColor; if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(*this, style, fallbackColor)) { if (strokePaintingResource->applyResource(*this, style, context, ApplyToStrokeMode)) @@ -258,62 +261,73 @@ void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext* cont } } -void RenderSVGShape::fillAndStrokeShape(GraphicsContext* context) +void RenderSVGShape::strokeShape(GraphicsContext& context) { - fillShape(style(), context); - - if (!style().svgStyle().hasVisibleStroke()) + if (!style().hasVisibleStroke()) return; - GraphicsContextStateSaver stateSaver(*context, false); - + GraphicsContextStateSaver stateSaver(context, false); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) return; } - strokeShape(style(), context); } +void RenderSVGShape::fillStrokeMarkers(PaintInfo& childPaintInfo) +{ + auto paintOrder = style().paintTypesForPaintOrder(); + for (unsigned i = 0; i < paintOrder.size(); ++i) { + switch (paintOrder.at(i)) { + case PaintTypeFill: + fillShape(style(), childPaintInfo.context()); + break; + case PaintTypeStroke: + strokeShape(childPaintInfo.context()); + break; + case PaintTypeMarkers: + if (!m_markerPositions.isEmpty()) + drawMarkers(childPaintInfo); + break; + } + } +} + void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&) { - if (paintInfo.context->paintingDisabled() || style().visibility() == HIDDEN || isEmpty()) + if (paintInfo.context().paintingDisabled() || paintInfo.phase != PaintPhaseForeground + || style().visibility() == HIDDEN || isEmpty()) return; FloatRect boundingBox = repaintRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); - bool drawsOutline = style().outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); - if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); - childPaintInfo.applyTransform(m_localTransform); - - if (childPaintInfo.phase == PaintPhaseForeground) { - SVGRenderingContext renderingContext(*this, childPaintInfo); - - if (renderingContext.isRenderingPrepared()) { - const SVGRenderStyle& svgStyle = style().svgStyle(); - if (svgStyle.shapeRendering() == SR_CRISPEDGES) - childPaintInfo.context->setShouldAntialias(false); - - fillAndStrokeShape(childPaintInfo.context); - if (!m_markerPositions.isEmpty()) - drawMarkers(childPaintInfo); - } - } + GraphicsContextStateSaver stateSaver(childPaintInfo.context()); + childPaintInfo.applyTransform(m_localTransform); + + if (childPaintInfo.phase == PaintPhaseForeground) { + SVGRenderingContext renderingContext(*this, childPaintInfo); - if (drawsOutline) - paintOutline(childPaintInfo, IntRect(boundingBox)); + if (renderingContext.isRenderingPrepared()) { + const SVGRenderStyle& svgStyle = style().svgStyle(); + if (svgStyle.shapeRendering() == SR_CRISPEDGES) + childPaintInfo.context().setShouldAntialias(false); + + fillStrokeMarkers(childPaintInfo); + } } + + if (style().outlineWidth()) + paintOutline(childPaintInfo, IntRect(boundingBox)); } // This method is called from inside paintOutline() since we call paintOutline() // while transformed to our coord system, return local coords -void RenderSVGShape::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) +void RenderSVGShape::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { - IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates()); + LayoutRect rect = LayoutRect(repaintRectInLocalCoordinates()); if (!rect.isEmpty()) rects.append(rect); } @@ -324,7 +338,7 @@ bool RenderSVGShape::nodeAtFloatPoint(const HitTestRequest& request, HitTestResu if (hitTestAction != HitTestForeground) return false; - FloatPoint localPoint = m_localTransform.inverse().mapPoint(pointInParent); + FloatPoint localPoint = m_localTransform.inverse().value_or(AffineTransform()).mapPoint(pointInParent); if (!SVGRenderSupport::pointInClippingArea(*this, localPoint)) return false; @@ -338,7 +352,7 @@ bool RenderSVGShape::nodeAtFloatPoint(const HitTestRequest& request, HitTestResu fillRule = svgStyle.clipRule(); if ((hitRules.canHitStroke && (svgStyle.hasStroke() || !hitRules.requireStroke) && strokeContains(localPoint, hitRules.requireStroke)) || (hitRules.canHitFill && (svgStyle.hasFill() || !hitRules.requireFill) && fillContains(localPoint, hitRules.requireFill, fillRule))) { - updateHitTestResult(result, roundedLayoutPoint(localPoint)); + updateHitTestResult(result, LayoutPoint(localPoint)); return true; } } @@ -364,7 +378,7 @@ FloatRect RenderSVGShape::markerRect(float strokeWidth) const { ASSERT(!m_markerPositions.isEmpty()); - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); ASSERT(resources); RenderSVGResourceMarker* markerStart = resources->markerStart(); @@ -396,10 +410,10 @@ FloatRect RenderSVGShape::calculateStrokeBoundingBox() const BoundingRectStrokeStyleApplier strokeStyle(*this); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); - if (nonScalingTransform.isInvertible()) { + if (std::optional<AffineTransform> inverse = nonScalingTransform.inverse()) { Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform); FloatRect strokeBoundingRect = usePath->strokeBoundingRect(&strokeStyle); - strokeBoundingRect = nonScalingTransform.inverse().mapRect(strokeBoundingRect); + strokeBoundingRect = inverse.value().mapRect(strokeBoundingRect); strokeBoundingBox.unite(strokeBoundingRect); } } else @@ -424,7 +438,7 @@ void RenderSVGShape::updateRepaintBoundingBox() float RenderSVGShape::strokeWidth() const { SVGLengthContext lengthContext(&graphicsElement()); - return style().svgStyle().strokeWidth().value(lengthContext); + return lengthContext.valueForLength(style().strokeWidth()); } bool RenderSVGShape::hasSmoothStroke() const @@ -432,15 +446,15 @@ bool RenderSVGShape::hasSmoothStroke() const const SVGRenderStyle& svgStyle = style().svgStyle(); return svgStyle.strokeDashArray().isEmpty() && svgStyle.strokeMiterLimit() == svgStyle.initialStrokeMiterLimit() - && svgStyle.joinStyle() == svgStyle.initialJoinStyle() - && svgStyle.capStyle() == svgStyle.initialCapStyle(); + && style().joinStyle() == style().initialJoinStyle() + && style().capStyle() == style().initialCapStyle(); } void RenderSVGShape::drawMarkers(PaintInfo& paintInfo) { ASSERT(!m_markerPositions.isEmpty()); - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources) return; @@ -467,11 +481,11 @@ void RenderSVGShape::processMarkerPositions() ASSERT(m_path); - SVGMarkerData markerData(m_markerPositions); - m_path->apply(&markerData, SVGMarkerData::updateFromPathElement); + SVGMarkerData markerData(m_markerPositions, SVGResourcesCache::cachedResourcesForRenderer(*this)->markerReverseStart()); + m_path->apply([&markerData](const PathElement& pathElement) { + SVGMarkerData::updateFromPathElement(markerData, pathElement); + }); markerData.pathIsDone(); } } - -#endif // ENABLE(SVG) |