summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/svg/RenderSVGShape.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/svg/RenderSVGShape.cpp')
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGShape.cpp144
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)