Chromium Code Reviews| 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 |