blob: ee92c47d542ea39744f4487e4007f8a5ed916a7c [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
fmalita397a5172016-08-08 11:38:55 -07008#include "SkCanvas.h"
fmalita2d961e02016-08-11 09:16:29 -07009#include "SkSVGAttribute.h"
fmalita6ceef3d2016-07-26 18:46:34 -070010#include "SkSVGRenderContext.h"
fmalitabffc2562016-08-03 10:21:11 -070011#include "SkSVGTypes.h"
fmalita6ceef3d2016-07-26 18:46:34 -070012
fmalitabffc2562016-08-03 10:21:11 -070013namespace {
14
15SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::LengthType t) {
16 switch (t) {
17 case SkSVGLengthContext::LengthType::kHorizontal:
18 return viewport.width();
19 case SkSVGLengthContext::LengthType::kVertical:
20 return viewport.height();
21 case SkSVGLengthContext::LengthType::kOther:
22 return SkScalarSqrt(viewport.width() * viewport.height());
23 }
24
25 SkASSERT(false); // Not reached.
26 return 0;
27}
28
29} // anonymous ns
30
31SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const {
32 switch (l.unit()) {
33 case SkSVGLength::Unit::kNumber:
fmalita2d961e02016-08-11 09:16:29 -070034 // Fall through.
35 case SkSVGLength::Unit::kPX:
fmalitabffc2562016-08-03 10:21:11 -070036 return l.value();
fmalitabffc2562016-08-03 10:21:11 -070037 case SkSVGLength::Unit::kPercentage:
38 return l.value() * length_size_for_type(fViewport, t) / 100;
fmalitabffc2562016-08-03 10:21:11 -070039 default:
40 SkDebugf("unsupported unit type: <%d>\n", l.unit());
fmalita2d961e02016-08-11 09:16:29 -070041 return 0;
fmalitabffc2562016-08-03 10:21:11 -070042 }
fmalitabffc2562016-08-03 10:21:11 -070043}
44
fmalita397a5172016-08-08 11:38:55 -070045SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y,
46 const SkSVGLength& w, const SkSVGLength& h) const {
47 return SkRect::MakeXYWH(
48 this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal),
49 this->resolve(y, SkSVGLengthContext::LengthType::kVertical),
50 this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal),
51 this->resolve(h, SkSVGLengthContext::LengthType::kVertical));
52}
fmalita6ceef3d2016-07-26 18:46:34 -070053
fmalita2d961e02016-08-11 09:16:29 -070054namespace {
fmalita397a5172016-08-08 11:38:55 -070055
fmalita2d961e02016-08-11 09:16:29 -070056SkPaint::Cap toSkCap(const SkSVGLineCap& cap) {
57 switch (cap.type()) {
58 case SkSVGLineCap::Type::kButt:
59 return SkPaint::kButt_Cap;
60 case SkSVGLineCap::Type::kRound:
61 return SkPaint::kRound_Cap;
62 case SkSVGLineCap::Type::kSquare:
63 return SkPaint::kSquare_Cap;
64 default:
65 SkASSERT(false);
66 return SkPaint::kButt_Cap;
fmalita6ceef3d2016-07-26 18:46:34 -070067 }
fmalita6ceef3d2016-07-26 18:46:34 -070068}
69
fmalita2d961e02016-08-11 09:16:29 -070070SkPaint::Join toSkJoin(const SkSVGLineJoin& join) {
71 switch (join.type()) {
72 case SkSVGLineJoin::Type::kMiter:
73 return SkPaint::kMiter_Join;
74 case SkSVGLineJoin::Type::kRound:
75 return SkPaint::kRound_Join;
76 case SkSVGLineJoin::Type::kBevel:
77 return SkPaint::kBevel_Join;
78 default:
79 SkASSERT(false);
80 return SkPaint::kMiter_Join;
fmalita6ceef3d2016-07-26 18:46:34 -070081 }
fmalita6ceef3d2016-07-26 18:46:34 -070082}
83
fmalita2d961e02016-08-11 09:16:29 -070084void applySvgPaint(const SkSVGPaint& svgPaint, SkPaint* p) {
85 switch (svgPaint.type()) {
86 case SkSVGPaint::Type::kColor:
87 p->setColor(SkColorSetA(svgPaint.color(), p->getAlpha()));
88 break;
89 case SkSVGPaint::Type::kCurrentColor:
90 SkDebugf("unimplemented 'currentColor' paint type");
91 // Fall through.
92 case SkSVGPaint::Type::kNone:
93 // Fall through.
94 case SkSVGPaint::Type::kInherit:
95 break;
fmalita6ceef3d2016-07-26 18:46:34 -070096 }
fmalita6ceef3d2016-07-26 18:46:34 -070097}
98
fmalita2d961e02016-08-11 09:16:29 -070099// Commit the selected attribute to the paint cache.
100template <SkSVGAttribute>
101void commitToPaint(const SkSVGPresentationAttributes&,
102 const SkSVGLengthContext&,
103 SkSVGPresentationContext*);
104
105template <>
106void commitToPaint<SkSVGAttribute::kFill>(const SkSVGPresentationAttributes& attrs,
107 const SkSVGLengthContext&,
108 SkSVGPresentationContext* pctx) {
109 applySvgPaint(*attrs.fFill.get(), &pctx->fFillPaint);
fmalita6ceef3d2016-07-26 18:46:34 -0700110}
111
fmalita2d961e02016-08-11 09:16:29 -0700112template <>
113void commitToPaint<SkSVGAttribute::kStroke>(const SkSVGPresentationAttributes& attrs,
114 const SkSVGLengthContext&,
115 SkSVGPresentationContext* pctx) {
116 applySvgPaint(*attrs.fStroke.get(), &pctx->fStrokePaint);
117}
118
119template <>
120void commitToPaint<SkSVGAttribute::kFillOpacity>(const SkSVGPresentationAttributes& attrs,
121 const SkSVGLengthContext&,
122 SkSVGPresentationContext* pctx) {
123 pctx->fFillPaint.setAlpha(static_cast<uint8_t>(*attrs.fFillOpacity.get() * 255));
124}
125
126template <>
127void commitToPaint<SkSVGAttribute::kStrokeLineCap>(const SkSVGPresentationAttributes& attrs,
128 const SkSVGLengthContext&,
129 SkSVGPresentationContext* pctx) {
130 const auto& cap = *attrs.fStrokeLineCap.get();
131 if (cap.type() != SkSVGLineCap::Type::kInherit) {
132 pctx->fStrokePaint.setStrokeCap(toSkCap(cap));
133 }
134}
135
136template <>
137void commitToPaint<SkSVGAttribute::kStrokeLineJoin>(const SkSVGPresentationAttributes& attrs,
138 const SkSVGLengthContext&,
139 SkSVGPresentationContext* pctx) {
140 const auto& join = *attrs.fStrokeLineJoin.get();
141 if (join.type() != SkSVGLineJoin::Type::kInherit) {
142 pctx->fStrokePaint.setStrokeJoin(toSkJoin(join));
143 }
144}
145
146template <>
147void commitToPaint<SkSVGAttribute::kStrokeOpacity>(const SkSVGPresentationAttributes& attrs,
148 const SkSVGLengthContext&,
149 SkSVGPresentationContext* pctx) {
150 pctx->fStrokePaint.setAlpha(static_cast<uint8_t>(*attrs.fStrokeOpacity.get() * 255));
151}
152
153template <>
154void commitToPaint<SkSVGAttribute::kStrokeWidth>(const SkSVGPresentationAttributes& attrs,
155 const SkSVGLengthContext& lctx,
156 SkSVGPresentationContext* pctx) {
157 auto strokeWidth = lctx.resolve(*attrs.fStrokeWidth.get(),
158 SkSVGLengthContext::LengthType::kOther);
159 pctx->fStrokePaint.setStrokeWidth(strokeWidth);
160}
161
162} // anonymous ns
163
164SkSVGPresentationContext::SkSVGPresentationContext()
165 : fInherited(SkSVGPresentationAttributes::MakeInitial()) {
166
167 fFillPaint.setStyle(SkPaint::kFill_Style);
168 fStrokePaint.setStyle(SkPaint::kStroke_Style);
169
170 // TODO: drive AA off presentation attrs also (shape-rendering?)
171 fFillPaint.setAntiAlias(true);
172 fStrokePaint.setAntiAlias(true);
173
174 // Commit initial values to the paint cache.
175 SkSVGLengthContext dummy(SkSize::Make(0, 0));
176 commitToPaint<SkSVGAttribute::kFill>(fInherited, dummy, this);
177 commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, dummy, this);
178 commitToPaint<SkSVGAttribute::kStroke>(fInherited, dummy, this);
179 commitToPaint<SkSVGAttribute::kStrokeLineCap>(fInherited, dummy, this);
180 commitToPaint<SkSVGAttribute::kStrokeLineJoin>(fInherited, dummy, this);
181 commitToPaint<SkSVGAttribute::kStrokeOpacity>(fInherited, dummy, this);
182 commitToPaint<SkSVGAttribute::kStrokeWidth>(fInherited, dummy, this);
fmalita6ceef3d2016-07-26 18:46:34 -0700183}
fmalita397a5172016-08-08 11:38:55 -0700184
185SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
186 const SkSVGLengthContext& lctx,
187 const SkSVGPresentationContext& pctx)
188 : fLengthContext(lctx)
189 , fPresentationContext(pctx)
190 , fCanvas(canvas)
191 , fCanvasSaveCount(canvas->getSaveCount()) {}
192
193SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
fmalita2d961e02016-08-11 09:16:29 -0700194 : SkSVGRenderContext(other.fCanvas,
195 *other.fLengthContext,
196 *other.fPresentationContext) {}
fmalita397a5172016-08-08 11:38:55 -0700197
198SkSVGRenderContext::~SkSVGRenderContext() {
199 fCanvas->restoreToCount(fCanvasSaveCount);
200}
fmalita2d961e02016-08-11 09:16:29 -0700201
202void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs) {
203
204#define ApplyLazyInheritedAttribute(ATTR) \
205 do { \
206 /* All attributes should be defined on the inherited context. */ \
207 SkASSERT(fPresentationContext->fInherited.f ## ATTR.isValid()); \
208 const auto* value = attrs.f ## ATTR.getMaybeNull(); \
209 if (value && *value != *fPresentationContext->fInherited.f ## ATTR.get()) { \
210 /* Update the local attribute value */ \
211 fPresentationContext.writable()->fInherited.f ## ATTR.set(*value); \
212 /* Update the cached paints */ \
213 commitToPaint<SkSVGAttribute::k ## ATTR>(attrs, *fLengthContext, \
214 fPresentationContext.writable()); \
215 } \
216 } while (false)
217
218 ApplyLazyInheritedAttribute(Fill);
219 ApplyLazyInheritedAttribute(FillOpacity);
220 ApplyLazyInheritedAttribute(Stroke);
221 ApplyLazyInheritedAttribute(StrokeLineCap);
222 ApplyLazyInheritedAttribute(StrokeLineJoin);
223 ApplyLazyInheritedAttribute(StrokeOpacity);
224 ApplyLazyInheritedAttribute(StrokeWidth);
225
226#undef ApplyLazyInheritedAttribute
227}
228
229const SkPaint* SkSVGRenderContext::fillPaint() const {
230 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fFill.get()->type();
231 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fFillPaint : nullptr;
232}
233
234const SkPaint* SkSVGRenderContext::strokePaint() const {
235 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fStroke.get()->type();
236 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fStrokePaint : nullptr;
237}