OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 #include "core/paint/SVGShapePainter.h" |
| 7 |
| 8 #include "core/paint/ObjectPainter.h" |
| 9 #include "core/paint/SVGMarkerPainter.h" |
| 10 #include "core/rendering/GraphicsContextAnnotator.h" |
| 11 #include "core/rendering/PaintInfo.h" |
| 12 #include "core/rendering/svg/RenderSVGPath.h" |
| 13 #include "core/rendering/svg/RenderSVGShape.h" |
| 14 #include "core/rendering/svg/SVGMarkerData.h" |
| 15 #include "core/rendering/svg/SVGRenderSupport.h" |
| 16 #include "core/rendering/svg/SVGRenderingContext.h" |
| 17 #include "core/rendering/svg/SVGResources.h" |
| 18 #include "core/rendering/svg/SVGResourcesCache.h" |
| 19 |
| 20 namespace blink { |
| 21 |
| 22 static bool setupNonScalingStrokeContext(AffineTransform& strokeTransform, Graph
icsContextStateSaver& stateSaver) |
| 23 { |
| 24 if (!strokeTransform.isInvertible()) |
| 25 return false; |
| 26 |
| 27 stateSaver.save(); |
| 28 stateSaver.context()->concatCTM(strokeTransform.inverse()); |
| 29 return true; |
| 30 } |
| 31 |
| 32 static void useStrokeStyleToFill(GraphicsContext* context) |
| 33 { |
| 34 if (Gradient* gradient = context->strokeGradient()) |
| 35 context->setFillGradient(gradient); |
| 36 else if (Pattern* pattern = context->strokePattern()) |
| 37 context->setFillPattern(pattern); |
| 38 else |
| 39 context->setFillColor(context->strokeColor()); |
| 40 } |
| 41 |
| 42 void SVGShapePainter::paint(PaintInfo& paintInfo) |
| 43 { |
| 44 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderSVGShape); |
| 45 if (paintInfo.phase != PaintPhaseForeground |
| 46 || m_renderSVGShape.style()->visibility() == HIDDEN |
| 47 || m_renderSVGShape.isShapeEmpty()) |
| 48 return; |
| 49 |
| 50 FloatRect boundingBox = m_renderSVGShape.paintInvalidationRectInLocalCoordin
ates(); |
| 51 if (!SVGRenderSupport::paintInfoIntersectsPaintInvalidationRect(boundingBox,
m_renderSVGShape.localTransform(), paintInfo)) |
| 52 return; |
| 53 |
| 54 PaintInfo childPaintInfo(paintInfo); |
| 55 |
| 56 GraphicsContextStateSaver stateSaver(*childPaintInfo.context); |
| 57 childPaintInfo.applyTransform(m_renderSVGShape.localTransform()); |
| 58 |
| 59 SVGRenderingContext renderingContext(&m_renderSVGShape, childPaintInfo); |
| 60 |
| 61 if (renderingContext.isRenderingPrepared()) { |
| 62 const SVGRenderStyle& svgStyle = m_renderSVGShape.style()->svgStyle(); |
| 63 if (svgStyle.shapeRendering() == SR_CRISPEDGES) |
| 64 childPaintInfo.context->setShouldAntialias(false); |
| 65 |
| 66 for (int i = 0; i < 3; i++) { |
| 67 switch (svgStyle.paintOrderType(i)) { |
| 68 case PT_FILL: { |
| 69 GraphicsContextStateSaver stateSaver(*childPaintInfo.context, fa
lse); |
| 70 if (!SVGRenderSupport::updateGraphicsContext(stateSaver, m_rende
rSVGShape.style(), m_renderSVGShape, ApplyToFillMode)) |
| 71 break; |
| 72 fillShape(childPaintInfo.context); |
| 73 break; |
| 74 } |
| 75 case PT_STROKE: |
| 76 if (svgStyle.hasVisibleStroke()) { |
| 77 GraphicsContextStateSaver stateSaver(*childPaintInfo.context
, false); |
| 78 AffineTransform nonScalingTransform; |
| 79 const AffineTransform* additionalPaintServerTransform = 0; |
| 80 |
| 81 if (m_renderSVGShape.hasNonScalingStroke()) { |
| 82 nonScalingTransform = m_renderSVGShape.nonScalingStrokeT
ransform(); |
| 83 if (!setupNonScalingStrokeContext(nonScalingTransform, s
tateSaver)) |
| 84 return; |
| 85 |
| 86 // Non-scaling stroke needs to reset the transform back
to the host transform. |
| 87 additionalPaintServerTransform = &nonScalingTransform; |
| 88 } |
| 89 |
| 90 if (!SVGRenderSupport::updateGraphicsContext(stateSaver, m_r
enderSVGShape.style(), m_renderSVGShape, ApplyToStrokeMode, additionalPaintServe
rTransform)) |
| 91 break; |
| 92 strokeShape(childPaintInfo.context); |
| 93 } |
| 94 break; |
| 95 case PT_MARKERS: |
| 96 paintMarkers(childPaintInfo); |
| 97 break; |
| 98 default: |
| 99 ASSERT_NOT_REACHED(); |
| 100 break; |
| 101 } |
| 102 } |
| 103 } |
| 104 |
| 105 if (m_renderSVGShape.style()->outlineWidth()) |
| 106 ObjectPainter(m_renderSVGShape).paintOutline(childPaintInfo, IntRect(bou
ndingBox)); |
| 107 } |
| 108 |
| 109 void SVGShapePainter::fillShape(GraphicsContext* context) |
| 110 { |
| 111 switch (m_renderSVGShape.geometryCodePath()) { |
| 112 case RectGeometryFastPath: |
| 113 context->fillRect(m_renderSVGShape.objectBoundingBox()); |
| 114 break; |
| 115 case EllipseGeometryFastPath: |
| 116 context->fillEllipse(m_renderSVGShape.objectBoundingBox()); |
| 117 break; |
| 118 default: |
| 119 context->fillPath(m_renderSVGShape.path()); |
| 120 } |
| 121 } |
| 122 |
| 123 void SVGShapePainter::strokeShape(GraphicsContext* context) |
| 124 { |
| 125 if (!m_renderSVGShape.style()->svgStyle().hasVisibleStroke()) |
| 126 return; |
| 127 |
| 128 switch (m_renderSVGShape.geometryCodePath()) { |
| 129 case RectGeometryFastPath: |
| 130 context->strokeRect(m_renderSVGShape.objectBoundingBox(), m_renderSVGSha
pe.strokeWidth()); |
| 131 break; |
| 132 case EllipseGeometryFastPath: |
| 133 context->strokeEllipse(m_renderSVGShape.objectBoundingBox()); |
| 134 break; |
| 135 default: |
| 136 ASSERT(m_renderSVGShape.hasPath()); |
| 137 Path* usePath = &m_renderSVGShape.path(); |
| 138 if (m_renderSVGShape.hasNonScalingStroke()) |
| 139 usePath = m_renderSVGShape.nonScalingStrokePath(usePath, m_renderSVG
Shape.nonScalingStrokeTransform()); |
| 140 context->strokePath(*usePath); |
| 141 strokeZeroLengthLineCaps(context); |
| 142 } |
| 143 } |
| 144 |
| 145 void SVGShapePainter::paintMarkers(PaintInfo& paintInfo) |
| 146 { |
| 147 const Vector<MarkerPosition>* markerPositions = m_renderSVGShape.markerPosit
ions(); |
| 148 if (!markerPositions || markerPositions->isEmpty()) |
| 149 return; |
| 150 |
| 151 SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(
&m_renderSVGShape); |
| 152 if (!resources) |
| 153 return; |
| 154 |
| 155 RenderSVGResourceMarker* markerStart = resources->markerStart(); |
| 156 RenderSVGResourceMarker* markerMid = resources->markerMid(); |
| 157 RenderSVGResourceMarker* markerEnd = resources->markerEnd(); |
| 158 if (!markerStart && !markerMid && !markerEnd) |
| 159 return; |
| 160 |
| 161 float strokeWidth = m_renderSVGShape.strokeWidth(); |
| 162 unsigned size = markerPositions->size(); |
| 163 for (unsigned i = 0; i < size; ++i) { |
| 164 if (RenderSVGResourceMarker* marker = SVGMarkerData::markerForType((*mar
kerPositions)[i].type, markerStart, markerMid, markerEnd)) |
| 165 SVGMarkerPainter(*marker).paint(paintInfo, (*markerPositions)[i], st
rokeWidth); |
| 166 } |
| 167 } |
| 168 |
| 169 void SVGShapePainter::strokeZeroLengthLineCaps(GraphicsContext* context) |
| 170 { |
| 171 const Vector<FloatPoint>* zeroLengthLineCaps = m_renderSVGShape.zeroLengthLi
neCaps(); |
| 172 if (!zeroLengthLineCaps || zeroLengthLineCaps->isEmpty()) |
| 173 return; |
| 174 |
| 175 Path* usePath; |
| 176 AffineTransform nonScalingTransform; |
| 177 |
| 178 if (m_renderSVGShape.hasNonScalingStroke()) |
| 179 nonScalingTransform = m_renderSVGShape.nonScalingStrokeTransform(); |
| 180 |
| 181 GraphicsContextStateSaver stateSaver(*context, true); |
| 182 useStrokeStyleToFill(context); |
| 183 for (size_t i = 0; i < zeroLengthLineCaps->size(); ++i) { |
| 184 usePath = zeroLengthLinecapPath((*zeroLengthLineCaps)[i]); |
| 185 if (m_renderSVGShape.hasNonScalingStroke()) |
| 186 usePath = m_renderSVGShape.nonScalingStrokePath(usePath, nonScalingT
ransform); |
| 187 context->fillPath(*usePath); |
| 188 } |
| 189 } |
| 190 |
| 191 Path* SVGShapePainter::zeroLengthLinecapPath(const FloatPoint& linecapPosition)
const |
| 192 { |
| 193 DEFINE_STATIC_LOCAL(Path, tempPath, ()); |
| 194 |
| 195 tempPath.clear(); |
| 196 if (m_renderSVGShape.style()->svgStyle().capStyle() == SquareCap) |
| 197 tempPath.addRect(RenderSVGPath::zeroLengthSubpathRect(linecapPosition, m
_renderSVGShape.strokeWidth())); |
| 198 else |
| 199 tempPath.addEllipse(RenderSVGPath::zeroLengthSubpathRect(linecapPosition
, m_renderSVGShape.strokeWidth())); |
| 200 |
| 201 return &tempPath; |
| 202 } |
| 203 |
| 204 } // namespace blink |
OLD | NEW |