diff options
author | fmalita <fmalita@chromium.org> | 2016-07-26 18:46:34 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-07-26 18:46:34 -0700 |
commit | 6ceef3dd67617c5f4572ada98d5ee85777d2db99 (patch) | |
tree | 80d683062d7bba05f8fe4df14cedcb489dd4aa00 /experimental/svg | |
parent | fc49d56feb2d890ccb3827ed087ab32e18a9da12 (diff) |
Initial SVG model
A minimal subset needed to render tiger.svg: <svg>, <g>, <path>, 'd', 'fill'/'stroke' (color-only), 'transform'.
R=reed@google.com,robertphillips@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2164193002
Review-Url: https://codereview.chromium.org/2164193002
Diffstat (limited to 'experimental/svg')
-rw-r--r-- | experimental/svg/model/SkSVGAttribute.cpp | 34 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGAttribute.h | 41 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGContainer.cpp | 21 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGContainer.h | 31 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGDOM.cpp | 244 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGDOM.h | 39 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGG.h | 25 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGNode.cpp | 60 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGNode.h | 56 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGPath.cpp | 37 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGPath.h | 38 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGRenderContext.cpp | 52 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGRenderContext.h | 36 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGSVG.cpp | 10 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGSVG.h | 25 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGTransformableNode.cpp | 26 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGTransformableNode.h | 34 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGValue.cpp | 8 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGValue.h | 59 |
19 files changed, 876 insertions, 0 deletions
diff --git a/experimental/svg/model/SkSVGAttribute.cpp b/experimental/svg/model/SkSVGAttribute.cpp new file mode 100644 index 0000000000..c4a374e7e1 --- /dev/null +++ b/experimental/svg/model/SkSVGAttribute.cpp @@ -0,0 +1,34 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSVGAttribute.h" +#include "SkSVGRenderContext.h" + +SkSVGPresentationAttributes::SkSVGPresentationAttributes() + : fFillIsSet(false) + , fStrokeIsSet(false) { } + +void SkSVGPresentationAttributes::setFill(SkColor c) { + fFill = c; + fFillIsSet = true; +} + +void SkSVGPresentationAttributes::setStroke(SkColor c) { + fStroke = c; + fStrokeIsSet = true; +} + + +void SkSVGPresentationAttributes::applyTo(SkTCopyOnFirstWrite<SkSVGRenderContext>& ctx) const { + if (fFillIsSet) { + ctx.writable()->setFillColor(fFill); + } + + if (fStrokeIsSet) { + ctx.writable()->setStrokeColor(fStroke); + } +} diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h new file mode 100644 index 0000000000..50989f17ec --- /dev/null +++ b/experimental/svg/model/SkSVGAttribute.h @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGAttribute_DEFINED +#define SkSVGAttribute_DEFINED + +#include "SkColor.h" +#include "SkTLazy.h" + +enum class SkSVGAttribute { + d, + fill, + stroke, + transform, +}; + +class SkSVGRenderContext; + +class SkSVGPresentationAttributes { +public: + SkSVGPresentationAttributes(); + + void setFill(SkColor); + void setStroke(SkColor); + + void applyTo(SkTCopyOnFirstWrite<SkSVGRenderContext>&) const; + +private: + // Color only for now. + SkColor fFill; + SkColor fStroke; + + unsigned fFillIsSet : 1; + unsigned fStrokeIsSet : 1; +}; + +#endif // SkSVGAttribute_DEFINED diff --git a/experimental/svg/model/SkSVGContainer.cpp b/experimental/svg/model/SkSVGContainer.cpp new file mode 100644 index 0000000000..f8667975bd --- /dev/null +++ b/experimental/svg/model/SkSVGContainer.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSVGContainer.h" + +SkSVGContainer::SkSVGContainer(SkSVGTag t) : INHERITED(t) { } + +void SkSVGContainer::appendChild(sk_sp<SkSVGNode> node) { + SkASSERT(node); + fChildren.push_back(std::move(node)); +} + +void SkSVGContainer::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const { + for (int i = 0; i < fChildren.count(); ++i) { + fChildren[i]->render(canvas, ctx); + } +} diff --git a/experimental/svg/model/SkSVGContainer.h b/experimental/svg/model/SkSVGContainer.h new file mode 100644 index 0000000000..27c7944da7 --- /dev/null +++ b/experimental/svg/model/SkSVGContainer.h @@ -0,0 +1,31 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGContainer_DEFINED +#define SkSVGContainer_DEFINED + +#include "SkSVGTransformableNode.h" +#include "SkTArray.h" + +class SkSVGContainer : public SkSVGTransformableNode { +public: + virtual ~SkSVGContainer() = default; + + void appendChild(sk_sp<SkSVGNode>) override; + +protected: + SkSVGContainer(SkSVGTag); + + void onRender(SkCanvas*, const SkSVGRenderContext&) const override; + +private: + SkSTArray<1, sk_sp<SkSVGNode>, true> fChildren; + + typedef SkSVGTransformableNode INHERITED; +}; + +#endif // SkSVGSVG_DEFINED diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp new file mode 100644 index 0000000000..6f782c3a96 --- /dev/null +++ b/experimental/svg/model/SkSVGDOM.cpp @@ -0,0 +1,244 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCanvas.h" +#include "SkDOM.h" +#include "SkParse.h" +#include "SkParsePath.h" +#include "SkSVGDOM.h" +#include "SkSVGG.h" +#include "SkSVGNode.h" +#include "SkSVGPath.h" +#include "SkSVGSVG.h" +#include "SkSVGValue.h" +#include "SkTSearch.h" + +namespace { + +SkColor ParseColor(const char* str) { + // FIXME: real parser + if (*str++ != '#') { + return SK_ColorBLACK; + } + + uint32_t v; + const char* consumed = SkParse::FindHex(str, &v); + + switch(consumed - str) { + case 6: + // matched '#xxxxxx' + break; + case 3: + // matched '#xxx; + v = ((v << 12) & 0x00f00000) | + ((v << 8) & 0x000ff000) | + ((v << 4) & 0x00000ff0) | + ((v << 0) & 0x0000000f); + break; + default: + // failed + v = 0; + break; + } + + return v | 0xff000000; +} + +const char* ParseScalarPair(const char* str, SkScalar v[2]) { + str = SkParse::FindScalar(str, v); + if (str) { + const char* second = SkParse::FindScalar(str, v + 1); + if (!second) { + v[1] = v[0]; + } else { + str = second; + } + } + + return str; +} + +SkMatrix ParseTransform(const char* str) { + SkMatrix m = SkMatrix::I(); + + // FIXME: real parser + if (!strncmp(str, "matrix(", 7)) { + SkScalar values[6]; + str = SkParse::FindScalars(str + 7, values, 6); + if (str) { + m.setAffine(values); + } + } else if (!strncmp(str, "scale(", 6)) { + SkScalar values[2]; + str = ParseScalarPair(str + 6, values); + if (str) { + m.setScale(values[0], values[1]); + } + } else if (!strncmp(str, "translate(", 10)) { + SkScalar values[2]; + str = ParseScalarPair(str + 10, values); + if (str) { + m.setTranslate(values[0], values[1]); + } + } else if (!strncmp(str, "rotate(", 7)) { + SkScalar value; + str = SkParse::FindScalar(str + 7, &value); + if (str) { + m.setRotate(value); + } + } + + return m; +} + +bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, + const char* stringValue) { + node->setAttribute(attr, SkSVGColorValue(ParseColor(stringValue))); + return true; +} + +bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, + const char* stringValue) { + SkPath path; + if (!SkParsePath::FromSVGString(stringValue, &path)) { + return false; + } + + node->setAttribute(attr, SkSVGPathValue(path)); + return true; +} + +bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, + const char* stringValue) { + node->setAttribute(attr, SkSVGTransformValue(ParseTransform(stringValue))); + return true; +} + +template<typename T> +struct SortedDictionaryEntry { + const char* fKey; + const T fValue; +}; + +struct AttrParseInfo { + SkSVGAttribute fAttr; + bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const char* stringValue); +}; + +SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = { + { "d", { SkSVGAttribute::d, SetPathDataAttribute }}, + { "fill", { SkSVGAttribute::fill, SetPaintAttribute }}, + { "stroke", { SkSVGAttribute::stroke, SetPaintAttribute }}, + { "transform", { SkSVGAttribute::transform, SetTransformAttribute }}, +}; + +SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = { + { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }}, + { "path", []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }}, + { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }}, +}; + +struct ConstructionContext { + ConstructionContext() : fParent(nullptr) { } + ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent) + : fParent(newParent.get()) { } + + const SkSVGNode* fParent; +}; + +void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode, + const sk_sp<SkSVGNode>& svgNode) { + const char* name, *value; + SkDOM::AttrIter attrIter(xmlDom, xmlNode); + while ((name = attrIter.next(&value))) { + const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey, + SkTo<int>(SK_ARRAY_COUNT(gAttributeParseInfo)), + name, sizeof(gAttributeParseInfo[0])); + if (attrIndex < 0) { + SkDebugf("unhandled attribute: %s\n", name); + continue; + } + + SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo)); + const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue; + if (!attrInfo.fSetter(svgNode, attrInfo.fAttr, value)) { + SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value); + } + } +} + +sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx, + const SkDOM::Node* xmlNode) { + const char* elem = dom.getName(xmlNode); + const SkDOM::Type elemType = dom.getType(xmlNode); + + if (elemType == SkDOM::kText_Type) { + SkASSERT(dom.countChildren(xmlNode) == 0); + // TODO: text handling + return nullptr; + } + + SkASSERT(elemType == SkDOM::kElement_Type); + + const int tagIndex = SkStrSearch(&gTagFactories[0].fKey, + SkTo<int>(SK_ARRAY_COUNT(gTagFactories)), + elem, sizeof(gTagFactories[0])); + if (tagIndex < 0) { + SkDebugf("unhandled element: <%s>\n", elem); + return nullptr; + } + + SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories)); + sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue(); + parse_node_attributes(dom, xmlNode, node); + + ConstructionContext localCtx(ctx, node); + for (auto* child = dom.getFirstChild(xmlNode, nullptr); child; + child = dom.getNextSibling(child)) { + sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child); + if (childNode) { + node->appendChild(std::move(childNode)); + } + } + + return node; +} + +} // anonymous namespace + +SkSVGDOM::SkSVGDOM(const SkSize& containerSize) + : fContainerSize(containerSize) { +} + +sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom, const SkSize& containerSize) { + sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>(containerSize); + + ConstructionContext ctx; + dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode()); + + return dom; +} + +sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, const SkSize& containerSize) { + SkDOM xmlDom; + if (!xmlDom.build(svgStream)) { + return nullptr; + } + + return MakeFromDOM(xmlDom, containerSize); +} + +void SkSVGDOM::render(SkCanvas* canvas) const { + if (fRoot) { + fRoot->render(canvas); + } +} + +void SkSVGDOM::setContainerSize(const SkSize& containerSize) { + // TODO: inval + fContainerSize = containerSize; +} diff --git a/experimental/svg/model/SkSVGDOM.h b/experimental/svg/model/SkSVGDOM.h new file mode 100644 index 0000000000..468ac00a90 --- /dev/null +++ b/experimental/svg/model/SkSVGDOM.h @@ -0,0 +1,39 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGDOM_DEFINED +#define SkSVGDOM_DEFINED + +#include "SkRefCnt.h" +#include "SkSize.h" +#include "SkTemplates.h" + +class SkCanvas; +class SkDOM; +class SkStream; +class SkSVGNode; + +class SkSVGDOM : public SkRefCnt { +public: + SkSVGDOM(const SkSize& containerSize); + ~SkSVGDOM() = default; + + static sk_sp<SkSVGDOM> MakeFromDOM(const SkDOM&, const SkSize& containerSize); + static sk_sp<SkSVGDOM> MakeFromStream(SkStream&, const SkSize& containerSize); + + void setContainerSize(const SkSize&); + + void render(SkCanvas*) const; + +private: + SkSize fContainerSize; + sk_sp<SkSVGNode> fRoot; + + typedef SkRefCnt INHERITED; +}; + +#endif // SkSVGDOM_DEFINED diff --git a/experimental/svg/model/SkSVGG.h b/experimental/svg/model/SkSVGG.h new file mode 100644 index 0000000000..eaaf822d78 --- /dev/null +++ b/experimental/svg/model/SkSVGG.h @@ -0,0 +1,25 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGG_DEFINED +#define SkSVGG_DEFINED + +#include "SkSVGContainer.h" + +class SkSVGG : public SkSVGContainer { +public: + virtual ~SkSVGG() = default; + + static sk_sp<SkSVGG> Make() { return sk_sp<SkSVGG>(new SkSVGG()); } + +private: + SkSVGG() : INHERITED(SkSVGTag::g) { } + + typedef SkSVGContainer INHERITED; +}; + +#endif // SkSVGG_DEFINED diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp new file mode 100644 index 0000000000..2b891792fd --- /dev/null +++ b/experimental/svg/model/SkSVGNode.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCanvas.h" +#include "SkMatrix.h" +#include "SkSVGNode.h" +#include "SkSVGRenderContext.h" +#include "SkSVGValue.h" +#include "SkTLazy.h" + +SkSVGNode::SkSVGNode(SkSVGTag t) : fTag(t) { } + +SkSVGNode::~SkSVGNode() { } + +void SkSVGNode::render(SkCanvas* canvas) const { + this->render(canvas, SkSVGRenderContext()); +} + +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); + } + + this->onRender(canvas, *localContext); +} + +void SkSVGNode::setAttribute(SkSVGAttribute attr, const SkSVGValue& v) { + this->onSetAttribute(attr, v); +} + +void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) { + switch (attr) { + case SkSVGAttribute::fill: + if (const SkSVGColorValue* color = v.as<SkSVGColorValue>()) { + fPresentationAttributes.setFill(*color); + } + break; + case SkSVGAttribute::stroke: + if (const SkSVGColorValue* color = v.as<SkSVGColorValue>()) { + fPresentationAttributes.setStroke(*color); + } + break; + default: + break; + } +} + +const SkMatrix& SkSVGNode::onLocalMatrix() const { + return SkMatrix::I(); +} diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h new file mode 100644 index 0000000000..de180146b7 --- /dev/null +++ b/experimental/svg/model/SkSVGNode.h @@ -0,0 +1,56 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGNode_DEFINED +#define SkSVGNode_DEFINED + +#include "SkRefCnt.h" +#include "SkSVGAttribute.h" + +class SkCanvas; +class SkMatrix; +class SkSVGRenderContext; +class SkSVGValue; + +enum class SkSVGTag { + g, + path, + svg +}; + +class SkSVGNode : public SkRefCnt { +public: + virtual ~SkSVGNode(); + + SkSVGTag tag() const { return fTag; } + + virtual void appendChild(sk_sp<SkSVGNode>) = 0; + + void render(SkCanvas*) const; + void render(SkCanvas*, const SkSVGRenderContext&) const; + + void setAttribute(SkSVGAttribute, const SkSVGValue&); + +protected: + SkSVGNode(SkSVGTag); + + virtual void onRender(SkCanvas*, const SkSVGRenderContext&) const = 0; + + virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&); + + virtual const SkMatrix& onLocalMatrix() const; + +private: + SkSVGTag fTag; + + // FIXME: this should be sparse + SkSVGPresentationAttributes fPresentationAttributes; + + typedef SkRefCnt INHERITED; +}; + +#endif // SkSVGNode_DEFINED diff --git a/experimental/svg/model/SkSVGPath.cpp b/experimental/svg/model/SkSVGPath.cpp new file mode 100644 index 0000000000..ba5e3d62ba --- /dev/null +++ b/experimental/svg/model/SkSVGPath.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkSVGPath.h" +#include "SkSVGRenderContext.h" +#include "SkSVGValue.h" + +SkSVGPath::SkSVGPath() : INHERITED(SkSVGTag::path) { } + +void SkSVGPath::doRender(SkCanvas* canvas, const SkPaint* paint) const { + if (paint) { + canvas->drawPath(fPath, *paint); + } +} + +void SkSVGPath::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const { + this->doRender(canvas, ctx.fillPaint()); + this->doRender(canvas, ctx.strokePaint()); +} + +void SkSVGPath::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) { + switch (attr) { + case SkSVGAttribute::d: + if (const auto* path = v.as<SkSVGPathValue>()) { + this->setPath(*path); + } + break; + default: + this->INHERITED::onSetAttribute(attr, v); + } +} diff --git a/experimental/svg/model/SkSVGPath.h b/experimental/svg/model/SkSVGPath.h new file mode 100644 index 0000000000..b650f67463 --- /dev/null +++ b/experimental/svg/model/SkSVGPath.h @@ -0,0 +1,38 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGPath_DEFINED +#define SkSVGPath_DEFINED + +#include "SkPath.h" +#include "SkSVGTransformableNode.h" + +class SkSVGPath final : public SkSVGTransformableNode { +public: + virtual ~SkSVGPath() = default; + static sk_sp<SkSVGPath> Make() { return sk_sp<SkSVGPath>(new SkSVGPath()); } + + void appendChild(sk_sp<SkSVGNode>) override { } + + void setPath(const SkPath& path) { fPath = path; } + +protected: + void onRender(SkCanvas*, const SkSVGRenderContext&) const override; + + void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override; + +private: + SkSVGPath(); + + void doRender(SkCanvas*, const SkPaint*) const; + + SkPath fPath; + + typedef SkSVGTransformableNode INHERITED; +}; + +#endif // SkSVGPath_DEFINED diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp new file mode 100644 index 0000000000..703606c528 --- /dev/null +++ b/experimental/svg/model/SkSVGRenderContext.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSVGRenderContext.h" + +SkSVGRenderContext::SkSVGRenderContext() { } + +SkSVGRenderContext& SkSVGRenderContext::operator=(const SkSVGRenderContext& other) { + if (other.fFill.isValid()) { + fFill.set(*other.fFill.get()); + } else { + fFill.reset(); + } + + if (other.fStroke.isValid()) { + fStroke.set(*other.fStroke.get()); + } else { + fStroke.reset(); + } + + return *this; +} + +SkPaint& SkSVGRenderContext::ensureFill() { + if (!fFill.isValid()) { + fFill.init(); + fFill.get()->setStyle(SkPaint::kFill_Style); + fFill.get()->setAntiAlias(true); + } + return *fFill.get(); +} + +SkPaint& SkSVGRenderContext::ensureStroke() { + if (!fStroke.isValid()) { + fStroke.init(); + fStroke.get()->setStyle(SkPaint::kStroke_Style); + fStroke.get()->setAntiAlias(true); + } + return *fStroke.get(); +} + +void SkSVGRenderContext::setFillColor(SkColor color) { + this->ensureFill().setColor(color); +} + +void SkSVGRenderContext::setStrokeColor(SkColor color) { + this->ensureStroke().setColor(color); +} diff --git a/experimental/svg/model/SkSVGRenderContext.h b/experimental/svg/model/SkSVGRenderContext.h new file mode 100644 index 0000000000..8ebaf12f0c --- /dev/null +++ b/experimental/svg/model/SkSVGRenderContext.h @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGRenderContext_DEFINED +#define SkSVGRenderContext_DEFINED + +#include "SkPaint.h" +#include "SkTLazy.h" + +class SkPaint; + +class SkSVGRenderContext { +public: + SkSVGRenderContext(); + SkSVGRenderContext(const SkSVGRenderContext&) = default; + SkSVGRenderContext& operator=(const SkSVGRenderContext&); + + const SkPaint* fillPaint() const { return fFill.getMaybeNull(); } + const SkPaint* strokePaint() const { return fStroke.getMaybeNull(); } + + void setFillColor(SkColor); + void setStrokeColor(SkColor); + +private: + SkPaint& ensureFill(); + SkPaint& ensureStroke(); + + SkTLazy<SkPaint> fFill; + SkTLazy<SkPaint> fStroke; +}; + +#endif // SkSVGRenderContext_DEFINED diff --git a/experimental/svg/model/SkSVGSVG.cpp b/experimental/svg/model/SkSVGSVG.cpp new file mode 100644 index 0000000000..feae0d7cc0 --- /dev/null +++ b/experimental/svg/model/SkSVGSVG.cpp @@ -0,0 +1,10 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSVGSVG.h" + +SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::svg) { } diff --git a/experimental/svg/model/SkSVGSVG.h b/experimental/svg/model/SkSVGSVG.h new file mode 100644 index 0000000000..8e69d144d6 --- /dev/null +++ b/experimental/svg/model/SkSVGSVG.h @@ -0,0 +1,25 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGSVG_DEFINED +#define SkSVGSVG_DEFINED + +#include "SkSVGContainer.h" + +class SkSVGSVG : public SkSVGContainer { +public: + virtual ~SkSVGSVG() = default; + + static sk_sp<SkSVGSVG> Make() { return sk_sp<SkSVGSVG>(new SkSVGSVG()); } + +private: + SkSVGSVG(); + + typedef SkSVGContainer INHERITED; +}; + +#endif // SkSVGSVG_DEFINED diff --git a/experimental/svg/model/SkSVGTransformableNode.cpp b/experimental/svg/model/SkSVGTransformableNode.cpp new file mode 100644 index 0000000000..1af89d8c73 --- /dev/null +++ b/experimental/svg/model/SkSVGTransformableNode.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSVGTransformableNode.h" +#include "SkSVGValue.h" + +SkSVGTransformableNode::SkSVGTransformableNode(SkSVGTag tag) + : INHERITED(tag) + , fMatrix(SkMatrix::I()) { } + +void SkSVGTransformableNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) { + switch (attr) { + case SkSVGAttribute::transform: + if (const auto* transform = v.as<SkSVGTransformValue>()) { + this->setTransform(*transform); + } + break; + default: + this->INHERITED::onSetAttribute(attr, v); + break; + } +} diff --git a/experimental/svg/model/SkSVGTransformableNode.h b/experimental/svg/model/SkSVGTransformableNode.h new file mode 100644 index 0000000000..c345e8594f --- /dev/null +++ b/experimental/svg/model/SkSVGTransformableNode.h @@ -0,0 +1,34 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGTransformableNode_DEFINED +#define SkSVGTransformableNode_DEFINED + +#include "SkMatrix.h" +#include "SkSVGNode.h" + +class SkSVGTransformableNode : public SkSVGNode { +public: + virtual ~SkSVGTransformableNode() = default; + + void setTransform(const SkMatrix& m) { fMatrix = m; } + +protected: + SkSVGTransformableNode(SkSVGTag); + + void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override; + + const SkMatrix& onLocalMatrix() const override { return fMatrix; } + +private: + // FIXME: should be sparse + SkMatrix fMatrix; + + typedef SkSVGNode INHERITED; +}; + +#endif // SkSVGTransformableNode_DEFINED diff --git a/experimental/svg/model/SkSVGValue.cpp b/experimental/svg/model/SkSVGValue.cpp new file mode 100644 index 0000000000..674a200a34 --- /dev/null +++ b/experimental/svg/model/SkSVGValue.cpp @@ -0,0 +1,8 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSVGValue.h" diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h new file mode 100644 index 0000000000..3d3cd6efc1 --- /dev/null +++ b/experimental/svg/model/SkSVGValue.h @@ -0,0 +1,59 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSVGValue_DEFINED +#define SkSVGValue_DEFINED + +#include "SkColor.h" +#include "SkMatrix.h" +#include "SkPath.h" +#include "SkTypes.h" + +class SkSVGValue : public SkNoncopyable { +public: + enum class Type { + Color, + Path, + Transform, + }; + + Type type() const { return fType; } + + template <typename T> + const T* as() const { + return fType == T::TYPE ? static_cast<const T*>(this) : nullptr; + } + +protected: + SkSVGValue(Type t) : fType(t) { } + +private: + Type fType; +}; + +template <typename SkiaType, SkSVGValue::Type ValueType> +class SkSVGWrapperValue final : public SkSVGValue { +public: + static constexpr Type TYPE = ValueType; + + explicit SkSVGWrapperValue(const SkiaType& v) + : INHERITED(ValueType) + , fWrappedValue(v) { } + + operator const SkiaType&() const { return fWrappedValue; } + +private: + SkiaType fWrappedValue; + + using INHERITED = SkSVGValue; +}; + +using SkSVGColorValue = SkSVGWrapperValue<SkColor , SkSVGValue::Type::Color >; +using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::Path >; +using SkSVGTransformValue = SkSVGWrapperValue<SkMatrix, SkSVGValue::Type::Transform>; + +#endif // SkSVGValue_DEFINED |