diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-07-18 13:59:13 +0200 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-07-18 13:59:28 +0200 |
| commit | 4d6084feccab99c0a7b3ecef26bb49c41dd50201 (patch) | |
| tree | fd1195897f551eee6d5a15d07ff5733b15aa2a5c /Source/WebCore/rendering/svg | |
| parent | ae901828d4689ab9e89113f6b6ea8042b37a9fda (diff) | |
| download | qtwebkit-4d6084feccab99c0a7b3ecef26bb49c41dd50201.tar.gz | |
Imported WebKit commit ff52235a78888e5cb8e286a828a8698042200e67 (http://svn.webkit.org/repository/webkit/trunk@122948)
New snapshot that should fix the rendering issues recently introduced
Diffstat (limited to 'Source/WebCore/rendering/svg')
| -rwxr-xr-x | Source/WebCore/rendering/svg/RenderSVGPath.cpp | 118 | ||||
| -rw-r--r-- | Source/WebCore/rendering/svg/RenderSVGPath.h | 13 | ||||
| -rwxr-xr-x | Source/WebCore/rendering/svg/RenderSVGShape.cpp | 131 | ||||
| -rw-r--r-- | Source/WebCore/rendering/svg/RenderSVGShape.h | 21 |
4 files changed, 165 insertions, 118 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.cpp b/Source/WebCore/rendering/svg/RenderSVGPath.cpp index edad43945..cf658359d 100755 --- a/Source/WebCore/rendering/svg/RenderSVGPath.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGPath.cpp @@ -32,6 +32,7 @@ #include "SVGPathElement.h" #include "SVGStyledTransformableElement.h" +#include "SVGSubpathData.h" namespace WebCore { @@ -44,6 +45,123 @@ RenderSVGPath::~RenderSVGPath() { } +void RenderSVGPath::updateShapeFromElement() +{ + RenderSVGShape::updateShapeFromElement(); + updateZeroLengthSubpaths(); + + m_strokeBoundingBox = calculateUpdatedStrokeBoundingBox(); +} + +FloatRect RenderSVGPath::calculateUpdatedStrokeBoundingBox() const +{ + FloatRect strokeBoundingBox = m_strokeBoundingBox; + + if (style()->svgStyle()->hasStroke()) { + // FIXME: zero-length subpaths do not respect vector-effect = non-scaling-stroke. + float strokeWidth = this->strokeWidth(); + for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) + strokeBoundingBox.unite(zeroLengthSubpathRect(m_zeroLengthLinecapLocations[i], strokeWidth)); + } + + return strokeBoundingBox; +} + +static void useStrokeStyleToFill(GraphicsContext* context) +{ + if (Gradient* gradient = context->strokeGradient()) + context->setFillGradient(gradient); + else if (Pattern* pattern = context->strokePattern()) + context->setFillPattern(pattern); + else + context->setFillColor(context->strokeColor(), context->strokeColorSpace()); +} + +void RenderSVGPath::strokeShape(GraphicsContext* context) const +{ + if (!style()->svgStyle()->hasVisibleStroke()) + return; + + RenderSVGShape::strokeShape(context); + + if (m_zeroLengthLinecapLocations.isEmpty()) + return; + + Path* usePath; + AffineTransform nonScalingTransform; + + if (hasNonScalingStroke()) + nonScalingTransform = nonScalingStrokeTransform(); + + GraphicsContextStateSaver stateSaver(*context, true); + useStrokeStyleToFill(context); + for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) { + usePath = zeroLengthLinecapPath(m_zeroLengthLinecapLocations[i]); + if (hasNonScalingStroke()) + usePath = nonScalingStrokePath(usePath, nonScalingTransform); + context->fillPath(*usePath); + } +} + +bool RenderSVGPath::shapeDependentStrokeContains(const FloatPoint& point) +{ + if (RenderSVGShape::shapeDependentStrokeContains(point)) + return true; + + const SVGRenderStyle* svgStyle = style()->svgStyle(); + for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) { + ASSERT(svgStyle->hasStroke()); + float strokeWidth = this->strokeWidth(); + if (svgStyle->capStyle() == SquareCap) { + if (zeroLengthSubpathRect(m_zeroLengthLinecapLocations[i], strokeWidth).contains(point)) + return true; + } else { + ASSERT(svgStyle->capStyle() == RoundCap); + FloatPoint radiusVector(point.x() - m_zeroLengthLinecapLocations[i].x(), point.y() - m_zeroLengthLinecapLocations[i].y()); + if (radiusVector.lengthSquared() < strokeWidth * strokeWidth * .25f) + return true; + } + } + return false; +} + +bool RenderSVGPath::shouldStrokeZeroLengthSubpath() const +{ + // Spec(11.4): Any zero length subpath shall not be stroked if the "stroke-linecap" property has a value of butt + // but shall be stroked if the "stroke-linecap" property has a value of round or square + return style()->svgStyle()->hasStroke() && style()->svgStyle()->capStyle() != ButtCap; +} + +Path* RenderSVGPath::zeroLengthLinecapPath(const FloatPoint& linecapPosition) const +{ + DEFINE_STATIC_LOCAL(Path, tempPath, ()); + + tempPath.clear(); + if (style()->svgStyle()->capStyle() == SquareCap) + tempPath.addRect(zeroLengthSubpathRect(linecapPosition, this->strokeWidth())); + else + tempPath.addEllipse(zeroLengthSubpathRect(linecapPosition, this->strokeWidth())); + + return &tempPath; +} + +FloatRect RenderSVGPath::zeroLengthSubpathRect(const FloatPoint& linecapPosition, float strokeWidth) const +{ + return FloatRect(linecapPosition.x() - strokeWidth / 2, linecapPosition.y() - strokeWidth / 2, strokeWidth, strokeWidth); +} + +void RenderSVGPath::updateZeroLengthSubpaths() +{ + m_zeroLengthLinecapLocations.clear(); + + if (!strokeWidth() || !shouldStrokeZeroLengthSubpath()) + return; + + SVGSubpathData subpathData(m_zeroLengthLinecapLocations); + path().apply(&subpathData, SVGSubpathData::updateFromPathElement); + subpathData.pathIsDone(); +} + } #endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.h b/Source/WebCore/rendering/svg/RenderSVGPath.h index 77e99e5be..ab1cf1c0b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGPath.h +++ b/Source/WebCore/rendering/svg/RenderSVGPath.h @@ -39,6 +39,19 @@ public: private: virtual bool isSVGPath() const { return true; } virtual const char* renderName() const { return "RenderSVGPath"; } + + virtual void updateShapeFromElement() OVERRIDE; + FloatRect calculateUpdatedStrokeBoundingBox() const; + + virtual void strokeShape(GraphicsContext*) const OVERRIDE; + virtual bool shapeDependentStrokeContains(const FloatPoint&) OVERRIDE; + + bool shouldStrokeZeroLengthSubpath() const; + Path* zeroLengthLinecapPath(const FloatPoint&) const; + FloatRect zeroLengthSubpathRect(const FloatPoint&, float) const; + void updateZeroLengthSubpaths(); + + Vector<FloatPoint> m_zeroLengthLinecapLocations; }; } diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.cpp b/Source/WebCore/rendering/svg/RenderSVGShape.cpp index 282c50a0b..62a8c99ba 100755 --- a/Source/WebCore/rendering/svg/RenderSVGShape.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGShape.cpp @@ -44,7 +44,6 @@ #include "SVGResources.h" #include "SVGResourcesCache.h" #include "SVGStyledTransformableElement.h" -#include "SVGSubpathData.h" #include "SVGTransformList.h" #include "SVGURIReference.h" #include "StrokeStyleApplier.h" @@ -72,7 +71,6 @@ void RenderSVGShape::updateShapeFromElement() SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node()); updatePathFromGraphicsElement(element, path()); - processZeroLengthSubpaths(); processMarkerPositions(); m_fillBoundingBox = calculateObjectBoundingBox(); @@ -91,8 +89,13 @@ void RenderSVGShape::fillShape(GraphicsContext* context) const void RenderSVGShape::strokeShape(GraphicsContext* context) const { - if (style()->svgStyle()->hasVisibleStroke()) - context->strokePath(path()); + ASSERT(m_path); + Path* usePath = m_path.get(); + + if (hasNonScalingStroke()) + usePath = nonScalingStrokePath(usePath, nonScalingStrokeTransform()); + + context->strokePath(*usePath); } bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point) @@ -136,20 +139,6 @@ bool RenderSVGShape::strokeContains(const FloatPoint& point, bool requiresStroke if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style(), fallbackColor)) return false; - for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) { - ASSERT(style()->svgStyle()->hasStroke()); - float strokeWidth = this->strokeWidth(); - if (style()->svgStyle()->capStyle() == SquareCap) { - if (zeroLengthSubpathRect(m_zeroLengthLinecapLocations[i], strokeWidth).contains(point)) - return true; - } else { - ASSERT(style()->svgStyle()->capStyle() == RoundCap); - FloatPoint radiusVector(point.x() - m_zeroLengthLinecapLocations[i].x(), point.y() - m_zeroLengthLinecapLocations[i].y()); - if (radiusVector.lengthSquared() < strokeWidth * strokeWidth * .25f) - return true; - } - } - return shapeDependentStrokeContains(point); } @@ -212,13 +201,6 @@ AffineTransform RenderSVGShape::nonScalingStrokeTransform() const return element->getScreenCTM(SVGLocatable::DisallowStyleUpdate); } -bool RenderSVGShape::shouldStrokeZeroLengthSubpath() const -{ - // Spec(11.4): Any zero length subpath shall not be stroked if the "stroke-linecap" property has a value of butt - // but shall be stroked if the "stroke-linecap" property has a value of round or square - return style()->svgStyle()->hasStroke() && style()->svgStyle()->capStyle() != ButtCap; -} - bool RenderSVGShape::shouldGenerateMarkerPositions() const { if (!style()->svgStyle()->hasMarkers()) @@ -235,94 +217,55 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const return resources->markerStart() || resources->markerMid() || resources->markerEnd(); } -FloatRect RenderSVGShape::zeroLengthSubpathRect(const FloatPoint& linecapPosition, float strokeWidth) const -{ - return FloatRect(linecapPosition.x() - strokeWidth / 2, linecapPosition.y() - strokeWidth / 2, strokeWidth, strokeWidth); -} - -Path* RenderSVGShape::zeroLengthLinecapPath(const FloatPoint& linecapPosition) -{ - // Spec(11.4): Any zero length subpath shall not be stroked if the "stroke-linecap" property has a value of butt - // but shall be stroked if the "stroke-linecap" property has a value of round or square - DEFINE_STATIC_LOCAL(Path, tempPath, ()); - - tempPath.clear(); - float strokeWidth = this->strokeWidth(); - if (style()->svgStyle()->capStyle() == SquareCap) - tempPath.addRect(zeroLengthSubpathRect(linecapPosition, strokeWidth)); - else - tempPath.addEllipse(zeroLengthSubpathRect(linecapPosition, strokeWidth)); - - return &tempPath; -} - -void RenderSVGShape::fillShape(RenderStyle* style, GraphicsContext* context, Path* path, RenderSVGShape* shape) +void RenderSVGShape::fillShape(RenderStyle* style, GraphicsContext* context) { Color fallbackColor; if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(this, style, fallbackColor)) { if (fillPaintingResource->applyResource(this, style, context, ApplyToFillMode)) - fillPaintingResource->postApplyResource(this, context, ApplyToFillMode, path, shape); + fillPaintingResource->postApplyResource(this, context, ApplyToFillMode, 0, this); else if (fallbackColor.isValid()) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); fallbackResource->setColor(fallbackColor); if (fallbackResource->applyResource(this, style, context, ApplyToFillMode)) - fallbackResource->postApplyResource(this, context, ApplyToFillMode, path, shape); + fallbackResource->postApplyResource(this, context, ApplyToFillMode, 0, this); } } } -void RenderSVGShape::strokePath(RenderStyle* style, GraphicsContext* context, Path* path, RenderSVGResource* strokePaintingResource, - const Color& fallbackColor, int applyMode) +void RenderSVGShape::strokeShape(RenderStyle* style, GraphicsContext* context) { - if (!style->svgStyle()->hasVisibleStroke()) - return; - - if (strokePaintingResource->applyResource(this, style, context, applyMode)) { - strokePaintingResource->postApplyResource(this, context, applyMode, path, this); - return; + Color fallbackColor; + if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, fallbackColor)) { + if (strokePaintingResource->applyResource(this, style, context, ApplyToStrokeMode)) + strokePaintingResource->postApplyResource(this, context, ApplyToStrokeMode, 0, this); + else if (fallbackColor.isValid()) { + RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); + fallbackResource->setColor(fallbackColor); + if (fallbackResource->applyResource(this, style, context, ApplyToStrokeMode)) + fallbackResource->postApplyResource(this, context, ApplyToStrokeMode, 0, this); + } } - - if (!fallbackColor.isValid()) - return; - - RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); - fallbackResource->setColor(fallbackColor); - if (fallbackResource->applyResource(this, style, context, applyMode)) - fallbackResource->postApplyResource(this, context, applyMode, path, this); } -void RenderSVGShape::fillAndStrokePath(GraphicsContext* context) +void RenderSVGShape::fillAndStrokeShape(GraphicsContext* context) { RenderStyle* style = this->style(); - fillShape(style, context, 0, this); + fillShape(style, context); - Color fallbackColor = Color(); - RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(this, style, fallbackColor); - if (!strokePaintingResource) + if (!style->svgStyle()->hasVisibleStroke()) return; - Path* usePath = m_path.get(); GraphicsContextStateSaver stateSaver(*context, false); AffineTransform nonScalingTransform; if (hasNonScalingStroke()) { - nonScalingTransform = nonScalingStrokeTransform(); + AffineTransform nonScalingTransform = nonScalingStrokeTransform(); if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) return; - usePath = nonScalingStrokePath(usePath, nonScalingTransform); } - strokePath(style, context, usePath, strokePaintingResource, fallbackColor, ApplyToStrokeMode); - - // Spec(11.4): Any zero length subpath shall not be stroked if the "stroke-linecap" property has a value of butt - // but shall be stroked if the "stroke-linecap" property has a value of round or square - for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) { - Path* usePath = zeroLengthLinecapPath(m_zeroLengthLinecapLocations[i]); - if (hasNonScalingStroke()) - usePath = nonScalingStrokePath(usePath, nonScalingTransform); - strokePath(style, context, usePath, strokePaintingResource, fallbackColor, ApplyToFillMode); - } + strokeShape(style, context); } void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&) @@ -347,7 +290,7 @@ void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&) if (svgStyle->shapeRendering() == SR_CRISPEDGES) childPaintInfo.context->setShouldAntialias(false); - fillAndStrokePath(childPaintInfo.context); + fillAndStrokeShape(childPaintInfo.context); if (!m_markerPositions.isEmpty()) drawMarkers(childPaintInfo); } @@ -453,11 +396,6 @@ FloatRect RenderSVGShape::calculateStrokeBoundingBox() const } } else strokeBoundingBox.unite(path().strokeBoundingRect(&strokeStyle)); - - // FIXME: zero-length subpaths do not respect vector-effect = non-scaling-stroke. - float strokeWidth = this->strokeWidth(); - for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) - strokeBoundingBox.unite(zeroLengthSubpathRect(m_zeroLengthLinecapLocations[i], strokeWidth)); } if (!m_markerPositions.isEmpty()) @@ -510,21 +448,6 @@ void RenderSVGShape::drawMarkers(PaintInfo& paintInfo) } } -void RenderSVGShape::processZeroLengthSubpaths() -{ - m_zeroLengthLinecapLocations.clear(); - - float strokeWidth = this->strokeWidth(); - if (!strokeWidth || !shouldStrokeZeroLengthSubpath()) - return; - - ASSERT(m_path); - - SVGSubpathData subpathData(m_zeroLengthLinecapLocations); - m_path->apply(&subpathData, SVGSubpathData::updateFromPathElement); - subpathData.pathIsDone(); -} - void RenderSVGShape::processMarkerPositions() { m_markerPositions.clear(); diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.h b/Source/WebCore/rendering/svg/RenderSVGShape.h index 81c6b370c..4796e8c31 100644 --- a/Source/WebCore/rendering/svg/RenderSVGShape.h +++ b/Source/WebCore/rendering/svg/RenderSVGShape.h @@ -89,9 +89,12 @@ protected: virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; float strokeWidth() const; bool hasPath() const { return m_path.get(); } - bool hasNonScalingStroke() const { return style()->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE; } bool hasSmoothStroke() const; + bool hasNonScalingStroke() const { return style()->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE; } + AffineTransform nonScalingStrokeTransform() const; + Path* nonScalingStrokePath(const Path*, const AffineTransform&) const; + FloatRect m_fillBoundingBox; FloatRect m_strokeBoundingBox; @@ -115,35 +118,25 @@ private: virtual FloatRect objectBoundingBox() const { return m_fillBoundingBox; } virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; } - FloatRect calculateObjectBoundingBox() const; FloatRect calculateStrokeBoundingBox() const; void updateRepaintBoundingBox(); - AffineTransform nonScalingStrokeTransform() const; bool setupNonScalingStrokeContext(AffineTransform&, GraphicsContextStateSaver&); - Path* nonScalingStrokePath(const Path*, const AffineTransform&) const; - - Path* zeroLengthLinecapPath(const FloatPoint&); - bool shouldStrokeZeroLengthSubpath() const; - FloatRect zeroLengthSubpathRect(const FloatPoint&, float) const; - void processZeroLengthSubpaths(); bool shouldGenerateMarkerPositions() const; FloatRect markerRect(float strokeWidth) const; void processMarkerPositions(); - void fillShape(RenderStyle*, GraphicsContext*, Path*, RenderSVGShape*); - void strokePath(RenderStyle*, GraphicsContext*, Path*, RenderSVGResource*, - const Color&, int); - void fillAndStrokePath(GraphicsContext*); + void fillShape(RenderStyle*, GraphicsContext*); + void strokeShape(RenderStyle*, GraphicsContext*); + void fillAndStrokeShape(GraphicsContext*); void drawMarkers(PaintInfo&); private: FloatRect m_repaintBoundingBox; AffineTransform m_localTransform; OwnPtr<Path> m_path; - Vector<FloatPoint> m_zeroLengthLinecapLocations; Vector<MarkerPosition> m_markerPositions; bool m_needsBoundariesUpdate : 1; |
