: fFillIsSet(false)
, fStrokeIsSet(false) { }
-void SkSVGPresentationAttributes::setFill(const SkSVGColor& c) {
+void SkSVGPresentationAttributes::setFill(const SkSVGColorType& c) {
fFill = c;
fFillIsSet = true;
}
-void SkSVGPresentationAttributes::setStroke(const SkSVGColor& c) {
+void SkSVGPresentationAttributes::setStroke(const SkSVGColorType& c) {
fStroke = c;
fStrokeIsSet = true;
}
-void SkSVGPresentationAttributes::applyTo(SkTCopyOnFirstWrite<SkSVGRenderContext>& ctx) const {
+void SkSVGPresentationAttributes::applyTo(SkSVGRenderContext* ctx) const {
if (fFillIsSet) {
- ctx.writable()->setFillColor(fFill);
+ ctx->writablePresentationContext()->setFillColor(fFill);
}
if (fStrokeIsSet) {
- ctx.writable()->setStrokeColor(fStroke);
+ ctx->writablePresentationContext()->setStrokeColor(fStroke);
}
}
#include "SkSVGTypes.h"
#include "SkTLazy.h"
+class SkSVGRenderContext;
+
enum class SkSVGAttribute {
kD,
kFill,
kHeight,
kStroke,
kTransform,
+ kViewBox,
kWidth,
kX,
kY,
kUnknown,
};
-class SkSVGRenderContext;
-
class SkSVGPresentationAttributes {
public:
SkSVGPresentationAttributes();
- void setFill(const SkSVGColor&);
- void setStroke(const SkSVGColor&);
+ void setFill(const SkSVGColorType&);
+ void setStroke(const SkSVGColorType&);
- void applyTo(SkTCopyOnFirstWrite<SkSVGRenderContext>&) const;
+ void applyTo(SkSVGRenderContext*) const;
private:
// Color only for now.
- SkSVGColor fFill;
- SkSVGColor fStroke;
+ SkSVGColorType fFill;
+ SkSVGColorType fStroke;
unsigned fFillIsSet : 1;
unsigned fStrokeIsSet : 1;
}
// https://www.w3.org/TR/SVG/types.html#DataTypeColor
-bool SkSVGAttributeParser::parseColor(SkSVGColor* color) {
+bool SkSVGAttributeParser::parseColor(SkSVGColorType* color) {
SkColor c;
// TODO: rgb(...)
if (this->parseHexColorToken(&c) || this->parseNamedColorToken(&c)) {
- *color = SkSVGColor(c);
+ *color = SkSVGColorType(c);
return true;
}
}
// https://www.w3.org/TR/SVG/types.html#DataTypeNumber
-bool SkSVGAttributeParser::parseNumber(SkSVGNumber* number) {
+bool SkSVGAttributeParser::parseNumber(SkSVGNumberType* number) {
// consume WS
this->parseWSToken();
SkScalar s;
if (this->parseScalarToken(&s)) {
- *number = SkSVGNumber(s);
+ *number = SkSVGNumberType(s);
// consume trailing separators
this->parseSepToken();
return true;
return false;
}
+
+// https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
+bool SkSVGAttributeParser::parseViewBox(SkSVGViewBoxType* vb) {
+ SkScalar x, y, w, h;
+ this->parseWSToken();
+
+ bool parsedValue = false;
+ if (this->parseScalarToken(&x) && this->parseSepToken() &&
+ this->parseScalarToken(&y) && this->parseSepToken() &&
+ this->parseScalarToken(&w) && this->parseSepToken() &&
+ this->parseScalarToken(&h)) {
+
+ *vb = SkSVGViewBoxType(SkRect::MakeXYWH(x, y, w, h));
+ parsedValue = true;
+ // consume trailing whitespace
+ this->parseWSToken();
+ }
+ return parsedValue && this->parseEOSToken();
+}
public:
SkSVGAttributeParser(const char[]);
- bool parseColor(SkSVGColor*);
- bool parseNumber(SkSVGNumber*);
+ bool parseColor(SkSVGColorType*);
+ bool parseNumber(SkSVGNumberType*);
bool parseLength(SkSVGLength*);
+ bool parseViewBox(SkSVGViewBoxType*);
private:
// Stack-only
fChildren.push_back(std::move(node));
}
-void SkSVGContainer::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const {
+void SkSVGContainer::onRender(const SkSVGRenderContext& ctx) const {
for (int i = 0; i < fChildren.count(); ++i) {
- fChildren[i]->render(canvas, ctx);
+ fChildren[i]->render(ctx);
}
}
protected:
SkSVGContainer(SkSVGTag);
- void onRender(SkCanvas*, const SkSVGRenderContext&) const override;
+ void onRender(const SkSVGRenderContext&) const override;
private:
SkSTArray<1, sk_sp<SkSVGNode>, true> fChildren;
bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
- SkSVGColor color;
+ SkSVGColorType color;
SkSVGAttributeParser parser(stringValue);
if (!parser.parseColor(&color)) {
return false;
return true;
}
+bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGViewBoxType viewBox;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseViewBox(&viewBox)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
+ return true;
+}
+
// Breaks a "foo: bar; baz: ..." string into key:value pairs.
class StyleIterator {
public:
{ "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
{ "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
{ "transform", { SkSVGAttribute::kTransform, SetTransformAttribute }},
+ { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
{ "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
{ "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
{ "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
void SkSVGDOM::render(SkCanvas* canvas) const {
if (fRoot) {
- SkSVGRenderContext ctx(fContainerSize);
- fRoot->render(canvas, ctx);
+ SkSVGRenderContext ctx(canvas,
+ SkSVGLengthContext(fContainerSize),
+ SkSVGPresentationContext());
+ fRoot->render(ctx);
}
}
SkSVGNode::~SkSVGNode() { }
-void SkSVGNode::render(SkCanvas* canvas, const SkSVGRenderContext& ctx) const {
- SkTCopyOnFirstWrite<SkSVGRenderContext> localContext(ctx);
- fPresentationAttributes.applyTo(localContext);
-
- SkAutoCanvasRestore acr(canvas, false);
- const SkMatrix& m = this->onLocalMatrix();
- if (!m.isIdentity()) {
- canvas->save();
- canvas->concat(m);
+void SkSVGNode::render(const SkSVGRenderContext& ctx) const {
+ SkSVGRenderContext localContext(ctx);
+
+ if (this->onPrepareToRender(&localContext)) {
+ this->onRender(localContext);
}
+}
- this->onRender(canvas, *localContext);
+bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
+ fPresentationAttributes.applyTo(ctx);
+ return true;
}
void SkSVGNode::setAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
break;
}
}
-
-const SkMatrix& SkSVGNode::onLocalMatrix() const {
- return SkMatrix::I();
-}
virtual void appendChild(sk_sp<SkSVGNode>) = 0;
- void render(SkCanvas*, const SkSVGRenderContext&) const;
+ void render(const SkSVGRenderContext&) const;
void setAttribute(SkSVGAttribute, const SkSVGValue&);
protected:
SkSVGNode(SkSVGTag);
- virtual void onRender(SkCanvas*, const SkSVGRenderContext&) const = 0;
+ // Called before onRender(), to apply local attributes to the context. Unlike onRender(),
+ // onPrepareToRender() bubbles up the inheritance chain: overriders should always call
+ // INHERITED::onPrepareToRender(), unless they intend to short-circuit rendering
+ // (return false).
+ // Implementations are expected to return true if rendering is to continue, or false if
+ // the node/subtree rendering is disabled.
+ virtual bool onPrepareToRender(SkSVGRenderContext*) const;
- virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
+ virtual void onRender(const SkSVGRenderContext&) const = 0;
- virtual const SkMatrix& onLocalMatrix() const;
+ virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
private:
SkSVGTag fTag;
void SkSVGRect::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
const SkPaint& paint) const {
- const SkRect r = SkRect::MakeXYWH(
- lctx.resolve(fX, SkSVGLengthContext::LengthType::kHorizontal),
- lctx.resolve(fY, SkSVGLengthContext::LengthType::kVertical),
- lctx.resolve(fWidth, SkSVGLengthContext::LengthType::kHorizontal),
- lctx.resolve(fHeight, SkSVGLengthContext::LengthType::kVertical));
-
- canvas->drawRect(r, paint);
+ canvas->drawRect(lctx.resolveRect(fX, fY, fWidth, fHeight), paint);
}
* found in the LICENSE file.
*/
+#include "SkCanvas.h"
#include "SkSVGRenderContext.h"
#include "SkSVGTypes.h"
return 0;
}
-SkSVGRenderContext::SkSVGRenderContext(const SkSize& initialViewport)
- : fLengthContext(initialViewport) {}
+SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y,
+ const SkSVGLength& w, const SkSVGLength& h) const {
+ return SkRect::MakeXYWH(
+ this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal),
+ this->resolve(y, SkSVGLengthContext::LengthType::kVertical),
+ this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal),
+ this->resolve(h, SkSVGLengthContext::LengthType::kVertical));
+}
+
+SkSVGPresentationContext::SkSVGPresentationContext() {}
+
+SkSVGPresentationContext::SkSVGPresentationContext(const SkSVGPresentationContext& o) {
+ this->initFrom(o);
+}
+
+SkSVGPresentationContext& SkSVGPresentationContext::operator=(const SkSVGPresentationContext& o) {
+ this->initFrom(o);
+ return *this;
+}
-SkSVGRenderContext& SkSVGRenderContext::operator=(const SkSVGRenderContext& other) {
+void SkSVGPresentationContext::initFrom(const SkSVGPresentationContext& other) {
if (other.fFill.isValid()) {
fFill.set(*other.fFill.get());
} else {
} else {
fStroke.reset();
}
-
- return *this;
}
-SkPaint& SkSVGRenderContext::ensureFill() {
+SkPaint& SkSVGPresentationContext::ensureFill() {
if (!fFill.isValid()) {
fFill.init();
fFill.get()->setStyle(SkPaint::kFill_Style);
return *fFill.get();
}
-SkPaint& SkSVGRenderContext::ensureStroke() {
+SkPaint& SkSVGPresentationContext::ensureStroke() {
if (!fStroke.isValid()) {
fStroke.init();
fStroke.get()->setStyle(SkPaint::kStroke_Style);
return *fStroke.get();
}
-void SkSVGRenderContext::setFillColor(SkColor color) {
+void SkSVGPresentationContext::setFillColor(SkColor color) {
this->ensureFill().setColor(color);
}
-void SkSVGRenderContext::setStrokeColor(SkColor color) {
+void SkSVGPresentationContext::setStrokeColor(SkColor color) {
this->ensureStroke().setColor(color);
}
+
+SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
+ const SkSVGLengthContext& lctx,
+ const SkSVGPresentationContext& pctx)
+ : fLengthContext(lctx)
+ , fPresentationContext(pctx)
+ , fCanvas(canvas)
+ , fCanvasSaveCount(canvas->getSaveCount()) {}
+
+SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
+ : SkSVGRenderContext(other.canvas(),
+ other.lengthContext(),
+ other.presentationContext()) {}
+
+SkSVGRenderContext::~SkSVGRenderContext() {
+ fCanvas->restoreToCount(fCanvasSaveCount);
+}
#ifndef SkSVGRenderContext_DEFINED
#define SkSVGRenderContext_DEFINED
-#include "SkSize.h"
#include "SkPaint.h"
+#include "SkRect.h"
+#include "SkSize.h"
#include "SkTLazy.h"
+#include "SkTypes.h"
-class SkPaint;
+class SkCanvas;
class SkSVGLength;
class SkSVGLengthContext {
kOther,
};
+ const SkSize& viewPort() const { return fViewport; }
void setViewPort(const SkSize& viewport) { fViewport = viewport; }
SkScalar resolve(const SkSVGLength&, LengthType) const;
+ SkRect resolveRect(const SkSVGLength& x, const SkSVGLength& y,
+ const SkSVGLength& w, const SkSVGLength& h) const;
private:
SkSize fViewport;
};
-class SkSVGRenderContext {
+class SkSVGPresentationContext {
public:
- explicit SkSVGRenderContext(const SkSize& initialViewport);
- SkSVGRenderContext(const SkSVGRenderContext&) = default;
- SkSVGRenderContext& operator=(const SkSVGRenderContext&);
-
- const SkSVGLengthContext& lengthContext() const { return fLengthContext; }
+ SkSVGPresentationContext();
+ SkSVGPresentationContext(const SkSVGPresentationContext&);
+ SkSVGPresentationContext& operator=(const SkSVGPresentationContext&);
const SkPaint* fillPaint() const { return fFill.getMaybeNull(); }
const SkPaint* strokePaint() const { return fStroke.getMaybeNull(); }
void setStrokeColor(SkColor);
private:
+ void initFrom(const SkSVGPresentationContext&);
+
SkPaint& ensureFill();
SkPaint& ensureStroke();
- SkSVGLengthContext fLengthContext;
- SkTLazy<SkPaint> fFill;
- SkTLazy<SkPaint> fStroke;
+ // TODO: convert to regular SkPaints and track explicit attribute values instead.
+ SkTLazy<SkPaint> fFill;
+ SkTLazy<SkPaint> fStroke;
+};
+
+class SkSVGRenderContext {
+public:
+ SkSVGRenderContext(SkCanvas*, const SkSVGLengthContext&, const SkSVGPresentationContext&);
+ SkSVGRenderContext(const SkSVGRenderContext&);
+ ~SkSVGRenderContext();
+
+ const SkSVGLengthContext& lengthContext() const { return *fLengthContext; }
+ SkSVGLengthContext* writableLengthContext() { return fLengthContext.writable(); }
+
+ const SkSVGPresentationContext& presentationContext() const { return *fPresentationContext; }
+ SkSVGPresentationContext* writablePresentationContext() {
+ return fPresentationContext.writable();
+ }
+
+ SkCanvas* canvas() const { return fCanvas; }
+
+private:
+ // Stack-only
+ void* operator new(size_t) = delete;
+ void* operator new(size_t, void*) = delete;
+ SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete;
+
+ SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
+ SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext;
+ SkCanvas* fCanvas;
+ // The save count on 'fCanvas' at construction time.
+ // A restoreToCount() will be issued on destruction.
+ int fCanvasSaveCount;
};
#endif // SkSVGRenderContext_DEFINED
* found in the LICENSE file.
*/
+#include "SkCanvas.h"
+#include "SkSVGRenderContext.h"
#include "SkSVGSVG.h"
#include "SkSVGValue.h"
SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { }
+bool SkSVGSVG::onPrepareToRender(SkSVGRenderContext* ctx) const {
+ auto viewPortRect = ctx->lengthContext().resolveRect(fX, fY, fWidth, fHeight);
+ auto contentMatrix = SkMatrix::MakeTrans(viewPortRect.x(), viewPortRect.y());
+ auto viewPort = SkSize::Make(viewPortRect.width(), viewPortRect.height());
+
+ if (fViewBox.isValid()) {
+ const SkRect& viewBox = *fViewBox.get();
+
+ // An empty viewbox disables rendering.
+ if (viewBox.isEmpty()) {
+ return false;
+ }
+
+ // A viewBox overrides the intrinsic viewport.
+ viewPort = SkSize::Make(viewBox.width(), viewBox.height());
+
+ contentMatrix.preConcat(
+ SkMatrix::MakeRectToRect(viewBox, viewPortRect, SkMatrix::kFill_ScaleToFit));
+ }
+
+ if (!contentMatrix.isIdentity()) {
+ ctx->canvas()->save();
+ ctx->canvas()->concat(contentMatrix);
+ }
+
+ if (viewPort != ctx->lengthContext().viewPort()) {
+ ctx->writableLengthContext()->setViewPort(viewPort);
+ }
+
+ return this->INHERITED::onPrepareToRender(ctx);
+}
+
void SkSVGSVG::setX(const SkSVGLength& x) {
fX = x;
}
fHeight = h;
}
+void SkSVGSVG::setViewBox(const SkSVGViewBoxType& vb) {
+ fViewBox.set(vb);
+}
+
void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
case SkSVGAttribute::kX:
this->setHeight(*h);
}
break;
+ case SkSVGAttribute::kViewBox:
+ if (const auto* vb = v.as<SkSVGViewBoxValue>()) {
+ this->setViewBox(*vb);
+ }
+ break;
default:
this->INHERITED::onSetAttribute(attr, v);
}
#include "SkSVGContainer.h"
#include "SkSVGTypes.h"
+#include "SkTLazy.h"
class SkSVGSVG : public SkSVGContainer {
public:
void setY(const SkSVGLength&);
void setWidth(const SkSVGLength&);
void setHeight(const SkSVGLength&);
+ void setViewBox(const SkSVGViewBoxType&);
protected:
+ bool onPrepareToRender(SkSVGRenderContext*) const override;
+
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
private:
SkSVGLength fWidth = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
SkSVGLength fHeight = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
+ SkTLazy<SkSVGViewBoxType> fViewBox;
+
typedef SkSVGContainer INHERITED;
};
SkSVGShape::SkSVGShape(SkSVGTag t) : INHERITED(t) {}
-void SkSVGShape::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const {
- if (const SkPaint* fillPaint = ctx.fillPaint()) {
- this->onDraw(canvas, ctx.lengthContext(), *fillPaint);
+void SkSVGShape::onRender(const SkSVGRenderContext& ctx) const {
+ if (const SkPaint* fillPaint = ctx.presentationContext().fillPaint()) {
+ this->onDraw(ctx.canvas(), ctx.lengthContext(), *fillPaint);
}
- if (const SkPaint* strokePaint = ctx.strokePaint()) {
- this->onDraw(canvas, ctx.lengthContext(), *strokePaint);
+ if (const SkPaint* strokePaint = ctx.presentationContext().strokePaint()) {
+ this->onDraw(ctx.canvas(), ctx.lengthContext(), *strokePaint);
}
}
protected:
SkSVGShape(SkSVGTag);
- void onRender(SkCanvas*, const SkSVGRenderContext&) const final;
+ void onRender(const SkSVGRenderContext&) const final;
virtual void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const = 0;
* found in the LICENSE file.
*/
+#include "SkCanvas.h"
+#include "SkSVGRenderContext.h"
#include "SkSVGTransformableNode.h"
#include "SkSVGValue.h"
: INHERITED(tag)
, fMatrix(SkMatrix::I()) { }
+
+bool SkSVGTransformableNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
+ if (!fMatrix.isIdentity()) {
+ ctx->canvas()->save();
+ ctx->canvas()->concat(fMatrix);
+ }
+
+ return this->INHERITED::onPrepareToRender(ctx);
+}
+
void SkSVGTransformableNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
case SkSVGAttribute::kTransform:
protected:
SkSVGTransformableNode(SkSVGTag);
- void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
+ bool onPrepareToRender(SkSVGRenderContext*) const override;
- const SkMatrix& onLocalMatrix() const override { return fMatrix; }
+ void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
private:
// FIXME: should be sparse
#define SkSVGTypes_DEFINED
#include "SkColor.h"
+#include "SkRect.h"
#include "SkScalar.h"
#include "SkTypes.h"
-class SkSVGNumber {
+template <typename T>
+class SkSVGPrimitiveTypeWrapper {
public:
- constexpr SkSVGNumber() : fValue(0) {}
- explicit constexpr SkSVGNumber(SkScalar v) : fValue(v) {}
- SkSVGNumber(const SkSVGNumber&) = default;
- SkSVGNumber& operator=(const SkSVGNumber&) = default;
+ SkSVGPrimitiveTypeWrapper() = default;
+ explicit constexpr SkSVGPrimitiveTypeWrapper(T v) : fValue(v) {}
+ SkSVGPrimitiveTypeWrapper(const SkSVGPrimitiveTypeWrapper&) = default;
+ SkSVGPrimitiveTypeWrapper& operator=(const SkSVGPrimitiveTypeWrapper&) = default;
- const SkScalar& value() const { return fValue; }
-
- operator const SkScalar&() const { return fValue; }
+ const T& value() const { return fValue; }
+ operator const T&() const { return fValue; }
private:
- SkScalar fValue;
+ T fValue;
};
+using SkSVGColorType = SkSVGPrimitiveTypeWrapper<SkColor >;
+using SkSVGNumberType = SkSVGPrimitiveTypeWrapper<SkScalar>;
+using SkSVGViewBoxType = SkSVGPrimitiveTypeWrapper<SkRect >;
+
class SkSVGLength {
public:
enum class Unit {
Unit fUnit;
};
-class SkSVGColor {
-public:
- constexpr SkSVGColor() : fValue(SK_ColorBLACK) {}
- explicit constexpr SkSVGColor(SkColor c) : fValue(c) {}
-
- operator const SkColor&() const { return fValue; }
-
-private:
- SkColor fValue;
-};
-
#endif // SkSVGTypes_DEFINED
kLength,
kPath,
kTransform,
+ kViewBox,
};
Type type() const { return fType; }
typedef SkNoncopyable INHERITED;
};
-template <typename SkiaType, SkSVGValue::Type ValueType>
+template <typename T, SkSVGValue::Type ValueType>
class SkSVGWrapperValue final : public SkSVGValue {
public:
static constexpr Type TYPE = ValueType;
- explicit SkSVGWrapperValue(const SkiaType& v)
+ explicit SkSVGWrapperValue(const T& v)
: INHERITED(ValueType)
, fWrappedValue(v) { }
- operator const SkiaType&() const { return fWrappedValue; }
+ operator const T&() const { return fWrappedValue; }
private:
- SkiaType fWrappedValue;
+ // Stack-only
+ void* operator new(size_t) = delete;
+ void* operator new(size_t, void*) = delete;
+
+ const T& fWrappedValue;
typedef SkSVGValue INHERITED;
};
-using SkSVGColorValue = SkSVGWrapperValue<SkSVGColor , SkSVGValue::Type::kColor >;
-using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength, SkSVGValue::Type::kLength >;
-using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >;
-using SkSVGTransformValue = SkSVGWrapperValue<SkMatrix , SkSVGValue::Type::kTransform>;
+using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >;
+using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >;
+using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >;
+using SkSVGTransformValue = SkSVGWrapperValue<SkMatrix , SkSVGValue::Type::kTransform>;
+using SkSVGViewBoxValue = SkSVGWrapperValue<SkSVGViewBoxType, SkSVGValue::Type::kViewBox >;
#endif // SkSVGValue_DEFINED