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()) { |
32 case SkSVGLength::Unit::kNumber: | 33 case SkSVGLength::Unit::kNumber: |
| 34 // Fall through. |
| 35 case SkSVGLength::Unit::kPX: |
33 return l.value(); | 36 return l.value(); |
34 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; | |
38 default: | 39 default: |
39 SkDebugf("unsupported unit type: <%d>\n", l.unit()); | 40 SkDebugf("unsupported unit type: <%d>\n", l.unit()); |
40 break; | 41 return 0; |
41 } | 42 } |
42 | |
43 return 0; | |
44 } | 43 } |
45 | 44 |
46 SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength&
y, | 45 SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength&
y, |
47 const SkSVGLength& w, const SkSVGLength&
h) const { | 46 const SkSVGLength& w, const SkSVGLength&
h) const { |
48 return SkRect::MakeXYWH( | 47 return SkRect::MakeXYWH( |
49 this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal), | 48 this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal), |
50 this->resolve(y, SkSVGLengthContext::LengthType::kVertical), | 49 this->resolve(y, SkSVGLengthContext::LengthType::kVertical), |
51 this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal), | 50 this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal), |
52 this->resolve(h, SkSVGLengthContext::LengthType::kVertical)); | 51 this->resolve(h, SkSVGLengthContext::LengthType::kVertical)); |
53 } | 52 } |
54 | 53 |
55 SkSVGPresentationContext::SkSVGPresentationContext() {} | 54 namespace { |
56 | 55 |
57 SkSVGPresentationContext::SkSVGPresentationContext(const SkSVGPresentationContex
t& o) { | 56 SkPaint::Cap toSkCap(const SkSVGLineCap& cap) { |
58 this->initFrom(o); | 57 switch (cap.type()) { |
59 } | 58 case SkSVGLineCap::Type::kButt: |
60 | 59 return SkPaint::kButt_Cap; |
61 SkSVGPresentationContext& SkSVGPresentationContext::operator=(const SkSVGPresent
ationContext& o) { | 60 case SkSVGLineCap::Type::kRound: |
62 this->initFrom(o); | 61 return SkPaint::kRound_Cap; |
63 return *this; | 62 case SkSVGLineCap::Type::kSquare: |
64 } | 63 return SkPaint::kSquare_Cap; |
65 | 64 default: |
66 void SkSVGPresentationContext::initFrom(const SkSVGPresentationContext& other) { | 65 SkASSERT(false); |
67 if (other.fFill.isValid()) { | 66 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 } | 67 } |
78 } | 68 } |
79 | 69 |
80 SkPaint& SkSVGPresentationContext::ensureFill() { | 70 SkPaint::Join toSkJoin(const SkSVGLineJoin& join) { |
81 if (!fFill.isValid()) { | 71 switch (join.type()) { |
82 fFill.init(); | 72 case SkSVGLineJoin::Type::kMiter: |
83 fFill.get()->setStyle(SkPaint::kFill_Style); | 73 return SkPaint::kMiter_Join; |
84 fFill.get()->setAntiAlias(true); | 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; |
85 } | 81 } |
86 return *fFill.get(); | |
87 } | 82 } |
88 | 83 |
89 SkPaint& SkSVGPresentationContext::ensureStroke() { | 84 void applySvgPaint(const SkSVGPaint& svgPaint, SkPaint* p) { |
90 if (!fStroke.isValid()) { | 85 switch (svgPaint.type()) { |
91 fStroke.init(); | 86 case SkSVGPaint::Type::kColor: |
92 fStroke.get()->setStyle(SkPaint::kStroke_Style); | 87 p->setColor(SkColorSetA(svgPaint.color(), p->getAlpha())); |
93 fStroke.get()->setAntiAlias(true); | 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; |
94 } | 96 } |
95 return *fStroke.get(); | |
96 } | 97 } |
97 | 98 |
98 void SkSVGPresentationContext::setFillColor(SkColor color) { | 99 // Commit the selected attribute to the paint cache. |
99 this->ensureFill().setColor(color); | 100 template <SkSVGAttribute> |
| 101 void commitToPaint(const SkSVGPresentationAttributes&, |
| 102 const SkSVGLengthContext&, |
| 103 SkSVGPresentationContext*); |
| 104 |
| 105 template <> |
| 106 void commitToPaint<SkSVGAttribute::kFill>(const SkSVGPresentationAttributes& att
rs, |
| 107 const SkSVGLengthContext&, |
| 108 SkSVGPresentationContext* pctx) { |
| 109 applySvgPaint(*attrs.fFill.get(), &pctx->fFillPaint); |
100 } | 110 } |
101 | 111 |
102 void SkSVGPresentationContext::setStrokeColor(SkColor color) { | 112 template <> |
103 this->ensureStroke().setColor(color); | 113 void commitToPaint<SkSVGAttribute::kStroke>(const SkSVGPresentationAttributes& a
ttrs, |
| 114 const SkSVGLengthContext&, |
| 115 SkSVGPresentationContext* pctx) { |
| 116 applySvgPaint(*attrs.fStroke.get(), &pctx->fStrokePaint); |
| 117 } |
| 118 |
| 119 template <> |
| 120 void commitToPaint<SkSVGAttribute::kFillOpacity>(const SkSVGPresentationAttribut
es& attrs, |
| 121 const SkSVGLengthContext&, |
| 122 SkSVGPresentationContext* pctx)
{ |
| 123 pctx->fFillPaint.setAlpha(static_cast<uint8_t>(*attrs.fFillOpacity.get() * 2
55)); |
| 124 } |
| 125 |
| 126 template <> |
| 127 void commitToPaint<SkSVGAttribute::kStrokeLineCap>(const SkSVGPresentationAttrib
utes& attrs, |
| 128 const SkSVGLengthContext&, |
| 129 SkSVGPresentationContext* pct
x) { |
| 130 const auto& cap = *attrs.fStrokeLineCap.get(); |
| 131 if (cap.type() != SkSVGLineCap::Type::kInherit) { |
| 132 pctx->fStrokePaint.setStrokeCap(toSkCap(cap)); |
| 133 } |
| 134 } |
| 135 |
| 136 template <> |
| 137 void commitToPaint<SkSVGAttribute::kStrokeLineJoin>(const SkSVGPresentationAttri
butes& attrs, |
| 138 const SkSVGLengthContext&, |
| 139 SkSVGPresentationContext* pc
tx) { |
| 140 const auto& join = *attrs.fStrokeLineJoin.get(); |
| 141 if (join.type() != SkSVGLineJoin::Type::kInherit) { |
| 142 pctx->fStrokePaint.setStrokeJoin(toSkJoin(join)); |
| 143 } |
| 144 } |
| 145 |
| 146 template <> |
| 147 void commitToPaint<SkSVGAttribute::kStrokeOpacity>(const SkSVGPresentationAttrib
utes& attrs, |
| 148 const SkSVGLengthContext&, |
| 149 SkSVGPresentationContext* pct
x) { |
| 150 pctx->fStrokePaint.setAlpha(static_cast<uint8_t>(*attrs.fStrokeOpacity.get()
* 255)); |
| 151 } |
| 152 |
| 153 template <> |
| 154 void commitToPaint<SkSVGAttribute::kStrokeWidth>(const SkSVGPresentationAttribut
es& 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 |
| 164 SkSVGPresentationContext::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); |
104 } | 183 } |
105 | 184 |
106 SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, | 185 SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, |
107 const SkSVGLengthContext& lctx, | 186 const SkSVGLengthContext& lctx, |
108 const SkSVGPresentationContext& pctx) | 187 const SkSVGPresentationContext& pctx) |
109 : fLengthContext(lctx) | 188 : fLengthContext(lctx) |
110 , fPresentationContext(pctx) | 189 , fPresentationContext(pctx) |
111 , fCanvas(canvas) | 190 , fCanvas(canvas) |
112 , fCanvasSaveCount(canvas->getSaveCount()) {} | 191 , fCanvasSaveCount(canvas->getSaveCount()) {} |
113 | 192 |
114 SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) | 193 SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) |
115 : SkSVGRenderContext(other.canvas(), | 194 : SkSVGRenderContext(other.fCanvas, |
116 other.lengthContext(), | 195 *other.fLengthContext, |
117 other.presentationContext()) {} | 196 *other.fPresentationContext) {} |
118 | 197 |
119 SkSVGRenderContext::~SkSVGRenderContext() { | 198 SkSVGRenderContext::~SkSVGRenderContext() { |
120 fCanvas->restoreToCount(fCanvasSaveCount); | 199 fCanvas->restoreToCount(fCanvasSaveCount); |
121 } | 200 } |
| 201 |
| 202 void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
ibutes& 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.writab
le()); \ |
| 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 |
| 229 const SkPaint* SkSVGRenderContext::fillPaint() const { |
| 230 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fFill.ge
t()->type(); |
| 231 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fFillPa
int : nullptr; |
| 232 } |
| 233 |
| 234 const SkPaint* SkSVGRenderContext::strokePaint() const { |
| 235 const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fStroke.
get()->type(); |
| 236 return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fStroke
Paint : nullptr; |
| 237 } |
OLD | NEW |