OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> | 2 * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> |
3 * Copyright (C) 2004, 2005, 2008 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2008 Rob Buis <buis@kde.org> |
4 * Copyright (C) 2005, 2007 Eric Seidel <eric@webkit.org> | 4 * Copyright (C) 2005, 2007 Eric Seidel <eric@webkit.org> |
5 * Copyright (C) 2009 Google, Inc. | 5 * Copyright (C) 2009 Google, Inc. |
6 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> | 6 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> |
7 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 7 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
8 * Copyright (C) 2009 Jeff Schiller <codedread@gmail.com> | 8 * Copyright (C) 2009 Jeff Schiller <codedread@gmail.com> |
9 * | 9 * |
10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 | 93 |
94 bool RenderSVGPath::strokeContains(const FloatPoint& point, bool requiresStroke) | 94 bool RenderSVGPath::strokeContains(const FloatPoint& point, bool requiresStroke) |
95 { | 95 { |
96 if (!m_strokeAndMarkerBoundingBox.contains(point)) | 96 if (!m_strokeAndMarkerBoundingBox.contains(point)) |
97 return false; | 97 return false; |
98 | 98 |
99 Color fallbackColor; | 99 Color fallbackColor; |
100 if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style
(), fallbackColor)) | 100 if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style
(), fallbackColor)) |
101 return false; | 101 return false; |
102 | 102 |
103 if (shouldStrokeZeroLengthSubpath()) | |
104 return zeroLengthSubpathRect().contains(point); | |
105 | |
106 BoundingRectStrokeStyleApplier strokeStyle(this, style()); | 103 BoundingRectStrokeStyleApplier strokeStyle(this, style()); |
107 return m_path.strokeContains(&strokeStyle, point); | 104 return m_path.strokeContains(&strokeStyle, point); |
108 } | 105 } |
109 | 106 |
110 void RenderSVGPath::layout() | 107 void RenderSVGPath::layout() |
111 { | 108 { |
112 LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsL
ayout()); | 109 LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && selfNeedsL
ayout()); |
113 SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableE
lement*>(node()); | 110 SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableE
lement*>(node()); |
114 | 111 |
115 bool updateCachedBoundariesInParents = false; | 112 bool updateCachedBoundariesInParents = false; |
(...skipping 29 matching lines...) Expand all Loading... |
145 } | 142 } |
146 | 143 |
147 // If our bounds changed, notify the parents. | 144 // If our bounds changed, notify the parents. |
148 if (updateCachedBoundariesInParents) | 145 if (updateCachedBoundariesInParents) |
149 RenderSVGModelObject::setNeedsBoundariesUpdate(); | 146 RenderSVGModelObject::setNeedsBoundariesUpdate(); |
150 | 147 |
151 repainter.repaintAfterLayout(); | 148 repainter.repaintAfterLayout(); |
152 setNeedsLayout(false); | 149 setNeedsLayout(false); |
153 } | 150 } |
154 | 151 |
155 bool RenderSVGPath::shouldStrokeZeroLengthSubpath() const | |
156 { | |
157 // Spec(11.4): Any zero length subpath shall not be stroked if the ‘stroke-l
inecap’ property has a value of butt | |
158 // but shall be stroked if the ‘stroke-linecap’ property has a value of roun
d or square | |
159 return style()->svgStyle()->hasStroke() && style()->svgStyle()->capStyle() !
= ButtCap && !m_fillBoundingBox.width() && !m_fillBoundingBox.height(); | |
160 } | |
161 | |
162 FloatRect RenderSVGPath::zeroLengthSubpathRect() const | |
163 { | |
164 SVGElement* svgElement = static_cast<SVGElement*>(node()); | |
165 float strokeWidth = style()->svgStyle()->strokeWidth().value(svgElement); | |
166 return FloatRect(m_fillBoundingBox.x() - strokeWidth / 2, m_fillBoundingBox.
y() - strokeWidth / 2, strokeWidth, strokeWidth); | |
167 } | |
168 | |
169 void RenderSVGPath::setupSquareCapPath(Path*& usePath, int& applyMode) | |
170 { | |
171 // Spec(11.4): Any zero length subpath shall not be stroked if the ‘stroke-l
inecap’ property has a value of butt | |
172 // but shall be stroked if the ‘stroke-linecap’ property has a value of roun
d or square | |
173 DEFINE_STATIC_LOCAL(Path, tempPath, ()); | |
174 | |
175 applyMode = ApplyToFillMode; | |
176 usePath = &tempPath; | |
177 usePath->clear(); | |
178 if (style()->svgStyle()->capStyle() == SquareCap) | |
179 usePath->addRect(zeroLengthSubpathRect()); | |
180 else | |
181 usePath->addEllipse(zeroLengthSubpathRect()); | |
182 } | |
183 | |
184 bool RenderSVGPath::setupNonScalingStrokePath(Path*& usePath, GraphicsContextSta
teSaver& stateSaver) | |
185 { | |
186 DEFINE_STATIC_LOCAL(Path, tempPath, ()); | |
187 | |
188 SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableE
lement*>(node()); | |
189 AffineTransform nonScalingStrokeTransform = element->getScreenCTM(SVGLocatab
le::DisallowStyleUpdate); | |
190 if (!nonScalingStrokeTransform.isInvertible()) | |
191 return false; | |
192 | |
193 tempPath = m_path; | |
194 usePath = &tempPath; | |
195 tempPath.transform(nonScalingStrokeTransform); | |
196 | |
197 stateSaver.save(); | |
198 stateSaver.context()->concatCTM(nonScalingStrokeTransform.inverse()); | |
199 return true; | |
200 } | |
201 | |
202 void RenderSVGPath::fillAndStrokePath(GraphicsContext* context) | 152 void RenderSVGPath::fillAndStrokePath(GraphicsContext* context) |
203 { | 153 { |
204 RenderStyle* style = this->style(); | 154 RenderStyle* style = this->style(); |
205 | 155 |
206 Color fallbackColor; | 156 Color fallbackColor; |
207 if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintin
gResource(this, style, fallbackColor)) { | 157 if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintin
gResource(this, style, fallbackColor)) { |
208 if (fillPaintingResource->applyResource(this, style, context, ApplyToFil
lMode)) | 158 if (fillPaintingResource->applyResource(this, style, context, ApplyToFil
lMode)) |
209 fillPaintingResource->postApplyResource(this, context, ApplyToFillMo
de, &m_path); | 159 fillPaintingResource->postApplyResource(this, context, ApplyToFillMo
de, &m_path); |
210 else if (fallbackColor.isValid()) { | 160 else if (fallbackColor.isValid()) { |
211 RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::s
haredSolidPaintingResource(); | 161 RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::s
haredSolidPaintingResource(); |
212 fallbackResource->setColor(fallbackColor); | 162 fallbackResource->setColor(fallbackColor); |
213 if (fallbackResource->applyResource(this, style, context, ApplyToFil
lMode)) | 163 if (fallbackResource->applyResource(this, style, context, ApplyToFil
lMode)) |
214 fallbackResource->postApplyResource(this, context, ApplyToFillMo
de, &m_path); | 164 fallbackResource->postApplyResource(this, context, ApplyToFillMo
de, &m_path); |
215 } | 165 } |
216 } | 166 } |
217 | 167 |
218 fallbackColor = Color(); | 168 fallbackColor = Color(); |
219 RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintin
gResource(this, style, fallbackColor); | 169 RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintin
gResource(this, style, fallbackColor); |
220 if (!strokePaintingResource) | 170 if (!strokePaintingResource) |
221 return; | 171 return; |
222 | 172 |
223 Path* usePath = &m_path; | 173 Path path; |
224 int applyMode = ApplyToStrokeMode; | |
225 | 174 |
226 bool nonScalingStroke = style->svgStyle()->vectorEffect() == VE_NON_SCALING_
STROKE; | 175 bool nonScalingStroke = style->svgStyle()->vectorEffect() == VE_NON_SCALING_
STROKE; |
227 | 176 |
228 GraphicsContextStateSaver stateSaver(*context, false); | 177 GraphicsContextStateSaver stateSaver(*context, false); |
| 178 if (nonScalingStroke) { |
| 179 SVGStyledTransformableElement* element = static_cast<SVGStyledTransforma
bleElement*>(node()); |
| 180 AffineTransform nonScalingStrokeTransform = element->getScreenCTM(SVGLoc
atable::DisallowStyleUpdate); |
| 181 if (!nonScalingStrokeTransform.isInvertible()) |
| 182 return; |
229 | 183 |
230 // Spec(11.4): Any zero length subpath shall not be stroked if the ‘stroke-l
inecap’ property has a value of butt | 184 path = m_path; |
231 // but shall be stroked if the ‘stroke-linecap’ property has a value of roun
d or square | 185 path.transform(nonScalingStrokeTransform); |
232 // FIXME: this does not work for zero-length subpaths, only when total path
is zero-length | 186 |
233 if (shouldStrokeZeroLengthSubpath()) | 187 stateSaver.save(); |
234 setupSquareCapPath(usePath, applyMode); | 188 context->concatCTM(nonScalingStrokeTransform.inverse()); |
235 else if (nonScalingStroke) { | |
236 if (!setupNonScalingStrokePath(usePath, stateSaver)) | |
237 return; | |
238 } | 189 } |
239 | 190 |
240 if (strokePaintingResource->applyResource(this, style, context, applyMode)) | 191 if (strokePaintingResource->applyResource(this, style, context, ApplyToStrok
eMode)) |
241 strokePaintingResource->postApplyResource(this, context, applyMode, useP
ath); | 192 strokePaintingResource->postApplyResource(this, context, ApplyToStrokeMo
de, nonScalingStroke ? &path : &m_path); |
242 else if (fallbackColor.isValid()) { | 193 else if (fallbackColor.isValid()) { |
243 RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::share
dSolidPaintingResource(); | 194 RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::share
dSolidPaintingResource(); |
244 fallbackResource->setColor(fallbackColor); | 195 fallbackResource->setColor(fallbackColor); |
245 if (fallbackResource->applyResource(this, style, context, applyMode)) | 196 if (fallbackResource->applyResource(this, style, context, ApplyToStrokeM
ode)) |
246 fallbackResource->postApplyResource(this, context, applyMode, usePat
h); | 197 fallbackResource->postApplyResource(this, context, ApplyToStrokeMode
, nonScalingStroke ? &path : &m_path); |
247 } | 198 } |
248 } | 199 } |
249 | 200 |
250 void RenderSVGPath::paint(PaintInfo& paintInfo, const LayoutPoint&) | 201 void RenderSVGPath::paint(PaintInfo& paintInfo, const LayoutPoint&) |
251 { | 202 { |
252 if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN
|| m_path.isEmpty()) | 203 if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN
|| m_path.isEmpty()) |
253 return; | 204 return; |
254 | 205 |
255 FloatRect boundingBox = repaintRectInLocalCoordinates(); | 206 FloatRect boundingBox = repaintRectInLocalCoordinates(); |
256 if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTr
ansform, paintInfo)) | 207 if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTr
ansform, paintInfo)) |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 if (m_path.isEmpty()) { | 303 if (m_path.isEmpty()) { |
353 m_fillBoundingBox = FloatRect(); | 304 m_fillBoundingBox = FloatRect(); |
354 m_strokeAndMarkerBoundingBox = FloatRect(); | 305 m_strokeAndMarkerBoundingBox = FloatRect(); |
355 m_repaintBoundingBox = FloatRect(); | 306 m_repaintBoundingBox = FloatRect(); |
356 return; | 307 return; |
357 } | 308 } |
358 | 309 |
359 // Cache _unclipped_ fill bounding box, used for calculations in resources | 310 // Cache _unclipped_ fill bounding box, used for calculations in resources |
360 m_fillBoundingBox = m_path.boundingRect(); | 311 m_fillBoundingBox = m_path.boundingRect(); |
361 | 312 |
362 // Spec(11.4): Any zero length subpath shall not be stroked if the ‘stroke-l
inecap’ property has a value of butt | |
363 // but shall be stroked if the ‘stroke-linecap’ property has a value of roun
d or square | |
364 if (shouldStrokeZeroLengthSubpath()) { | |
365 m_strokeAndMarkerBoundingBox = zeroLengthSubpathRect(); | |
366 // Cache smallest possible repaint rectangle | |
367 m_repaintBoundingBox = m_strokeAndMarkerBoundingBox; | |
368 SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBound
ingBox); | |
369 return; | |
370 } | |
371 | |
372 // Cache _unclipped_ stroke bounding box, used for calculations in resources
(includes marker boundaries) | 313 // Cache _unclipped_ stroke bounding box, used for calculations in resources
(includes marker boundaries) |
373 m_strokeAndMarkerBoundingBox = m_fillBoundingBox; | 314 m_strokeAndMarkerBoundingBox = m_fillBoundingBox; |
374 | 315 |
375 const SVGRenderStyle* svgStyle = style()->svgStyle(); | 316 const SVGRenderStyle* svgStyle = style()->svgStyle(); |
376 if (svgStyle->hasStroke()) { | 317 if (svgStyle->hasStroke()) { |
377 BoundingRectStrokeStyleApplier strokeStyle(this, style()); | 318 BoundingRectStrokeStyleApplier strokeStyle(this, style()); |
378 m_strokeAndMarkerBoundingBox.unite(m_path.strokeBoundingRect(&strokeStyl
e)); | 319 m_strokeAndMarkerBoundingBox.unite(m_path.strokeBoundingRect(&strokeStyl
e)); |
379 } | 320 } |
380 | 321 |
381 if (svgStyle->hasMarkers()) { | 322 if (svgStyle->hasMarkers()) { |
382 FloatRect markerBounds = calculateMarkerBoundsIfNeeded(); | 323 FloatRect markerBounds = calculateMarkerBoundsIfNeeded(); |
383 if (!markerBounds.isEmpty()) | 324 if (!markerBounds.isEmpty()) |
384 m_strokeAndMarkerBoundingBox.unite(markerBounds); | 325 m_strokeAndMarkerBoundingBox.unite(markerBounds); |
385 } | 326 } |
386 | 327 |
387 // Cache smallest possible repaint rectangle | 328 // Cache smallest possible repaint rectangle |
388 m_repaintBoundingBox = m_strokeAndMarkerBoundingBox; | 329 m_repaintBoundingBox = m_strokeAndMarkerBoundingBox; |
389 SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingB
ox); | 330 SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingB
ox); |
390 } | 331 } |
391 | 332 |
392 } | 333 } |
393 | 334 |
394 #endif // ENABLE(SVG) | 335 #endif // ENABLE(SVG) |
OLD | NEW |