OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkCanvas.h" | 8 #include "SkCanvas.h" |
9 #include "SkSVGAttribute.h" | |
9 #include "SkSVGRenderContext.h" | 10 #include "SkSVGRenderContext.h" |
10 #include "SkSVGTypes.h" | 11 #include "SkSVGTypes.h" |
11 | 12 |
12 namespace { | 13 namespace { |
13 | 14 |
14 SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::Length Type t) { | 15 SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::Length Type t) { |
15 switch (t) { | 16 switch (t) { |
16 case SkSVGLengthContext::LengthType::kHorizontal: | 17 case SkSVGLengthContext::LengthType::kHorizontal: |
17 return viewport.width(); | 18 return viewport.width(); |
18 case SkSVGLengthContext::LengthType::kVertical: | 19 case SkSVGLengthContext::LengthType::kVertical: |
19 return viewport.height(); | 20 return viewport.height(); |
20 case SkSVGLengthContext::LengthType::kOther: | 21 case SkSVGLengthContext::LengthType::kOther: |
21 return SkScalarSqrt(viewport.width() * viewport.height()); | 22 return SkScalarSqrt(viewport.width() * viewport.height()); |
22 } | 23 } |
23 | 24 |
24 SkASSERT(false); // Not reached. | 25 SkASSERT(false); // Not reached. |
25 return 0; | 26 return 0; |
26 } | 27 } |
27 | 28 |
28 } // anonymous ns | 29 } // anonymous ns |
29 | 30 |
30 SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const { | 31 SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const { |
31 switch (l.unit()) { | 32 switch (l.unit()) { |
robertphillips
2016/08/11 13:38:54
// fall through ?
f(malita)
2016/08/11 14:03:16
Done.
| |
32 case SkSVGLength::Unit::kNumber: | 33 case SkSVGLength::Unit::kNumber: |
34 case SkSVGLength::Unit::kPX: | |
33 return l.value(); | 35 return l.value(); |
34 break; | 36 break; |
35 case SkSVGLength::Unit::kPercentage: | 37 case SkSVGLength::Unit::kPercentage: |
36 return l.value() * length_size_for_type(fViewport, t) / 100; | 38 return l.value() * length_size_for_type(fViewport, t) / 100; |
37 break; | 39 break; |
38 default: | 40 default: |
39 SkDebugf("unsupported unit type: <%d>\n", l.unit()); | 41 SkDebugf("unsupported unit type: <%d>\n", l.unit()); |
40 break; | 42 break; |
41 } | 43 } |
42 | 44 |
43 return 0; | 45 return 0; |
44 } | 46 } |
45 | 47 |
46 SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y, | 48 SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y, |
47 const SkSVGLength& w, const SkSVGLength& h) const { | 49 const SkSVGLength& w, const SkSVGLength& h) const { |
48 return SkRect::MakeXYWH( | 50 return SkRect::MakeXYWH( |
49 this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal), | 51 this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal), |
50 this->resolve(y, SkSVGLengthContext::LengthType::kVertical), | 52 this->resolve(y, SkSVGLengthContext::LengthType::kVertical), |
51 this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal), | 53 this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal), |
52 this->resolve(h, SkSVGLengthContext::LengthType::kVertical)); | 54 this->resolve(h, SkSVGLengthContext::LengthType::kVertical)); |
53 } | 55 } |
54 | 56 |
55 SkSVGPresentationContext::SkSVGPresentationContext() {} | 57 namespace { |
56 | 58 |
57 SkSVGPresentationContext::SkSVGPresentationContext(const SkSVGPresentationContex t& o) { | 59 SkPaint::Cap toSkCap(const SkSVGLineCap& cap) { |
58 this->initFrom(o); | 60 switch (cap.type()) { |
59 } | 61 case SkSVGLineCap::Type::kButt: |
60 | 62 return SkPaint::kButt_Cap; |
61 SkSVGPresentationContext& SkSVGPresentationContext::operator=(const SkSVGPresent ationContext& o) { | 63 case SkSVGLineCap::Type::kRound: |
62 this->initFrom(o); | 64 return SkPaint::kRound_Cap; |
63 return *this; | 65 case SkSVGLineCap::Type::kSquare: |
64 } | 66 return SkPaint::kSquare_Cap; |
65 | 67 default: |
66 void SkSVGPresentationContext::initFrom(const SkSVGPresentationContext& other) { | 68 SkASSERT(false); |
67 if (other.fFill.isValid()) { | 69 return SkPaint::kButt_Cap; |
68 fFill.set(*other.fFill.get()); | |
69 } else { | |
70 fFill.reset(); | |
71 } | |
72 | |
73 if (other.fStroke.isValid()) { | |
74 fStroke.set(*other.fStroke.get()); | |
75 } else { | |
76 fStroke.reset(); | |
77 } | 70 } |
78 } | 71 } |
79 | 72 |
80 SkPaint& SkSVGPresentationContext::ensureFill() { | 73 SkPaint::Join toSkJoin(const SkSVGLineJoin& join) { |
81 if (!fFill.isValid()) { | 74 switch (join.type()) { |
82 fFill.init(); | 75 case SkSVGLineJoin::Type::kMiter: |
83 fFill.get()->setStyle(SkPaint::kFill_Style); | 76 return SkPaint::kMiter_Join; |
84 fFill.get()->setAntiAlias(true); | 77 case SkSVGLineJoin::Type::kRound: |
78 return SkPaint::kRound_Join; | |
79 case SkSVGLineJoin::Type::kBevel: | |
80 return SkPaint::kBevel_Join; | |
81 default: | |
82 SkASSERT(false); | |
83 return SkPaint::kMiter_Join; | |
85 } | 84 } |
86 return *fFill.get(); | |
87 } | 85 } |
88 | 86 |
89 SkPaint& SkSVGPresentationContext::ensureStroke() { | 87 void applySvgPaint(const SkSVGPaint& svgPaint, SkPaint* p) { |
90 if (!fStroke.isValid()) { | 88 switch (svgPaint.type()) { |
91 fStroke.init(); | 89 case SkSVGPaint::Type::kColor: |
92 fStroke.get()->setStyle(SkPaint::kStroke_Style); | 90 p->setColor(SkColorSetA(svgPaint.color(), p->getAlpha())); |
93 fStroke.get()->setAntiAlias(true); | 91 break; |
92 case SkSVGPaint::Type::kCurrentColor: | |
93 SkDebugf("unimplemented 'currentColor' paint type"); | |
94 // Fall through. | |
95 case SkSVGPaint::Type::kNone: | |
96 // Fall through. | |
97 case SkSVGPaint::Type::kInherit: | |
98 break; | |
94 } | 99 } |
95 return *fStroke.get(); | |
96 } | 100 } |
97 | 101 |
98 void SkSVGPresentationContext::setFillColor(SkColor color) { | 102 // Commit the selected attribute to the paint cache. |
99 this->ensureFill().setColor(color); | 103 template <SkSVGAttribute> |
104 void commitToPaint(const SkSVGPresentationAttributes&, | |
105 const SkSVGLengthContext&, | |
106 SkSVGPresentationContext*); | |
107 | |
108 template <> | |
109 void commitToPaint<SkSVGAttribute::kFill>(const SkSVGPresentationAttributes& att rs, | |
110 const SkSVGLengthContext&, | |
111 SkSVGPresentationContext* pctx) { | |
112 applySvgPaint(*attrs.fFill.get(), &pctx->fFillPaint); | |
100 } | 113 } |
101 | 114 |
102 void SkSVGPresentationContext::setStrokeColor(SkColor color) { | 115 template <> |
103 this->ensureStroke().setColor(color); | 116 void commitToPaint<SkSVGAttribute::kStroke>(const SkSVGPresentationAttributes& a ttrs, |
117 const SkSVGLengthContext&, | |
118 SkSVGPresentationContext* pctx) { | |
119 applySvgPaint(*attrs.fStroke.get(), &pctx->fStrokePaint); | |
120 } | |
121 | |
122 template <> | |
123 void commitToPaint<SkSVGAttribute::kFillOpacity>(const SkSVGPresentationAttribut es& attrs, | |
124 const SkSVGLengthContext&, | |
125 SkSVGPresentationContext* pctx) { | |
126 pctx->fFillPaint.setAlpha(static_cast<uint8_t>(*attrs.fFillOpacity.get() * 2 55)); | |
127 } | |
128 | |
129 template <> | |
130 void commitToPaint<SkSVGAttribute::kStrokeLineCap>(const SkSVGPresentationAttrib utes& attrs, | |
131 const SkSVGLengthContext&, | |
132 SkSVGPresentationContext* pct x) { | |
133 const auto& cap = *attrs.fStrokeLineCap.get(); | |
134 if (cap.type() != SkSVGLineCap::Type::kInherit) { | |
135 pctx->fStrokePaint.setStrokeCap(toSkCap(cap)); | |
136 } | |
137 } | |
138 | |
139 template <> | |
140 void commitToPaint<SkSVGAttribute::kStrokeLineJoin>(const SkSVGPresentationAttri butes& attrs, | |
141 const SkSVGLengthContext&, | |
142 SkSVGPresentationContext* pc tx) { | |
143 const auto& join = *attrs.fStrokeLineJoin.get(); | |
144 if (join.type() != SkSVGLineJoin::Type::kInherit) { | |
145 pctx->fStrokePaint.setStrokeJoin(toSkJoin(join)); | |
146 } | |
147 } | |
148 | |
149 template <> | |
150 void commitToPaint<SkSVGAttribute::kStrokeOpacity>(const SkSVGPresentationAttrib utes& attrs, | |
151 const SkSVGLengthContext&, | |
152 SkSVGPresentationContext* pct x) { | |
153 pctx->fStrokePaint.setAlpha(static_cast<uint8_t>(*attrs.fStrokeOpacity.get() * 255)); | |
154 } | |
155 | |
156 template <> | |
157 void commitToPaint<SkSVGAttribute::kStrokeWidth>(const SkSVGPresentationAttribut es& attrs, | |
158 const SkSVGLengthContext& lctx, | |
159 SkSVGPresentationContext* pctx) { | |
160 auto strokeWidth = lctx.resolve(*attrs.fStrokeWidth.get(), | |
161 SkSVGLengthContext::LengthType::kOther); | |
162 pctx->fStrokePaint.setStrokeWidth(strokeWidth); | |
163 } | |
164 | |
165 } // anonymous ns | |
166 | |
167 SkSVGPresentationContext::SkSVGPresentationContext() | |
168 : fInherited(SkSVGPresentationAttributes::MakeInitial()) { | |
169 | |
170 fFillPaint.setStyle(SkPaint::kFill_Style); | |
171 fStrokePaint.setStyle(SkPaint::kStroke_Style); | |
172 | |
173 // TODO: drive AA off presentation attrs also (shape-rendering?) | |
174 fFillPaint.setAntiAlias(true); | |
175 fStrokePaint.setAntiAlias(true); | |
176 | |
177 // Commit initial values to the paint cache. | |
178 SkSVGLengthContext dummy(SkSize::Make(0, 0)); | |
179 commitToPaint<SkSVGAttribute::kFill>(fInherited, dummy, this); | |
180 commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, dummy, this); | |
181 commitToPaint<SkSVGAttribute::kStroke>(fInherited, dummy, this); | |
182 commitToPaint<SkSVGAttribute::kStrokeLineCap>(fInherited, dummy, this); | |
183 commitToPaint<SkSVGAttribute::kStrokeLineJoin>(fInherited, dummy, this); | |
184 commitToPaint<SkSVGAttribute::kStrokeOpacity>(fInherited, dummy, this); | |
185 commitToPaint<SkSVGAttribute::kStrokeWidth>(fInherited, dummy, this); | |
104 } | 186 } |
105 | 187 |
106 SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, | 188 SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, |
107 const SkSVGLengthContext& lctx, | 189 const SkSVGLengthContext& lctx, |
108 const SkSVGPresentationContext& pctx) | 190 const SkSVGPresentationContext& pctx) |
109 : fLengthContext(lctx) | 191 : fLengthContext(lctx) |
110 , fPresentationContext(pctx) | 192 , fPresentationContext(pctx) |
111 , fCanvas(canvas) | 193 , fCanvas(canvas) |
112 , fCanvasSaveCount(canvas->getSaveCount()) {} | 194 , fCanvasSaveCount(canvas->getSaveCount()) {} |
113 | 195 |
114 SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) | 196 SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) |
115 : SkSVGRenderContext(other.canvas(), | 197 : SkSVGRenderContext(other.fCanvas, |
116 other.lengthContext(), | 198 *other.fLengthContext, |
117 other.presentationContext()) {} | 199 *other.fPresentationContext) {} |
118 | 200 |
119 SkSVGRenderContext::~SkSVGRenderContext() { | 201 SkSVGRenderContext::~SkSVGRenderContext() { |
120 fCanvas->restoreToCount(fCanvasSaveCount); | 202 fCanvas->restoreToCount(fCanvasSaveCount); |
121 } | 203 } |
204 | |
205 void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr ibutes& attrs) { | |
206 | |
207 #define ApplyLazyInheritedAttribute(ATTR) \ | |
208 do { \ | |
209 /* All attributes should be defined on the inherited context. */ \ | |
210 SkASSERT(fPresentationContext->fInherited.f ## ATTR.isValid()); \ | |
211 const auto* value = attrs.f ## ATTR.getMaybeNull(); \ | |
212 if (value && *value != *fPresentationContext->fInherited.f ## ATTR.get() ) { \ | |
213 /* Update the local attribute value */ \ | |
214 fPresentationContext.writable()->fInherited.f ## ATTR.set(*value); \ | |
215 /* Update the cached paints */ \ | |
216 commitToPaint<SkSVGAttribute::k ## ATTR>(attrs, *fLengthContext, \ | |
217 fPresentationContext.writab le()); \ | |
218 } \ | |
219 } while (false) | |
220 | |
221 ApplyLazyInheritedAttribute(Fill); | |
222 ApplyLazyInheritedAttribute(FillOpacity); | |
223 ApplyLazyInheritedAttribute(Stroke); | |
224 ApplyLazyInheritedAttribute(StrokeLineCap); | |
225 ApplyLazyInheritedAttribute(StrokeLineJoin); | |
226 ApplyLazyInheritedAttribute(StrokeOpacity); | |
227 ApplyLazyInheritedAttribute(StrokeWidth); | |
228 | |
229 #undef ApplyLazyInheritedAttribute | |
230 } | |
231 | |
232 const SkPaint* SkSVGRenderContext::fillPaint() const { | |
233 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fFill.ge t()->type(); | |
234 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fFillPa int : nullptr; | |
235 } | |
236 | |
237 const SkPaint* SkSVGRenderContext::strokePaint() const { | |
238 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fStroke. get()->type(); | |
239 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fStroke Paint : nullptr; | |
240 } | |
OLD | NEW |