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/svg/LayoutSVGResourceMarker.h" | 8 #include "core/layout/svg/LayoutSVGResourceMarker.h" |
9 #include "core/layout/svg/LayoutSVGShape.h" | 9 #include "core/layout/svg/LayoutSVGShape.h" |
10 #include "core/layout/svg/SVGLayoutSupport.h" | 10 #include "core/layout/svg/SVGLayoutSupport.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 #include "wtf/Optional.h" | 25 #include "wtf/Optional.h" |
26 | 26 |
27 namespace blink { | 27 namespace blink { |
28 | 28 |
29 static bool setupNonScalingStrokeContext(AffineTransform& strokeTransform, Graph
icsContextStateSaver& stateSaver) | 29 static bool setupNonScalingStrokeContext(AffineTransform& strokeTransform, Graph
icsContextStateSaver& stateSaver) |
30 { | 30 { |
31 if (!strokeTransform.isInvertible()) | 31 if (!strokeTransform.isInvertible()) |
32 return false; | 32 return false; |
33 | 33 |
34 stateSaver.save(); | 34 stateSaver.save(); |
35 stateSaver.context()->concatCTM(strokeTransform.inverse()); | 35 stateSaver.context().concatCTM(strokeTransform.inverse()); |
36 return true; | 36 return true; |
37 } | 37 } |
38 | 38 |
39 static SkPath::FillType fillRuleFromStyle(const PaintInfo& paintInfo, const SVGC
omputedStyle& svgStyle) | 39 static SkPath::FillType fillRuleFromStyle(const PaintInfo& paintInfo, const SVGC
omputedStyle& svgStyle) |
40 { | 40 { |
41 return WebCoreWindRuleToSkFillType(paintInfo.isRenderingClipPathAsMaskImage(
) ? svgStyle.clipRule() : svgStyle.fillRule()); | 41 return WebCoreWindRuleToSkFillType(paintInfo.isRenderingClipPathAsMaskImage(
) ? svgStyle.clipRule() : svgStyle.fillRule()); |
42 } | 42 } |
43 | 43 |
44 void SVGShapePainter::paint(const PaintInfo& paintInfo) | 44 void SVGShapePainter::paint(const PaintInfo& paintInfo) |
45 { | 45 { |
46 if (paintInfo.phase != PaintPhaseForeground | 46 if (paintInfo.phase != PaintPhaseForeground |
47 || m_layoutSVGShape.style()->visibility() == HIDDEN | 47 || m_layoutSVGShape.style()->visibility() == HIDDEN |
48 || m_layoutSVGShape.isShapeEmpty()) | 48 || m_layoutSVGShape.isShapeEmpty()) |
49 return; | 49 return; |
50 | 50 |
51 FloatRect boundingBox = m_layoutSVGShape.paintInvalidationRectInLocalCoordin
ates(); | 51 FloatRect boundingBox = m_layoutSVGShape.paintInvalidationRectInLocalCoordin
ates(); |
52 if (!paintInfo.cullRect().intersectsCullRect(m_layoutSVGShape.localTransform
(), boundingBox)) | 52 if (!paintInfo.cullRect().intersectsCullRect(m_layoutSVGShape.localTransform
(), boundingBox)) |
53 return; | 53 return; |
54 | 54 |
55 PaintInfo paintInfoBeforeFiltering(paintInfo); | 55 PaintInfo paintInfoBeforeFiltering(paintInfo); |
56 // Shapes cannot have children so do not call updateCullRect. | 56 // Shapes cannot have children so do not call updateCullRect. |
57 TransformRecorder transformRecorder(*paintInfoBeforeFiltering.context, m_lay
outSVGShape, m_layoutSVGShape.localTransform()); | 57 TransformRecorder transformRecorder(paintInfoBeforeFiltering.context, m_layo
utSVGShape, m_layoutSVGShape.localTransform()); |
58 { | 58 { |
59 SVGPaintContext paintContext(m_layoutSVGShape, paintInfoBeforeFiltering)
; | 59 SVGPaintContext paintContext(m_layoutSVGShape, paintInfoBeforeFiltering)
; |
60 if (paintContext.applyClipMaskAndFilterIfNecessary() && !LayoutObjectDra
wingRecorder::useCachedDrawingIfPossible(*paintContext.paintInfo().context, m_la
youtSVGShape, paintContext.paintInfo().phase, LayoutPoint())) { | 60 if (paintContext.applyClipMaskAndFilterIfNecessary() && !LayoutObjectDra
wingRecorder::useCachedDrawingIfPossible(paintContext.paintInfo().context, m_lay
outSVGShape, paintContext.paintInfo().phase, LayoutPoint())) { |
61 LayoutObjectDrawingRecorder recorder(*paintContext.paintInfo().conte
xt, m_layoutSVGShape, paintContext.paintInfo().phase, boundingBox, LayoutPoint()
); | 61 LayoutObjectDrawingRecorder recorder(paintContext.paintInfo().contex
t, m_layoutSVGShape, paintContext.paintInfo().phase, boundingBox, LayoutPoint())
; |
62 const SVGComputedStyle& svgStyle = m_layoutSVGShape.style()->svgStyl
e(); | 62 const SVGComputedStyle& svgStyle = m_layoutSVGShape.style()->svgStyl
e(); |
63 | 63 |
64 bool shouldAntiAlias = svgStyle.shapeRendering() != SR_CRISPEDGES; | 64 bool shouldAntiAlias = svgStyle.shapeRendering() != SR_CRISPEDGES; |
65 | 65 |
66 for (int i = 0; i < 3; i++) { | 66 for (int i = 0; i < 3; i++) { |
67 switch (svgStyle.paintOrderType(i)) { | 67 switch (svgStyle.paintOrderType(i)) { |
68 case PT_FILL: { | 68 case PT_FILL: { |
69 SkPaint fillPaint; | 69 SkPaint fillPaint; |
70 if (!SVGPaintContext::paintForLayoutObject(paintContext.pain
tInfo(), m_layoutSVGShape.styleRef(), m_layoutSVGShape, ApplyToFillMode, fillPai
nt)) | 70 if (!SVGPaintContext::paintForLayoutObject(paintContext.pain
tInfo(), m_layoutSVGShape.styleRef(), m_layoutSVGShape, ApplyToFillMode, fillPai
nt)) |
71 break; | 71 break; |
72 fillPaint.setAntiAlias(shouldAntiAlias); | 72 fillPaint.setAntiAlias(shouldAntiAlias); |
73 fillShape(paintContext.paintInfo().context, fillPaint, fillR
uleFromStyle(paintContext.paintInfo(), svgStyle)); | 73 fillShape(paintContext.paintInfo().context, fillPaint, fillR
uleFromStyle(paintContext.paintInfo(), svgStyle)); |
74 break; | 74 break; |
75 } | 75 } |
76 case PT_STROKE: | 76 case PT_STROKE: |
77 if (svgStyle.hasVisibleStroke()) { | 77 if (svgStyle.hasVisibleStroke()) { |
78 GraphicsContextStateSaver stateSaver(*paintContext.paint
Info().context, false); | 78 GraphicsContextStateSaver stateSaver(paintContext.paintI
nfo().context, false); |
79 AffineTransform nonScalingTransform; | 79 AffineTransform nonScalingTransform; |
80 const AffineTransform* additionalPaintServerTransform =
0; | 80 const AffineTransform* additionalPaintServerTransform =
0; |
81 | 81 |
82 if (m_layoutSVGShape.hasNonScalingStroke()) { | 82 if (m_layoutSVGShape.hasNonScalingStroke()) { |
83 nonScalingTransform = m_layoutSVGShape.nonScalingStr
okeTransform(); | 83 nonScalingTransform = m_layoutSVGShape.nonScalingStr
okeTransform(); |
84 if (!setupNonScalingStrokeContext(nonScalingTransfor
m, stateSaver)) | 84 if (!setupNonScalingStrokeContext(nonScalingTransfor
m, stateSaver)) |
85 return; | 85 return; |
86 | 86 |
87 // Non-scaling stroke needs to reset the transform b
ack to the host transform. | 87 // Non-scaling stroke needs to reset the transform b
ack to the host transform. |
88 additionalPaintServerTransform = &nonScalingTransfor
m; | 88 additionalPaintServerTransform = &nonScalingTransfor
m; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 m_path.setFillType(m_savedFillType); | 131 m_path.setFillType(m_savedFillType); |
132 } | 132 } |
133 | 133 |
134 const SkPath& skPath() const { return m_path; } | 134 const SkPath& skPath() const { return m_path; } |
135 | 135 |
136 private: | 136 private: |
137 SkPath& m_path; | 137 SkPath& m_path; |
138 SkPath::FillType m_savedFillType; | 138 SkPath::FillType m_savedFillType; |
139 }; | 139 }; |
140 | 140 |
141 void SVGShapePainter::fillShape(GraphicsContext* context, const SkPaint& paint,
SkPath::FillType fillType) | 141 void SVGShapePainter::fillShape(GraphicsContext& context, const SkPaint& paint,
SkPath::FillType fillType) |
142 { | 142 { |
143 switch (m_layoutSVGShape.geometryCodePath()) { | 143 switch (m_layoutSVGShape.geometryCodePath()) { |
144 case RectGeometryFastPath: | 144 case RectGeometryFastPath: |
145 context->drawRect(m_layoutSVGShape.objectBoundingBox(), paint); | 145 context.drawRect(m_layoutSVGShape.objectBoundingBox(), paint); |
146 break; | 146 break; |
147 case EllipseGeometryFastPath: | 147 case EllipseGeometryFastPath: |
148 context->drawOval(m_layoutSVGShape.objectBoundingBox(), paint); | 148 context.drawOval(m_layoutSVGShape.objectBoundingBox(), paint); |
149 break; | 149 break; |
150 default: { | 150 default: { |
151 PathWithTemporaryWindingRule pathWithWinding(m_layoutSVGShape.path(), fi
llType); | 151 PathWithTemporaryWindingRule pathWithWinding(m_layoutSVGShape.path(), fi
llType); |
152 context->drawPath(pathWithWinding.skPath(), paint); | 152 context.drawPath(pathWithWinding.skPath(), paint); |
153 } | 153 } |
154 } | 154 } |
155 } | 155 } |
156 | 156 |
157 void SVGShapePainter::strokeShape(GraphicsContext* context, const SkPaint& paint
) | 157 void SVGShapePainter::strokeShape(GraphicsContext& context, const SkPaint& paint
) |
158 { | 158 { |
159 if (!m_layoutSVGShape.style()->svgStyle().hasVisibleStroke()) | 159 if (!m_layoutSVGShape.style()->svgStyle().hasVisibleStroke()) |
160 return; | 160 return; |
161 | 161 |
162 switch (m_layoutSVGShape.geometryCodePath()) { | 162 switch (m_layoutSVGShape.geometryCodePath()) { |
163 case RectGeometryFastPath: | 163 case RectGeometryFastPath: |
164 context->drawRect(m_layoutSVGShape.objectBoundingBox(), paint); | 164 context.drawRect(m_layoutSVGShape.objectBoundingBox(), paint); |
165 break; | 165 break; |
166 case EllipseGeometryFastPath: | 166 case EllipseGeometryFastPath: |
167 context->drawOval(m_layoutSVGShape.objectBoundingBox(), paint); | 167 context.drawOval(m_layoutSVGShape.objectBoundingBox(), paint); |
168 break; | 168 break; |
169 default: | 169 default: |
170 ASSERT(m_layoutSVGShape.hasPath()); | 170 ASSERT(m_layoutSVGShape.hasPath()); |
171 Path* usePath = &m_layoutSVGShape.path(); | 171 Path* usePath = &m_layoutSVGShape.path(); |
172 if (m_layoutSVGShape.hasNonScalingStroke()) | 172 if (m_layoutSVGShape.hasNonScalingStroke()) |
173 usePath = m_layoutSVGShape.nonScalingStrokePath(usePath, m_layoutSVG
Shape.nonScalingStrokeTransform()); | 173 usePath = m_layoutSVGShape.nonScalingStrokePath(usePath, m_layoutSVG
Shape.nonScalingStrokeTransform()); |
174 context->drawPath(usePath->skPath(), paint); | 174 context.drawPath(usePath->skPath(), paint); |
175 } | 175 } |
176 } | 176 } |
177 | 177 |
178 void SVGShapePainter::paintMarkers(const PaintInfo& paintInfo, const FloatRect&
boundingBox) | 178 void SVGShapePainter::paintMarkers(const PaintInfo& paintInfo, const FloatRect&
boundingBox) |
179 { | 179 { |
180 const Vector<MarkerPosition>* markerPositions = m_layoutSVGShape.markerPosit
ions(); | 180 const Vector<MarkerPosition>* markerPositions = m_layoutSVGShape.markerPosit
ions(); |
181 if (!markerPositions || markerPositions->isEmpty()) | 181 if (!markerPositions || markerPositions->isEmpty()) |
182 return; | 182 return; |
183 | 183 |
184 SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(
&m_layoutSVGShape); | 184 SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(
&m_layoutSVGShape); |
185 if (!resources) | 185 if (!resources) |
186 return; | 186 return; |
187 | 187 |
188 LayoutSVGResourceMarker* markerStart = resources->markerStart(); | 188 LayoutSVGResourceMarker* markerStart = resources->markerStart(); |
189 LayoutSVGResourceMarker* markerMid = resources->markerMid(); | 189 LayoutSVGResourceMarker* markerMid = resources->markerMid(); |
190 LayoutSVGResourceMarker* markerEnd = resources->markerEnd(); | 190 LayoutSVGResourceMarker* markerEnd = resources->markerEnd(); |
191 if (!markerStart && !markerMid && !markerEnd) | 191 if (!markerStart && !markerMid && !markerEnd) |
192 return; | 192 return; |
193 | 193 |
194 float strokeWidth = m_layoutSVGShape.strokeWidth(); | 194 float strokeWidth = m_layoutSVGShape.strokeWidth(); |
195 unsigned size = markerPositions->size(); | 195 unsigned size = markerPositions->size(); |
196 | 196 |
197 for (unsigned i = 0; i < size; ++i) { | 197 for (unsigned i = 0; i < size; ++i) { |
198 if (LayoutSVGResourceMarker* marker = SVGMarkerData::markerForType((*mar
kerPositions)[i].type, markerStart, markerMid, markerEnd)) { | 198 if (LayoutSVGResourceMarker* marker = SVGMarkerData::markerForType((*mar
kerPositions)[i].type, markerStart, markerMid, markerEnd)) { |
199 SkPictureBuilder pictureBuilder(boundingBox, nullptr, paintInfo.cont
ext); | 199 SkPictureBuilder pictureBuilder(boundingBox, nullptr, &paintInfo.con
text); |
200 PaintInfo markerPaintInfo(paintInfo); | 200 PaintInfo markerPaintInfo(pictureBuilder.context(), paintInfo); |
201 markerPaintInfo.context = &pictureBuilder.context(); | |
202 | 201 |
203 // It's expensive to track the transformed paint cull rect for each | 202 // It's expensive to track the transformed paint cull rect for each |
204 // marker so just disable culling. The shape paint call will already | 203 // marker so just disable culling. The shape paint call will already |
205 // be culled if it is outside the paint info cull rect. | 204 // be culled if it is outside the paint info cull rect. |
206 markerPaintInfo.m_cullRect.m_rect = LayoutRect::infiniteIntRect(); | 205 markerPaintInfo.m_cullRect.m_rect = LayoutRect::infiniteIntRect(); |
207 | 206 |
208 paintMarker(markerPaintInfo, *marker, (*markerPositions)[i], strokeW
idth); | 207 paintMarker(markerPaintInfo, *marker, (*markerPositions)[i], strokeW
idth); |
209 pictureBuilder.endRecording()->playback(paintInfo.context->canvas())
; | 208 pictureBuilder.endRecording()->playback(paintInfo.context.canvas()); |
210 } | 209 } |
211 } | 210 } |
212 } | 211 } |
213 | 212 |
214 void SVGShapePainter::paintMarker(const PaintInfo& paintInfo, LayoutSVGResourceM
arker& marker, const MarkerPosition& position, float strokeWidth) | 213 void SVGShapePainter::paintMarker(const PaintInfo& paintInfo, LayoutSVGResourceM
arker& marker, const MarkerPosition& position, float strokeWidth) |
215 { | 214 { |
216 // An empty viewBox disables rendering. | 215 // An empty viewBox disables rendering. |
217 SVGMarkerElement* markerElement = toSVGMarkerElement(marker.element()); | 216 SVGMarkerElement* markerElement = toSVGMarkerElement(marker.element()); |
218 ASSERT(markerElement); | 217 ASSERT(markerElement); |
219 if (markerElement->hasAttribute(SVGNames::viewBoxAttr) && markerElement->vie
wBox()->currentValue()->isValid() && markerElement->viewBox()->currentValue()->v
alue().isEmpty()) | 218 if (markerElement->hasAttribute(SVGNames::viewBoxAttr) && markerElement->vie
wBox()->currentValue()->isValid() && markerElement->viewBox()->currentValue()->v
alue().isEmpty()) |
220 return; | 219 return; |
221 | 220 |
222 TransformRecorder transformRecorder(*paintInfo.context, marker, marker.marke
rTransformation(position.origin, position.angle, strokeWidth)); | 221 TransformRecorder transformRecorder(paintInfo.context, marker, marker.marker
Transformation(position.origin, position.angle, strokeWidth)); |
223 Optional<FloatClipRecorder> clipRecorder; | 222 Optional<FloatClipRecorder> clipRecorder; |
224 if (SVGLayoutSupport::isOverflowHidden(&marker)) | 223 if (SVGLayoutSupport::isOverflowHidden(&marker)) |
225 clipRecorder.emplace(*paintInfo.context, marker, paintInfo.phase, marker
.viewport()); | 224 clipRecorder.emplace(paintInfo.context, marker, paintInfo.phase, marker.
viewport()); |
226 SVGContainerPainter(marker).paint(paintInfo); | 225 SVGContainerPainter(marker).paint(paintInfo); |
227 } | 226 } |
228 | 227 |
229 } // namespace blink | 228 } // namespace blink |
OLD | NEW |