| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/paint/SVGShapePainter.h" | 6 #include "core/paint/SVGShapePainter.h" |
| 7 | 7 |
| 8 #include "core/layout/PaintInfo.h" | 8 #include "core/layout/PaintInfo.h" |
| 9 #include "core/layout/svg/LayoutSVGPath.h" | 9 #include "core/layout/svg/LayoutSVGPath.h" |
| 10 #include "core/layout/svg/LayoutSVGResourceMarker.h" | 10 #include "core/layout/svg/LayoutSVGResourceMarker.h" |
| 11 #include "core/layout/svg/LayoutSVGShape.h" | 11 #include "core/layout/svg/LayoutSVGShape.h" |
| 12 #include "core/layout/svg/SVGLayoutSupport.h" | 12 #include "core/layout/svg/SVGLayoutSupport.h" |
| 13 #include "core/layout/svg/SVGMarkerData.h" | 13 #include "core/layout/svg/SVGMarkerData.h" |
| 14 #include "core/layout/svg/SVGResources.h" | 14 #include "core/layout/svg/SVGResources.h" |
| 15 #include "core/layout/svg/SVGResourcesCache.h" | 15 #include "core/layout/svg/SVGResourcesCache.h" |
| 16 #include "core/paint/GraphicsContextAnnotator.h" | 16 #include "core/paint/GraphicsContextAnnotator.h" |
| 17 #include "core/paint/LayoutObjectDrawingRecorder.h" | 17 #include "core/paint/LayoutObjectDrawingRecorder.h" |
| 18 #include "core/paint/ObjectPainter.h" | 18 #include "core/paint/ObjectPainter.h" |
| 19 #include "core/paint/SVGContainerPainter.h" | 19 #include "core/paint/SVGContainerPainter.h" |
| 20 #include "core/paint/SVGPaintContext.h" | 20 #include "core/paint/SVGPaintContext.h" |
| 21 #include "core/paint/TransformRecorder.h" | 21 #include "core/paint/TransformRecorder.h" |
| 22 #include "platform/graphics/paint/DisplayItemListContextRecorder.h" | 22 #include "platform/graphics/paint/DisplayItemListContextRecorder.h" |
| 23 #include "third_party/skia/include/core/SkPaint.h" |
| 23 #include "third_party/skia/include/core/SkPicture.h" | 24 #include "third_party/skia/include/core/SkPicture.h" |
| 24 | 25 |
| 25 namespace blink { | 26 namespace blink { |
| 26 | 27 |
| 27 static bool setupNonScalingStrokeContext(AffineTransform& strokeTransform, Graph
icsContextStateSaver& stateSaver) | 28 static bool setupNonScalingStrokeContext(AffineTransform& strokeTransform, Graph
icsContextStateSaver& stateSaver) |
| 28 { | 29 { |
| 29 if (!strokeTransform.isInvertible()) | 30 if (!strokeTransform.isInvertible()) |
| 30 return false; | 31 return false; |
| 31 | 32 |
| 32 stateSaver.save(); | 33 stateSaver.save(); |
| 33 stateSaver.context()->concatCTM(strokeTransform.inverse()); | 34 stateSaver.context()->concatCTM(strokeTransform.inverse()); |
| 34 return true; | 35 return true; |
| 35 } | 36 } |
| 36 | 37 |
| 37 static void useStrokeStyleToFill(GraphicsContext* context) | 38 static bool paintForLayoutObject(const PaintInfo& paintInfo, const ComputedStyle
& style, LayoutObject& layoutObject, LayoutSVGResourceMode resourceMode, SkPaint
& paint, const AffineTransform* additionalPaintServerTransform = nullptr) |
| 38 { | 39 { |
| 39 if (Gradient* gradient = context->strokeGradient()) | 40 if (paintInfo.isRenderingClipPathAsMaskImage()) { |
| 40 context->setFillGradient(gradient); | 41 if (resourceMode == ApplyToStrokeMode) |
| 41 else if (Pattern* pattern = context->strokePattern()) | 42 return false; |
| 42 context->setFillPattern(pattern); | 43 paint.setColor(SVGComputedStyle::initialFillPaintColor().rgb()); |
| 43 else | 44 paint.setShader(nullptr); |
| 44 context->setFillColor(context->strokeColor()); | 45 return true; |
| 46 } |
| 47 |
| 48 SVGPaintServer paintServer = SVGPaintServer::requestForLayoutObject(layoutOb
ject, style, resourceMode); |
| 49 if (!paintServer.isValid()) |
| 50 return false; |
| 51 |
| 52 if (additionalPaintServerTransform && paintServer.isTransformDependent()) |
| 53 paintServer.prependTransform(*additionalPaintServerTransform); |
| 54 |
| 55 const SVGComputedStyle& svgStyle = style.svgStyle(); |
| 56 float paintAlpha = resourceMode == ApplyToFillMode ? svgStyle.fillOpacity()
: svgStyle.strokeOpacity(); |
| 57 paintServer.applyToSkPaint(paint, paintAlpha); |
| 58 |
| 59 paint.setFilterQuality(WebCoreInterpolationQualityToSkFilterQuality(Interpol
ationDefault)); |
| 60 |
| 61 // TODO(fs): The color filter can set when generating a picture for a mask - |
| 62 // due to color-interpolation. We could also just apply the |
| 63 // color-interpolation property from the the shape itself (which could mean |
| 64 // the paintserver if it has it specified), since that would be more in line |
| 65 // with the spec for color-interpolation. For now, just steal it from the GC |
| 66 // though. |
| 67 // Additionally, it's not really safe/guaranteed to be correct, as |
| 68 // something down the paint pipe may want to farther tweak the color |
| 69 // filter, which could yield incorrect results. (Consider just using |
| 70 // saveLayer() w/ this color filter explicitly instead.) |
| 71 paint.setColorFilter(paintInfo.context->colorFilter()); |
| 72 return true; |
| 73 } |
| 74 |
| 75 static SkPath::FillType fillRuleFromStyle(const PaintInfo& paintInfo, const SVGC
omputedStyle& svgStyle) |
| 76 { |
| 77 return WebCoreWindRuleToSkFillType(paintInfo.isRenderingClipPathAsMaskImage(
) ? svgStyle.clipRule() : svgStyle.fillRule()); |
| 45 } | 78 } |
| 46 | 79 |
| 47 void SVGShapePainter::paint(const PaintInfo& paintInfo) | 80 void SVGShapePainter::paint(const PaintInfo& paintInfo) |
| 48 { | 81 { |
| 49 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderSVGShape); | 82 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderSVGShape); |
| 50 if (paintInfo.phase != PaintPhaseForeground | 83 if (paintInfo.phase != PaintPhaseForeground |
| 51 || m_renderSVGShape.style()->visibility() == HIDDEN | 84 || m_renderSVGShape.style()->visibility() == HIDDEN |
| 52 || m_renderSVGShape.isShapeEmpty()) | 85 || m_renderSVGShape.isShapeEmpty()) |
| 53 return; | 86 return; |
| 54 | 87 |
| 55 PaintInfo paintInfoBeforeFiltering(paintInfo); | 88 PaintInfo paintInfoBeforeFiltering(paintInfo); |
| 56 FloatRect boundingBox = m_renderSVGShape.paintInvalidationRectInLocalCoordin
ates(); | 89 FloatRect boundingBox = m_renderSVGShape.paintInvalidationRectInLocalCoordin
ates(); |
| 57 | 90 |
| 58 TransformRecorder transformRecorder(*paintInfoBeforeFiltering.context, m_ren
derSVGShape, m_renderSVGShape.localTransform()); | 91 TransformRecorder transformRecorder(*paintInfoBeforeFiltering.context, m_ren
derSVGShape, m_renderSVGShape.localTransform()); |
| 59 { | 92 { |
| 60 SVGPaintContext paintContext(m_renderSVGShape, paintInfoBeforeFiltering)
; | 93 SVGPaintContext paintContext(m_renderSVGShape, paintInfoBeforeFiltering)
; |
| 61 if (paintContext.applyClipMaskAndFilterIfNecessary()) { | 94 if (paintContext.applyClipMaskAndFilterIfNecessary()) { |
| 62 LayoutObjectDrawingRecorder recorder(*paintContext.paintInfo().conte
xt, m_renderSVGShape, paintContext.paintInfo().phase, boundingBox); | 95 LayoutObjectDrawingRecorder recorder(*paintContext.paintInfo().conte
xt, m_renderSVGShape, paintContext.paintInfo().phase, boundingBox); |
| 63 if (!recorder.canUseCachedDrawing()) { | 96 if (!recorder.canUseCachedDrawing()) { |
| 64 const SVGComputedStyle& svgStyle = m_renderSVGShape.style()->svg
Style(); | 97 const SVGComputedStyle& svgStyle = m_renderSVGShape.style()->svg
Style(); |
| 65 | 98 |
| 66 bool shouldAntiAlias = svgStyle.shapeRendering() != SR_CRISPEDGE
S; | 99 bool shouldAntiAlias = svgStyle.shapeRendering() != SR_CRISPEDGE
S; |
| 67 // We're munging GC paint attributes without saving first (and s
o does | |
| 68 // updateGraphicsContext below). This is in line with making GC
less stateful, | |
| 69 // but we should keep an eye out for unintended side effects. | |
| 70 // | |
| 71 // FIXME: the mutation avoidance check should be in (all) the GC
setters. | |
| 72 if (shouldAntiAlias != paintContext.paintInfo().context->shouldA
ntialias()) | |
| 73 paintContext.paintInfo().context->setShouldAntialias(shouldA
ntiAlias); | |
| 74 | 100 |
| 75 for (int i = 0; i < 3; i++) { | 101 for (int i = 0; i < 3; i++) { |
| 76 switch (svgStyle.paintOrderType(i)) { | 102 switch (svgStyle.paintOrderType(i)) { |
| 77 case PT_FILL: { | 103 case PT_FILL: { |
| 78 GraphicsContextStateSaver stateSaver(*paintContext.paint
Info().context, false); | 104 SkPaint fillPaint; |
| 79 if (!SVGLayoutSupport::updateGraphicsContext(paintContex
t.paintInfo(), stateSaver, m_renderSVGShape.styleRef(), m_renderSVGShape, ApplyT
oFillMode)) | 105 if (!paintForLayoutObject(paintContext.paintInfo(), m_re
nderSVGShape.styleRef(), m_renderSVGShape, ApplyToFillMode, fillPaint)) |
| 80 break; | 106 break; |
| 81 fillShape(paintContext.paintInfo().context); | 107 fillPaint.setAntiAlias(shouldAntiAlias); |
| 108 fillShape(paintContext.paintInfo().context, fillPaint, f
illRuleFromStyle(paintContext.paintInfo(), svgStyle)); |
| 82 break; | 109 break; |
| 83 } | 110 } |
| 84 case PT_STROKE: | 111 case PT_STROKE: |
| 85 if (svgStyle.hasVisibleStroke()) { | 112 if (svgStyle.hasVisibleStroke()) { |
| 86 GraphicsContextStateSaver stateSaver(*paintContext.p
aintInfo().context, false); | 113 GraphicsContextStateSaver stateSaver(*paintContext.p
aintInfo().context, false); |
| 87 AffineTransform nonScalingTransform; | 114 AffineTransform nonScalingTransform; |
| 88 const AffineTransform* additionalPaintServerTransfor
m = 0; | 115 const AffineTransform* additionalPaintServerTransfor
m = 0; |
| 89 | 116 |
| 90 if (m_renderSVGShape.hasNonScalingStroke()) { | 117 if (m_renderSVGShape.hasNonScalingStroke()) { |
| 91 nonScalingTransform = m_renderSVGShape.nonScalin
gStrokeTransform(); | 118 nonScalingTransform = m_renderSVGShape.nonScalin
gStrokeTransform(); |
| 92 if (!setupNonScalingStrokeContext(nonScalingTran
sform, stateSaver)) | 119 if (!setupNonScalingStrokeContext(nonScalingTran
sform, stateSaver)) |
| 93 return; | 120 return; |
| 94 | 121 |
| 95 // Non-scaling stroke needs to reset the transfo
rm back to the host transform. | 122 // Non-scaling stroke needs to reset the transfo
rm back to the host transform. |
| 96 additionalPaintServerTransform = &nonScalingTran
sform; | 123 additionalPaintServerTransform = &nonScalingTran
sform; |
| 97 } | 124 } |
| 98 | 125 |
| 99 if (!SVGLayoutSupport::updateGraphicsContext(paintCo
ntext.paintInfo(), stateSaver, m_renderSVGShape.styleRef(), m_renderSVGShape, Ap
plyToStrokeMode, additionalPaintServerTransform)) | 126 SkPaint strokePaint; |
| 127 if (!paintForLayoutObject(paintContext.paintInfo(),
m_renderSVGShape.styleRef(), m_renderSVGShape, ApplyToStrokeMode, strokePaint, a
dditionalPaintServerTransform)) |
| 100 break; | 128 break; |
| 101 strokeShape(paintContext.paintInfo().context); | 129 strokePaint.setAntiAlias(shouldAntiAlias); |
| 130 |
| 131 StrokeData strokeData; |
| 132 SVGLayoutSupport::applyStrokeStyleToStrokeData(strok
eData, m_renderSVGShape.styleRef(), m_renderSVGShape); |
| 133 strokeData.setupPaint(&strokePaint); |
| 134 |
| 135 strokeShape(paintContext.paintInfo().context, stroke
Paint); |
| 102 } | 136 } |
| 103 break; | 137 break; |
| 104 case PT_MARKERS: | 138 case PT_MARKERS: |
| 105 paintMarkers(paintContext.paintInfo()); | 139 paintMarkers(paintContext.paintInfo()); |
| 106 break; | 140 break; |
| 107 default: | 141 default: |
| 108 ASSERT_NOT_REACHED(); | 142 ASSERT_NOT_REACHED(); |
| 109 break; | 143 break; |
| 110 } | 144 } |
| 111 } | 145 } |
| 112 } | 146 } |
| 113 } | 147 } |
| 114 } | 148 } |
| 115 | 149 |
| 116 if (m_renderSVGShape.style()->outlineWidth()) { | 150 if (m_renderSVGShape.style()->outlineWidth()) { |
| 117 PaintInfo outlinePaintInfo(paintInfoBeforeFiltering); | 151 PaintInfo outlinePaintInfo(paintInfoBeforeFiltering); |
| 118 outlinePaintInfo.phase = PaintPhaseSelfOutline; | 152 outlinePaintInfo.phase = PaintPhaseSelfOutline; |
| 119 LayoutRect layoutObjectBounds(boundingBox); | 153 LayoutRect layoutObjectBounds(boundingBox); |
| 120 ObjectPainter(m_renderSVGShape).paintOutline(outlinePaintInfo, layoutObj
ectBounds, layoutObjectBounds); | 154 ObjectPainter(m_renderSVGShape).paintOutline(outlinePaintInfo, layoutObj
ectBounds, layoutObjectBounds); |
| 121 } | 155 } |
| 122 } | 156 } |
| 123 | 157 |
| 124 void SVGShapePainter::fillShape(GraphicsContext* context) | 158 class PathWithTemporaryWindingRule { |
| 159 public: |
| 160 PathWithTemporaryWindingRule(Path& path, SkPath::FillType fillType) |
| 161 : m_path(const_cast<SkPath&>(path.skPath())) |
| 162 { |
| 163 m_savedFillType = m_path.getFillType(); |
| 164 m_path.setFillType(fillType); |
| 165 } |
| 166 ~PathWithTemporaryWindingRule() |
| 167 { |
| 168 m_path.setFillType(m_savedFillType); |
| 169 } |
| 170 |
| 171 const SkPath& skPath() const { return m_path; } |
| 172 |
| 173 private: |
| 174 SkPath& m_path; |
| 175 SkPath::FillType m_savedFillType; |
| 176 }; |
| 177 |
| 178 void SVGShapePainter::fillShape(GraphicsContext* context, const SkPaint& paint,
SkPath::FillType fillType) |
| 125 { | 179 { |
| 126 switch (m_renderSVGShape.geometryCodePath()) { | 180 switch (m_renderSVGShape.geometryCodePath()) { |
| 127 case RectGeometryFastPath: | 181 case RectGeometryFastPath: |
| 128 context->fillRect(m_renderSVGShape.objectBoundingBox()); | 182 context->drawRect(m_renderSVGShape.objectBoundingBox(), paint); |
| 129 break; | 183 break; |
| 130 case EllipseGeometryFastPath: | 184 case EllipseGeometryFastPath: |
| 131 context->fillEllipse(m_renderSVGShape.objectBoundingBox()); | 185 context->drawOval(m_renderSVGShape.objectBoundingBox(), paint); |
| 132 break; | 186 break; |
| 133 default: | 187 default: { |
| 134 context->fillPath(m_renderSVGShape.path()); | 188 PathWithTemporaryWindingRule pathWithWinding(m_renderSVGShape.path(), fi
llType); |
| 189 context->drawPath(pathWithWinding.skPath(), paint); |
| 190 } |
| 135 } | 191 } |
| 136 } | 192 } |
| 137 | 193 |
| 138 void SVGShapePainter::strokeShape(GraphicsContext* context) | 194 void SVGShapePainter::strokeShape(GraphicsContext* context, const SkPaint& paint
) |
| 139 { | 195 { |
| 140 if (!m_renderSVGShape.style()->svgStyle().hasVisibleStroke()) | 196 if (!m_renderSVGShape.style()->svgStyle().hasVisibleStroke()) |
| 141 return; | 197 return; |
| 142 | 198 |
| 143 switch (m_renderSVGShape.geometryCodePath()) { | 199 switch (m_renderSVGShape.geometryCodePath()) { |
| 144 case RectGeometryFastPath: | 200 case RectGeometryFastPath: |
| 145 context->strokeRect(m_renderSVGShape.objectBoundingBox(), m_renderSVGSha
pe.strokeWidth()); | 201 context->drawRect(m_renderSVGShape.objectBoundingBox(), paint); |
| 146 break; | 202 break; |
| 147 case EllipseGeometryFastPath: | 203 case EllipseGeometryFastPath: |
| 148 context->strokeEllipse(m_renderSVGShape.objectBoundingBox()); | 204 context->drawOval(m_renderSVGShape.objectBoundingBox(), paint); |
| 149 break; | 205 break; |
| 150 default: | 206 default: |
| 151 ASSERT(m_renderSVGShape.hasPath()); | 207 ASSERT(m_renderSVGShape.hasPath()); |
| 152 Path* usePath = &m_renderSVGShape.path(); | 208 Path* usePath = &m_renderSVGShape.path(); |
| 153 if (m_renderSVGShape.hasNonScalingStroke()) | 209 if (m_renderSVGShape.hasNonScalingStroke()) |
| 154 usePath = m_renderSVGShape.nonScalingStrokePath(usePath, m_renderSVG
Shape.nonScalingStrokeTransform()); | 210 usePath = m_renderSVGShape.nonScalingStrokePath(usePath, m_renderSVG
Shape.nonScalingStrokeTransform()); |
| 155 context->strokePath(*usePath); | 211 context->drawPath(usePath->skPath(), paint); |
| 156 strokeZeroLengthLineCaps(context); | 212 strokeZeroLengthLineCaps(context, paint); |
| 157 } | 213 } |
| 158 } | 214 } |
| 159 | 215 |
| 160 void SVGShapePainter::paintMarkers(const PaintInfo& paintInfo) | 216 void SVGShapePainter::paintMarkers(const PaintInfo& paintInfo) |
| 161 { | 217 { |
| 162 const Vector<MarkerPosition>* markerPositions = m_renderSVGShape.markerPosit
ions(); | 218 const Vector<MarkerPosition>* markerPositions = m_renderSVGShape.markerPosit
ions(); |
| 163 if (!markerPositions || markerPositions->isEmpty()) | 219 if (!markerPositions || markerPositions->isEmpty()) |
| 164 return; | 220 return; |
| 165 | 221 |
| 166 SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(
&m_renderSVGShape); | 222 SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(
&m_renderSVGShape); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 196 | 252 |
| 197 TransformRecorder transformRecorder(*markerPaintInfo.context, marker, ma
rker.markerTransformation(position.origin, position.angle, strokeWidth)); | 253 TransformRecorder transformRecorder(*markerPaintInfo.context, marker, ma
rker.markerTransformation(position.origin, position.angle, strokeWidth)); |
| 198 OwnPtr<FloatClipRecorder> clipRecorder; | 254 OwnPtr<FloatClipRecorder> clipRecorder; |
| 199 if (SVGLayoutSupport::isOverflowHidden(&marker)) | 255 if (SVGLayoutSupport::isOverflowHidden(&marker)) |
| 200 clipRecorder = adoptPtr(new FloatClipRecorder(*markerPaintInfo.conte
xt, marker, markerPaintInfo.phase, marker.viewport())); | 256 clipRecorder = adoptPtr(new FloatClipRecorder(*markerPaintInfo.conte
xt, marker, markerPaintInfo.phase, marker.viewport())); |
| 201 | 257 |
| 202 SVGContainerPainter(marker).paint(markerPaintInfo); | 258 SVGContainerPainter(marker).paint(markerPaintInfo); |
| 203 } | 259 } |
| 204 } | 260 } |
| 205 | 261 |
| 206 void SVGShapePainter::strokeZeroLengthLineCaps(GraphicsContext* context) | 262 void SVGShapePainter::strokeZeroLengthLineCaps(GraphicsContext* context, const S
kPaint& strokePaint) |
| 207 { | 263 { |
| 208 const Vector<FloatPoint>* zeroLengthLineCaps = m_renderSVGShape.zeroLengthLi
neCaps(); | 264 const Vector<FloatPoint>* zeroLengthLineCaps = m_renderSVGShape.zeroLengthLi
neCaps(); |
| 209 if (!zeroLengthLineCaps || zeroLengthLineCaps->isEmpty()) | 265 if (!zeroLengthLineCaps || zeroLengthLineCaps->isEmpty()) |
| 210 return; | 266 return; |
| 211 | 267 |
| 212 Path* usePath; | 268 // We need a paint for filling. |
| 269 SkPaint fillPaint = strokePaint; |
| 270 fillPaint.setStyle(SkPaint::kFill_Style); |
| 271 |
| 213 AffineTransform nonScalingTransform; | 272 AffineTransform nonScalingTransform; |
| 214 | |
| 215 if (m_renderSVGShape.hasNonScalingStroke()) | 273 if (m_renderSVGShape.hasNonScalingStroke()) |
| 216 nonScalingTransform = m_renderSVGShape.nonScalingStrokeTransform(); | 274 nonScalingTransform = m_renderSVGShape.nonScalingStrokeTransform(); |
| 217 | 275 |
| 218 GraphicsContextStateSaver stateSaver(*context, true); | 276 Path tempPath; |
| 219 useStrokeStyleToFill(context); | |
| 220 for (size_t i = 0; i < zeroLengthLineCaps->size(); ++i) { | 277 for (size_t i = 0; i < zeroLengthLineCaps->size(); ++i) { |
| 221 usePath = zeroLengthLinecapPath((*zeroLengthLineCaps)[i]); | 278 FloatRect subpathRect = LayoutSVGPath::zeroLengthSubpathRect((*zeroLengt
hLineCaps)[i], m_renderSVGShape.strokeWidth()); |
| 279 tempPath.clear(); |
| 280 if (m_renderSVGShape.style()->svgStyle().capStyle() == SquareCap) |
| 281 tempPath.addRect(subpathRect); |
| 282 else |
| 283 tempPath.addEllipse(subpathRect); |
| 284 // This open-codes LayoutSVGShape::nonScalingStrokePath, because the |
| 285 // requirements here differ (we have a temporary path that we can |
| 286 // mutate.) |
| 222 if (m_renderSVGShape.hasNonScalingStroke()) | 287 if (m_renderSVGShape.hasNonScalingStroke()) |
| 223 usePath = m_renderSVGShape.nonScalingStrokePath(usePath, nonScalingT
ransform); | 288 tempPath.transform(nonScalingTransform); |
| 224 context->fillPath(*usePath); | 289 context->drawPath(tempPath.skPath(), fillPaint); |
| 225 } | 290 } |
| 226 } | 291 } |
| 227 | 292 |
| 228 Path* SVGShapePainter::zeroLengthLinecapPath(const FloatPoint& linecapPosition)
const | |
| 229 { | |
| 230 DEFINE_STATIC_LOCAL(Path, tempPath, ()); | |
| 231 | |
| 232 tempPath.clear(); | |
| 233 if (m_renderSVGShape.style()->svgStyle().capStyle() == SquareCap) | |
| 234 tempPath.addRect(LayoutSVGPath::zeroLengthSubpathRect(linecapPosition, m
_renderSVGShape.strokeWidth())); | |
| 235 else | |
| 236 tempPath.addEllipse(LayoutSVGPath::zeroLengthSubpathRect(linecapPosition
, m_renderSVGShape.strokeWidth())); | |
| 237 | |
| 238 return &tempPath; | |
| 239 } | |
| 240 | |
| 241 } // namespace blink | 293 } // namespace blink |
| OLD | NEW |