Index: experimental/svg/model/SkSVGRenderContext.cpp |
diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp |
index e902d4ecf3d389018535e941299ef989c1e7bd42..ee92c47d542ea39744f4487e4007f8a5ed916a7c 100644 |
--- a/experimental/svg/model/SkSVGRenderContext.cpp |
+++ b/experimental/svg/model/SkSVGRenderContext.cpp |
@@ -6,6 +6,7 @@ |
*/ |
#include "SkCanvas.h" |
+#include "SkSVGAttribute.h" |
#include "SkSVGRenderContext.h" |
#include "SkSVGTypes.h" |
@@ -30,17 +31,15 @@ SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::Length |
SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const { |
switch (l.unit()) { |
case SkSVGLength::Unit::kNumber: |
+ // Fall through. |
+ case SkSVGLength::Unit::kPX: |
return l.value(); |
- break; |
case SkSVGLength::Unit::kPercentage: |
return l.value() * length_size_for_type(fViewport, t) / 100; |
- break; |
default: |
SkDebugf("unsupported unit type: <%d>\n", l.unit()); |
- break; |
+ return 0; |
} |
- |
- return 0; |
} |
SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y, |
@@ -52,55 +51,135 @@ SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& |
this->resolve(h, SkSVGLengthContext::LengthType::kVertical)); |
} |
-SkSVGPresentationContext::SkSVGPresentationContext() {} |
+namespace { |
-SkSVGPresentationContext::SkSVGPresentationContext(const SkSVGPresentationContext& o) { |
- this->initFrom(o); |
+SkPaint::Cap toSkCap(const SkSVGLineCap& cap) { |
+ switch (cap.type()) { |
+ case SkSVGLineCap::Type::kButt: |
+ return SkPaint::kButt_Cap; |
+ case SkSVGLineCap::Type::kRound: |
+ return SkPaint::kRound_Cap; |
+ case SkSVGLineCap::Type::kSquare: |
+ return SkPaint::kSquare_Cap; |
+ default: |
+ SkASSERT(false); |
+ return SkPaint::kButt_Cap; |
+ } |
} |
-SkSVGPresentationContext& SkSVGPresentationContext::operator=(const SkSVGPresentationContext& o) { |
- this->initFrom(o); |
- return *this; |
+SkPaint::Join toSkJoin(const SkSVGLineJoin& join) { |
+ switch (join.type()) { |
+ case SkSVGLineJoin::Type::kMiter: |
+ return SkPaint::kMiter_Join; |
+ case SkSVGLineJoin::Type::kRound: |
+ return SkPaint::kRound_Join; |
+ case SkSVGLineJoin::Type::kBevel: |
+ return SkPaint::kBevel_Join; |
+ default: |
+ SkASSERT(false); |
+ return SkPaint::kMiter_Join; |
+ } |
} |
-void SkSVGPresentationContext::initFrom(const SkSVGPresentationContext& other) { |
- if (other.fFill.isValid()) { |
- fFill.set(*other.fFill.get()); |
- } else { |
- fFill.reset(); |
+void applySvgPaint(const SkSVGPaint& svgPaint, SkPaint* p) { |
+ switch (svgPaint.type()) { |
+ case SkSVGPaint::Type::kColor: |
+ p->setColor(SkColorSetA(svgPaint.color(), p->getAlpha())); |
+ break; |
+ case SkSVGPaint::Type::kCurrentColor: |
+ SkDebugf("unimplemented 'currentColor' paint type"); |
+ // Fall through. |
+ case SkSVGPaint::Type::kNone: |
+ // Fall through. |
+ case SkSVGPaint::Type::kInherit: |
+ break; |
} |
+} |
- if (other.fStroke.isValid()) { |
- fStroke.set(*other.fStroke.get()); |
- } else { |
- fStroke.reset(); |
- } |
+// Commit the selected attribute to the paint cache. |
+template <SkSVGAttribute> |
+void commitToPaint(const SkSVGPresentationAttributes&, |
+ const SkSVGLengthContext&, |
+ SkSVGPresentationContext*); |
+ |
+template <> |
+void commitToPaint<SkSVGAttribute::kFill>(const SkSVGPresentationAttributes& attrs, |
+ const SkSVGLengthContext&, |
+ SkSVGPresentationContext* pctx) { |
+ applySvgPaint(*attrs.fFill.get(), &pctx->fFillPaint); |
} |
-SkPaint& SkSVGPresentationContext::ensureFill() { |
- if (!fFill.isValid()) { |
- fFill.init(); |
- fFill.get()->setStyle(SkPaint::kFill_Style); |
- fFill.get()->setAntiAlias(true); |
+template <> |
+void commitToPaint<SkSVGAttribute::kStroke>(const SkSVGPresentationAttributes& attrs, |
+ const SkSVGLengthContext&, |
+ SkSVGPresentationContext* pctx) { |
+ applySvgPaint(*attrs.fStroke.get(), &pctx->fStrokePaint); |
+} |
+ |
+template <> |
+void commitToPaint<SkSVGAttribute::kFillOpacity>(const SkSVGPresentationAttributes& attrs, |
+ const SkSVGLengthContext&, |
+ SkSVGPresentationContext* pctx) { |
+ pctx->fFillPaint.setAlpha(static_cast<uint8_t>(*attrs.fFillOpacity.get() * 255)); |
+} |
+ |
+template <> |
+void commitToPaint<SkSVGAttribute::kStrokeLineCap>(const SkSVGPresentationAttributes& attrs, |
+ const SkSVGLengthContext&, |
+ SkSVGPresentationContext* pctx) { |
+ const auto& cap = *attrs.fStrokeLineCap.get(); |
+ if (cap.type() != SkSVGLineCap::Type::kInherit) { |
+ pctx->fStrokePaint.setStrokeCap(toSkCap(cap)); |
} |
- return *fFill.get(); |
} |
-SkPaint& SkSVGPresentationContext::ensureStroke() { |
- if (!fStroke.isValid()) { |
- fStroke.init(); |
- fStroke.get()->setStyle(SkPaint::kStroke_Style); |
- fStroke.get()->setAntiAlias(true); |
+template <> |
+void commitToPaint<SkSVGAttribute::kStrokeLineJoin>(const SkSVGPresentationAttributes& attrs, |
+ const SkSVGLengthContext&, |
+ SkSVGPresentationContext* pctx) { |
+ const auto& join = *attrs.fStrokeLineJoin.get(); |
+ if (join.type() != SkSVGLineJoin::Type::kInherit) { |
+ pctx->fStrokePaint.setStrokeJoin(toSkJoin(join)); |
} |
- return *fStroke.get(); |
} |
-void SkSVGPresentationContext::setFillColor(SkColor color) { |
- this->ensureFill().setColor(color); |
+template <> |
+void commitToPaint<SkSVGAttribute::kStrokeOpacity>(const SkSVGPresentationAttributes& attrs, |
+ const SkSVGLengthContext&, |
+ SkSVGPresentationContext* pctx) { |
+ pctx->fStrokePaint.setAlpha(static_cast<uint8_t>(*attrs.fStrokeOpacity.get() * 255)); |
} |
-void SkSVGPresentationContext::setStrokeColor(SkColor color) { |
- this->ensureStroke().setColor(color); |
+template <> |
+void commitToPaint<SkSVGAttribute::kStrokeWidth>(const SkSVGPresentationAttributes& attrs, |
+ const SkSVGLengthContext& lctx, |
+ SkSVGPresentationContext* pctx) { |
+ auto strokeWidth = lctx.resolve(*attrs.fStrokeWidth.get(), |
+ SkSVGLengthContext::LengthType::kOther); |
+ pctx->fStrokePaint.setStrokeWidth(strokeWidth); |
+} |
+ |
+} // anonymous ns |
+ |
+SkSVGPresentationContext::SkSVGPresentationContext() |
+ : fInherited(SkSVGPresentationAttributes::MakeInitial()) { |
+ |
+ fFillPaint.setStyle(SkPaint::kFill_Style); |
+ fStrokePaint.setStyle(SkPaint::kStroke_Style); |
+ |
+ // TODO: drive AA off presentation attrs also (shape-rendering?) |
+ fFillPaint.setAntiAlias(true); |
+ fStrokePaint.setAntiAlias(true); |
+ |
+ // Commit initial values to the paint cache. |
+ SkSVGLengthContext dummy(SkSize::Make(0, 0)); |
+ commitToPaint<SkSVGAttribute::kFill>(fInherited, dummy, this); |
+ commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, dummy, this); |
+ commitToPaint<SkSVGAttribute::kStroke>(fInherited, dummy, this); |
+ commitToPaint<SkSVGAttribute::kStrokeLineCap>(fInherited, dummy, this); |
+ commitToPaint<SkSVGAttribute::kStrokeLineJoin>(fInherited, dummy, this); |
+ commitToPaint<SkSVGAttribute::kStrokeOpacity>(fInherited, dummy, this); |
+ commitToPaint<SkSVGAttribute::kStrokeWidth>(fInherited, dummy, this); |
} |
SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, |
@@ -112,10 +191,47 @@ SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, |
, fCanvasSaveCount(canvas->getSaveCount()) {} |
SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) |
- : SkSVGRenderContext(other.canvas(), |
- other.lengthContext(), |
- other.presentationContext()) {} |
+ : SkSVGRenderContext(other.fCanvas, |
+ *other.fLengthContext, |
+ *other.fPresentationContext) {} |
SkSVGRenderContext::~SkSVGRenderContext() { |
fCanvas->restoreToCount(fCanvasSaveCount); |
} |
+ |
+void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttributes& attrs) { |
+ |
+#define ApplyLazyInheritedAttribute(ATTR) \ |
+ do { \ |
+ /* All attributes should be defined on the inherited context. */ \ |
+ SkASSERT(fPresentationContext->fInherited.f ## ATTR.isValid()); \ |
+ const auto* value = attrs.f ## ATTR.getMaybeNull(); \ |
+ if (value && *value != *fPresentationContext->fInherited.f ## ATTR.get()) { \ |
+ /* Update the local attribute value */ \ |
+ fPresentationContext.writable()->fInherited.f ## ATTR.set(*value); \ |
+ /* Update the cached paints */ \ |
+ commitToPaint<SkSVGAttribute::k ## ATTR>(attrs, *fLengthContext, \ |
+ fPresentationContext.writable()); \ |
+ } \ |
+ } while (false) |
+ |
+ ApplyLazyInheritedAttribute(Fill); |
+ ApplyLazyInheritedAttribute(FillOpacity); |
+ ApplyLazyInheritedAttribute(Stroke); |
+ ApplyLazyInheritedAttribute(StrokeLineCap); |
+ ApplyLazyInheritedAttribute(StrokeLineJoin); |
+ ApplyLazyInheritedAttribute(StrokeOpacity); |
+ ApplyLazyInheritedAttribute(StrokeWidth); |
+ |
+#undef ApplyLazyInheritedAttribute |
+} |
+ |
+const SkPaint* SkSVGRenderContext::fillPaint() const { |
+ const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fFill.get()->type(); |
+ return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fFillPaint : nullptr; |
+} |
+ |
+const SkPaint* SkSVGRenderContext::strokePaint() const { |
+ const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fStroke.get()->type(); |
+ return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fStrokePaint : nullptr; |
+} |