blob: cab5a00ea97f57767ee433f2dd3bbe85e9bc8832 [file] [log] [blame]
fmalita6ceef3d2016-07-26 18:46:34 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Hal Canaryc640d0d2018-06-13 09:59:02 -04008#include "SkSVGRenderContext.h"
9
fmalita397a5172016-08-08 11:38:55 -070010#include "SkCanvas.h"
Florin Malitaf543a602017-10-13 14:07:44 -040011#include "SkDashPathEffect.h"
Florin Malitae932d4b2016-12-01 13:35:11 -050012#include "SkPath.h"
fmalita2d961e02016-08-11 09:16:29 -070013#include "SkSVGAttribute.h"
fmalita28d5b722016-09-12 17:06:47 -070014#include "SkSVGNode.h"
fmalitabffc2562016-08-03 10:21:11 -070015#include "SkSVGTypes.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040016#include "SkTo.h"
fmalita6ceef3d2016-07-26 18:46:34 -070017
fmalitabffc2562016-08-03 10:21:11 -070018namespace {
19
20SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::LengthType t) {
21 switch (t) {
22 case SkSVGLengthContext::LengthType::kHorizontal:
23 return viewport.width();
24 case SkSVGLengthContext::LengthType::kVertical:
25 return viewport.height();
26 case SkSVGLengthContext::LengthType::kOther:
27 return SkScalarSqrt(viewport.width() * viewport.height());
28 }
29
30 SkASSERT(false); // Not reached.
31 return 0;
32}
33
fmalita280e2822016-08-17 14:51:03 -070034// Multipliers for DPI-relative units.
35constexpr SkScalar kINMultiplier = 1.00f;
36constexpr SkScalar kPTMultiplier = kINMultiplier / 72.272f;
37constexpr SkScalar kPCMultiplier = kPTMultiplier * 12;
38constexpr SkScalar kMMMultiplier = kINMultiplier / 25.4f;
39constexpr SkScalar kCMMultiplier = kMMMultiplier * 10;
40
fmalitabffc2562016-08-03 10:21:11 -070041} // anonymous ns
42
43SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const {
44 switch (l.unit()) {
45 case SkSVGLength::Unit::kNumber:
fmalita2d961e02016-08-11 09:16:29 -070046 // Fall through.
47 case SkSVGLength::Unit::kPX:
fmalitabffc2562016-08-03 10:21:11 -070048 return l.value();
fmalitabffc2562016-08-03 10:21:11 -070049 case SkSVGLength::Unit::kPercentage:
50 return l.value() * length_size_for_type(fViewport, t) / 100;
fmalita280e2822016-08-17 14:51:03 -070051 case SkSVGLength::Unit::kCM:
52 return l.value() * fDPI * kCMMultiplier;
53 case SkSVGLength::Unit::kMM:
54 return l.value() * fDPI * kMMMultiplier;
55 case SkSVGLength::Unit::kIN:
56 return l.value() * fDPI * kINMultiplier;
57 case SkSVGLength::Unit::kPT:
58 return l.value() * fDPI * kPTMultiplier;
59 case SkSVGLength::Unit::kPC:
60 return l.value() * fDPI * kPCMultiplier;
fmalitabffc2562016-08-03 10:21:11 -070061 default:
62 SkDebugf("unsupported unit type: <%d>\n", l.unit());
fmalita2d961e02016-08-11 09:16:29 -070063 return 0;
fmalitabffc2562016-08-03 10:21:11 -070064 }
fmalitabffc2562016-08-03 10:21:11 -070065}
66
fmalita397a5172016-08-08 11:38:55 -070067SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y,
68 const SkSVGLength& w, const SkSVGLength& h) const {
69 return SkRect::MakeXYWH(
70 this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal),
71 this->resolve(y, SkSVGLengthContext::LengthType::kVertical),
72 this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal),
73 this->resolve(h, SkSVGLengthContext::LengthType::kVertical));
74}
fmalita6ceef3d2016-07-26 18:46:34 -070075
fmalita2d961e02016-08-11 09:16:29 -070076namespace {
fmalita397a5172016-08-08 11:38:55 -070077
fmalita2d961e02016-08-11 09:16:29 -070078SkPaint::Cap toSkCap(const SkSVGLineCap& cap) {
79 switch (cap.type()) {
80 case SkSVGLineCap::Type::kButt:
81 return SkPaint::kButt_Cap;
82 case SkSVGLineCap::Type::kRound:
83 return SkPaint::kRound_Cap;
84 case SkSVGLineCap::Type::kSquare:
85 return SkPaint::kSquare_Cap;
86 default:
87 SkASSERT(false);
88 return SkPaint::kButt_Cap;
fmalita6ceef3d2016-07-26 18:46:34 -070089 }
fmalita6ceef3d2016-07-26 18:46:34 -070090}
91
fmalita2d961e02016-08-11 09:16:29 -070092SkPaint::Join toSkJoin(const SkSVGLineJoin& join) {
93 switch (join.type()) {
94 case SkSVGLineJoin::Type::kMiter:
95 return SkPaint::kMiter_Join;
96 case SkSVGLineJoin::Type::kRound:
97 return SkPaint::kRound_Join;
98 case SkSVGLineJoin::Type::kBevel:
99 return SkPaint::kBevel_Join;
100 default:
101 SkASSERT(false);
102 return SkPaint::kMiter_Join;
fmalita6ceef3d2016-07-26 18:46:34 -0700103 }
fmalita6ceef3d2016-07-26 18:46:34 -0700104}
105
fmalita28d5b722016-09-12 17:06:47 -0700106void applySvgPaint(const SkSVGRenderContext& ctx, const SkSVGPaint& svgPaint, SkPaint* p) {
fmalita2d961e02016-08-11 09:16:29 -0700107 switch (svgPaint.type()) {
108 case SkSVGPaint::Type::kColor:
109 p->setColor(SkColorSetA(svgPaint.color(), p->getAlpha()));
110 break;
fmalita28d5b722016-09-12 17:06:47 -0700111 case SkSVGPaint::Type::kIRI: {
112 const auto* node = ctx.findNodeById(svgPaint.iri());
113 if (!node || !node->asPaint(ctx, p)) {
114 p->setColor(SK_ColorTRANSPARENT);
115 }
116 break;
117 }
fmalita2d961e02016-08-11 09:16:29 -0700118 case SkSVGPaint::Type::kCurrentColor:
119 SkDebugf("unimplemented 'currentColor' paint type");
120 // Fall through.
121 case SkSVGPaint::Type::kNone:
122 // Fall through.
123 case SkSVGPaint::Type::kInherit:
124 break;
fmalita6ceef3d2016-07-26 18:46:34 -0700125 }
fmalita6ceef3d2016-07-26 18:46:34 -0700126}
127
fmalitaa26cab02016-08-29 05:54:42 -0700128inline uint8_t opacity_to_alpha(SkScalar o) {
129 return SkTo<uint8_t>(SkScalarRoundToInt(o * 255));
130}
131
fmalita2d961e02016-08-11 09:16:29 -0700132// Commit the selected attribute to the paint cache.
133template <SkSVGAttribute>
134void commitToPaint(const SkSVGPresentationAttributes&,
fmalita28d5b722016-09-12 17:06:47 -0700135 const SkSVGRenderContext&,
fmalita2d961e02016-08-11 09:16:29 -0700136 SkSVGPresentationContext*);
137
138template <>
139void commitToPaint<SkSVGAttribute::kFill>(const SkSVGPresentationAttributes& attrs,
fmalita28d5b722016-09-12 17:06:47 -0700140 const SkSVGRenderContext& ctx,
fmalita2d961e02016-08-11 09:16:29 -0700141 SkSVGPresentationContext* pctx) {
fmalita28d5b722016-09-12 17:06:47 -0700142 applySvgPaint(ctx, *attrs.fFill.get(), &pctx->fFillPaint);
fmalita6ceef3d2016-07-26 18:46:34 -0700143}
144
fmalita2d961e02016-08-11 09:16:29 -0700145template <>
146void commitToPaint<SkSVGAttribute::kStroke>(const SkSVGPresentationAttributes& attrs,
fmalita28d5b722016-09-12 17:06:47 -0700147 const SkSVGRenderContext& ctx,
fmalita2d961e02016-08-11 09:16:29 -0700148 SkSVGPresentationContext* pctx) {
fmalita28d5b722016-09-12 17:06:47 -0700149 applySvgPaint(ctx, *attrs.fStroke.get(), &pctx->fStrokePaint);
fmalita2d961e02016-08-11 09:16:29 -0700150}
151
152template <>
153void commitToPaint<SkSVGAttribute::kFillOpacity>(const SkSVGPresentationAttributes& attrs,
fmalita28d5b722016-09-12 17:06:47 -0700154 const SkSVGRenderContext&,
fmalita2d961e02016-08-11 09:16:29 -0700155 SkSVGPresentationContext* pctx) {
fmalitaa26cab02016-08-29 05:54:42 -0700156 pctx->fFillPaint.setAlpha(opacity_to_alpha(*attrs.fFillOpacity.get()));
fmalita2d961e02016-08-11 09:16:29 -0700157}
158
159template <>
Florin Malitaf543a602017-10-13 14:07:44 -0400160void commitToPaint<SkSVGAttribute::kStrokeDashArray>(const SkSVGPresentationAttributes& attrs,
161 const SkSVGRenderContext& ctx,
162 SkSVGPresentationContext* pctx) {
163 const auto& dashArray = attrs.fStrokeDashArray.get();
164 if (dashArray->type() != SkSVGDashArray::Type::kDashArray) {
165 return;
166 }
167
168 const auto count = dashArray->dashArray().count();
169 SkSTArray<128, SkScalar, true> intervals(count);
170 for (const auto& dash : dashArray->dashArray()) {
171 intervals.push_back(ctx.lengthContext().resolve(dash,
172 SkSVGLengthContext::LengthType::kOther));
173 }
174
175 if (count & 1) {
176 // If an odd number of values is provided, then the list of values
177 // is repeated to yield an even number of values.
178 intervals.push_back_n(count);
179 memcpy(intervals.begin() + count, intervals.begin(), count);
180 }
181
182 SkASSERT((intervals.count() & 1) == 0);
183
Florin Malitae1dadd72017-10-13 18:18:32 -0400184 const SkScalar phase = ctx.lengthContext().resolve(*pctx->fInherited.fStrokeDashOffset.get(),
185 SkSVGLengthContext::LengthType::kOther);
Florin Malitaf543a602017-10-13 14:07:44 -0400186 pctx->fStrokePaint.setPathEffect(SkDashPathEffect::Make(intervals.begin(),
187 intervals.count(),
188 phase));
189}
190
191template <>
Florin Malitae1dadd72017-10-13 18:18:32 -0400192void commitToPaint<SkSVGAttribute::kStrokeDashOffset>(const SkSVGPresentationAttributes&,
193 const SkSVGRenderContext&,
194 SkSVGPresentationContext*) {
195 // Applied via kStrokeDashArray.
196}
197
198template <>
fmalita2d961e02016-08-11 09:16:29 -0700199void commitToPaint<SkSVGAttribute::kStrokeLineCap>(const SkSVGPresentationAttributes& attrs,
fmalita28d5b722016-09-12 17:06:47 -0700200 const SkSVGRenderContext&,
fmalita2d961e02016-08-11 09:16:29 -0700201 SkSVGPresentationContext* pctx) {
202 const auto& cap = *attrs.fStrokeLineCap.get();
203 if (cap.type() != SkSVGLineCap::Type::kInherit) {
204 pctx->fStrokePaint.setStrokeCap(toSkCap(cap));
205 }
206}
207
208template <>
209void commitToPaint<SkSVGAttribute::kStrokeLineJoin>(const SkSVGPresentationAttributes& attrs,
fmalita28d5b722016-09-12 17:06:47 -0700210 const SkSVGRenderContext&,
fmalita2d961e02016-08-11 09:16:29 -0700211 SkSVGPresentationContext* pctx) {
212 const auto& join = *attrs.fStrokeLineJoin.get();
213 if (join.type() != SkSVGLineJoin::Type::kInherit) {
214 pctx->fStrokePaint.setStrokeJoin(toSkJoin(join));
215 }
216}
217
218template <>
Florin Malita4de426b2017-10-09 12:57:41 -0400219void commitToPaint<SkSVGAttribute::kStrokeMiterLimit>(const SkSVGPresentationAttributes& attrs,
220 const SkSVGRenderContext&,
221 SkSVGPresentationContext* pctx) {
222 pctx->fStrokePaint.setStrokeMiter(*attrs.fStrokeMiterLimit.get());
223}
224
225template <>
fmalita2d961e02016-08-11 09:16:29 -0700226void commitToPaint<SkSVGAttribute::kStrokeOpacity>(const SkSVGPresentationAttributes& attrs,
fmalita28d5b722016-09-12 17:06:47 -0700227 const SkSVGRenderContext&,
fmalita2d961e02016-08-11 09:16:29 -0700228 SkSVGPresentationContext* pctx) {
fmalitaa26cab02016-08-29 05:54:42 -0700229 pctx->fStrokePaint.setAlpha(opacity_to_alpha(*attrs.fStrokeOpacity.get()));
fmalita2d961e02016-08-11 09:16:29 -0700230}
231
232template <>
233void commitToPaint<SkSVGAttribute::kStrokeWidth>(const SkSVGPresentationAttributes& attrs,
fmalita28d5b722016-09-12 17:06:47 -0700234 const SkSVGRenderContext& ctx,
fmalita2d961e02016-08-11 09:16:29 -0700235 SkSVGPresentationContext* pctx) {
fmalita28d5b722016-09-12 17:06:47 -0700236 auto strokeWidth = ctx.lengthContext().resolve(*attrs.fStrokeWidth.get(),
237 SkSVGLengthContext::LengthType::kOther);
fmalita2d961e02016-08-11 09:16:29 -0700238 pctx->fStrokePaint.setStrokeWidth(strokeWidth);
239}
240
Florin Malitae932d4b2016-12-01 13:35:11 -0500241template <>
242void commitToPaint<SkSVGAttribute::kFillRule>(const SkSVGPresentationAttributes&,
243 const SkSVGRenderContext&,
244 SkSVGPresentationContext*) {
245 // Not part of the SkPaint state; applied to the path at render time.
246}
247
Florin Malita57a0edf2017-10-10 11:22:08 -0400248template <>
249void commitToPaint<SkSVGAttribute::kClipRule>(const SkSVGPresentationAttributes&,
250 const SkSVGRenderContext&,
251 SkSVGPresentationContext*) {
252 // Not part of the SkPaint state; applied to the path at clip time.
253}
254
Florin Malitaffe6ae42017-10-12 11:33:28 -0400255template <>
256void commitToPaint<SkSVGAttribute::kVisibility>(const SkSVGPresentationAttributes&,
257 const SkSVGRenderContext&,
258 SkSVGPresentationContext*) {
259 // Not part of the SkPaint state; queried to veto rendering.
260}
261
fmalita2d961e02016-08-11 09:16:29 -0700262} // anonymous ns
263
264SkSVGPresentationContext::SkSVGPresentationContext()
265 : fInherited(SkSVGPresentationAttributes::MakeInitial()) {
266
267 fFillPaint.setStyle(SkPaint::kFill_Style);
268 fStrokePaint.setStyle(SkPaint::kStroke_Style);
269
270 // TODO: drive AA off presentation attrs also (shape-rendering?)
271 fFillPaint.setAntiAlias(true);
272 fStrokePaint.setAntiAlias(true);
273
274 // Commit initial values to the paint cache.
fmalita28d5b722016-09-12 17:06:47 -0700275 SkCanvas dummyCanvas(0, 0);
276 SkSVGRenderContext dummy(&dummyCanvas, SkSVGIDMapper(), SkSVGLengthContext(SkSize::Make(0, 0)),
277 *this);
278
fmalita2d961e02016-08-11 09:16:29 -0700279 commitToPaint<SkSVGAttribute::kFill>(fInherited, dummy, this);
280 commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, dummy, this);
281 commitToPaint<SkSVGAttribute::kStroke>(fInherited, dummy, this);
282 commitToPaint<SkSVGAttribute::kStrokeLineCap>(fInherited, dummy, this);
283 commitToPaint<SkSVGAttribute::kStrokeLineJoin>(fInherited, dummy, this);
Florin Malita4de426b2017-10-09 12:57:41 -0400284 commitToPaint<SkSVGAttribute::kStrokeMiterLimit>(fInherited, dummy, this);
fmalita2d961e02016-08-11 09:16:29 -0700285 commitToPaint<SkSVGAttribute::kStrokeOpacity>(fInherited, dummy, this);
286 commitToPaint<SkSVGAttribute::kStrokeWidth>(fInherited, dummy, this);
fmalita6ceef3d2016-07-26 18:46:34 -0700287}
fmalita397a5172016-08-08 11:38:55 -0700288
289SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
fmalita28d5b722016-09-12 17:06:47 -0700290 const SkSVGIDMapper& mapper,
fmalita397a5172016-08-08 11:38:55 -0700291 const SkSVGLengthContext& lctx,
292 const SkSVGPresentationContext& pctx)
fmalita28d5b722016-09-12 17:06:47 -0700293 : fIDMapper(mapper)
294 , fLengthContext(lctx)
fmalita397a5172016-08-08 11:38:55 -0700295 , fPresentationContext(pctx)
296 , fCanvas(canvas)
297 , fCanvasSaveCount(canvas->getSaveCount()) {}
298
299SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
fmalita2d961e02016-08-11 09:16:29 -0700300 : SkSVGRenderContext(other.fCanvas,
fmalita28d5b722016-09-12 17:06:47 -0700301 other.fIDMapper,
fmalita2d961e02016-08-11 09:16:29 -0700302 *other.fLengthContext,
303 *other.fPresentationContext) {}
fmalita397a5172016-08-08 11:38:55 -0700304
Florin Malita1aa1bb62017-10-11 14:34:33 -0400305SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, SkCanvas* canvas)
306 : SkSVGRenderContext(canvas,
307 other.fIDMapper,
308 *other.fLengthContext,
309 *other.fPresentationContext) {}
310
fmalita397a5172016-08-08 11:38:55 -0700311SkSVGRenderContext::~SkSVGRenderContext() {
312 fCanvas->restoreToCount(fCanvasSaveCount);
313}
fmalita2d961e02016-08-11 09:16:29 -0700314
fmalita28d5b722016-09-12 17:06:47 -0700315const SkSVGNode* SkSVGRenderContext::findNodeById(const SkString& id) const {
316 const auto* v = fIDMapper.find(id);
317 return v ? v->get() : nullptr;
318}
319
fmalitabef51c22016-09-20 15:45:57 -0700320void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs,
321 uint32_t flags) {
fmalita2d961e02016-08-11 09:16:29 -0700322
323#define ApplyLazyInheritedAttribute(ATTR) \
324 do { \
325 /* All attributes should be defined on the inherited context. */ \
326 SkASSERT(fPresentationContext->fInherited.f ## ATTR.isValid()); \
327 const auto* value = attrs.f ## ATTR.getMaybeNull(); \
328 if (value && *value != *fPresentationContext->fInherited.f ## ATTR.get()) { \
329 /* Update the local attribute value */ \
330 fPresentationContext.writable()->fInherited.f ## ATTR.set(*value); \
331 /* Update the cached paints */ \
fmalita28d5b722016-09-12 17:06:47 -0700332 commitToPaint<SkSVGAttribute::k ## ATTR>(attrs, *this, \
fmalita2d961e02016-08-11 09:16:29 -0700333 fPresentationContext.writable()); \
334 } \
335 } while (false)
336
337 ApplyLazyInheritedAttribute(Fill);
338 ApplyLazyInheritedAttribute(FillOpacity);
Florin Malitae932d4b2016-12-01 13:35:11 -0500339 ApplyLazyInheritedAttribute(FillRule);
Florin Malita57a0edf2017-10-10 11:22:08 -0400340 ApplyLazyInheritedAttribute(ClipRule);
fmalita2d961e02016-08-11 09:16:29 -0700341 ApplyLazyInheritedAttribute(Stroke);
Florin Malitae1dadd72017-10-13 18:18:32 -0400342 ApplyLazyInheritedAttribute(StrokeDashOffset);
Florin Malitaf543a602017-10-13 14:07:44 -0400343 ApplyLazyInheritedAttribute(StrokeDashArray);
fmalita2d961e02016-08-11 09:16:29 -0700344 ApplyLazyInheritedAttribute(StrokeLineCap);
345 ApplyLazyInheritedAttribute(StrokeLineJoin);
Florin Malita4de426b2017-10-09 12:57:41 -0400346 ApplyLazyInheritedAttribute(StrokeMiterLimit);
fmalita2d961e02016-08-11 09:16:29 -0700347 ApplyLazyInheritedAttribute(StrokeOpacity);
348 ApplyLazyInheritedAttribute(StrokeWidth);
Florin Malitaffe6ae42017-10-12 11:33:28 -0400349 ApplyLazyInheritedAttribute(Visibility);
fmalita2d961e02016-08-11 09:16:29 -0700350
351#undef ApplyLazyInheritedAttribute
fmalita6fb06482016-08-15 12:45:11 -0700352
353 // Uninherited attributes. Only apply to the current context.
354
fmalitabef51c22016-09-20 15:45:57 -0700355 if (auto* opacity = attrs.fOpacity.getMaybeNull()) {
356 this->applyOpacity(opacity->value(), flags);
357 }
Florin Malitace8840e2016-12-08 09:26:47 -0500358
359 if (auto* clip = attrs.fClipPath.getMaybeNull()) {
360 this->applyClip(*clip);
361 }
fmalitabef51c22016-09-20 15:45:57 -0700362}
363
364void SkSVGRenderContext::applyOpacity(SkScalar opacity, uint32_t flags) {
365 if (opacity >= 1) {
366 return;
367 }
368
369 const bool hasFill = SkToBool(this->fillPaint());
370 const bool hasStroke = SkToBool(this->strokePaint());
371
372 // We can apply the opacity as paint alpha iif it only affects one atomic draw.
373 // For now, this means a) the target node doesn't have any descendants, and
374 // b) it only has a stroke or a fill (but not both). Going forward, we may need
375 // to refine this heuristic (e.g. to accommodate markers).
376 if ((flags & kLeaf) && (hasFill ^ hasStroke)) {
377 auto* pctx = fPresentationContext.writable();
378 if (hasFill) {
379 pctx->fFillPaint.setAlpha(
380 SkScalarRoundToInt(opacity * pctx->fFillPaint.getAlpha()));
381 } else {
382 pctx->fStrokePaint.setAlpha(
383 SkScalarRoundToInt(opacity * pctx->fStrokePaint.getAlpha()));
384 }
385 } else {
386 // Expensive, layer-based fall back.
fmalita6fb06482016-08-15 12:45:11 -0700387 SkPaint opacityPaint;
fmalitabef51c22016-09-20 15:45:57 -0700388 opacityPaint.setAlpha(opacity_to_alpha(opacity));
fmalita6fb06482016-08-15 12:45:11 -0700389 // Balanced in the destructor, via restoreToCount().
390 fCanvas->saveLayer(nullptr, &opacityPaint);
391 }
fmalita2d961e02016-08-11 09:16:29 -0700392}
393
Florin Malitab36be142017-10-11 14:11:16 -0400394void SkSVGRenderContext::saveOnce() {
395 // The canvas only needs to be saved once, per local SkSVGRenderContext.
396 if (fCanvas->getSaveCount() == fCanvasSaveCount) {
397 fCanvas->save();
398 }
399
400 SkASSERT(fCanvas->getSaveCount() > fCanvasSaveCount);
401}
402
Florin Malitace8840e2016-12-08 09:26:47 -0500403void SkSVGRenderContext::applyClip(const SkSVGClip& clip) {
404 if (clip.type() != SkSVGClip::Type::kIRI) {
405 return;
406 }
407
408 const SkSVGNode* clipNode = this->findNodeById(clip.iri());
409 if (!clipNode || clipNode->tag() != SkSVGTag::kClipPath) {
410 return;
411 }
412
413 const SkPath clipPath = clipNode->asPath(*this);
414
Florin Malita7d529882016-12-08 16:04:24 -0500415 // We use the computed clip path in two ways:
416 //
417 // - apply to the current canvas, for drawing
418 // - track in the presentation context, for asPath() composition
419 //
420 // TODO: the two uses are exclusive, avoid canvas churn when non needed.
421
Florin Malitab36be142017-10-11 14:11:16 -0400422 this->saveOnce();
Florin Malitace8840e2016-12-08 09:26:47 -0500423
424 fCanvas->clipPath(clipPath, true);
Florin Malita7d529882016-12-08 16:04:24 -0500425 fClipPath.set(clipPath);
Florin Malitace8840e2016-12-08 09:26:47 -0500426}
427
fmalita2d961e02016-08-11 09:16:29 -0700428const SkPaint* SkSVGRenderContext::fillPaint() const {
429 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fFill.get()->type();
430 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fFillPaint : nullptr;
431}
432
433const SkPaint* SkSVGRenderContext::strokePaint() const {
434 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fStroke.get()->type();
435 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fStrokePaint : nullptr;
436}