| 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 |