aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2016-08-03 10:21:11 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-03 10:21:11 -0700
commitbffc2566872f99d378a1113d0a49ec9ee0d60b7a (patch)
tree3a7fab8b6206e99201b1ea817c95454f340260c8 /experimental/svg
parent9e3d3d8b363edcdd81a13b2be046152c6bb839cd (diff)
[SVGDom] Initial SVGLength support
Mostly plumb new length types, but also introduce a stateful parser, rect shape and named color support. R=reed@google.com,robertphillips@google.com,stephana@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2202053002 Review-Url: https://codereview.chromium.org/2202053002
Diffstat (limited to 'experimental/svg')
-rw-r--r--experimental/svg/model/SkSVGAttribute.cpp4
-rw-r--r--experimental/svg/model/SkSVGAttribute.h14
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.cpp194
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.h45
-rw-r--r--experimental/svg/model/SkSVGDOM.cpp69
-rw-r--r--experimental/svg/model/SkSVGNode.cpp5
-rw-r--r--experimental/svg/model/SkSVGNode.h2
-rw-r--r--experimental/svg/model/SkSVGPath.cpp15
-rw-r--r--experimental/svg/model/SkSVGPath.h14
-rw-r--r--experimental/svg/model/SkSVGRect.cpp68
-rw-r--r--experimental/svg/model/SkSVGRect.h40
-rw-r--r--experimental/svg/model/SkSVGRenderContext.cpp38
-rw-r--r--experimental/svg/model/SkSVGRenderContext.h29
-rw-r--r--experimental/svg/model/SkSVGSVG.cpp44
-rw-r--r--experimental/svg/model/SkSVGSVG.h14
-rw-r--r--experimental/svg/model/SkSVGShape.cpp25
-rw-r--r--experimental/svg/model/SkSVGShape.h33
-rw-r--r--experimental/svg/model/SkSVGTypes.h72
-rw-r--r--experimental/svg/model/SkSVGValue.cpp1
-rw-r--r--experimental/svg/model/SkSVGValue.h19
20 files changed, 667 insertions, 78 deletions
diff --git a/experimental/svg/model/SkSVGAttribute.cpp b/experimental/svg/model/SkSVGAttribute.cpp
index c4a374e7e1..79c355176f 100644
--- a/experimental/svg/model/SkSVGAttribute.cpp
+++ b/experimental/svg/model/SkSVGAttribute.cpp
@@ -12,12 +12,12 @@ SkSVGPresentationAttributes::SkSVGPresentationAttributes()
: fFillIsSet(false)
, fStrokeIsSet(false) { }
-void SkSVGPresentationAttributes::setFill(SkColor c) {
+void SkSVGPresentationAttributes::setFill(const SkSVGColor& c) {
fFill = c;
fFillIsSet = true;
}
-void SkSVGPresentationAttributes::setStroke(SkColor c) {
+void SkSVGPresentationAttributes::setStroke(const SkSVGColor& c) {
fStroke = c;
fStrokeIsSet = true;
}
diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h
index 83a35527c5..64465b13c9 100644
--- a/experimental/svg/model/SkSVGAttribute.h
+++ b/experimental/svg/model/SkSVGAttribute.h
@@ -8,14 +8,18 @@
#ifndef SkSVGAttribute_DEFINED
#define SkSVGAttribute_DEFINED
-#include "SkColor.h"
+#include "SkSVGTypes.h"
#include "SkTLazy.h"
enum class SkSVGAttribute {
kD,
kFill,
+ kHeight,
kStroke,
kTransform,
+ kWidth,
+ kX,
+ kY,
kUnknown,
};
@@ -26,15 +30,15 @@ class SkSVGPresentationAttributes {
public:
SkSVGPresentationAttributes();
- void setFill(SkColor);
- void setStroke(SkColor);
+ void setFill(const SkSVGColor&);
+ void setStroke(const SkSVGColor&);
void applyTo(SkTCopyOnFirstWrite<SkSVGRenderContext>&) const;
private:
// Color only for now.
- SkColor fFill;
- SkColor fStroke;
+ SkSVGColor fFill;
+ SkSVGColor fStroke;
unsigned fFillIsSet : 1;
unsigned fStrokeIsSet : 1;
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp
new file mode 100644
index 0000000000..75e5d12f38
--- /dev/null
+++ b/experimental/svg/model/SkSVGAttributeParser.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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 "SkParse.h"
+#include "SkSVGAttributeParser.h"
+#include "SkSVGTypes.h"
+
+namespace {
+
+// TODO: these should be shared with SkParse.cpp
+
+inline bool is_between(char c, char min, char max) {
+ SkASSERT(min <= max);
+ return (unsigned)(c - min) <= (unsigned)(max - min);
+}
+
+inline bool is_eos(char c) {
+ return !c;
+}
+
+inline bool is_ws(char c) {
+ return is_between(c, 1, 32);
+}
+
+inline bool is_sep(char c) {
+ return is_ws(c) || c == ',' || c == ';';
+}
+
+} // anonymous ns
+
+SkSVGAttributeParser::SkSVGAttributeParser(const char attributeString[])
+ : fCurPos(attributeString) {}
+
+template <typename F>
+inline bool SkSVGAttributeParser::advanceWhile(F f) {
+ auto initial = fCurPos;
+ while (f(*fCurPos)) {
+ fCurPos++;
+ }
+ return fCurPos != initial;
+}
+
+inline bool SkSVGAttributeParser::parseEOSToken() {
+ return is_eos(*fCurPos);
+}
+
+inline bool SkSVGAttributeParser::parseSepToken() {
+ return this->advanceWhile(is_sep);
+}
+
+inline bool SkSVGAttributeParser::parseWSToken() {
+ return this->advanceWhile(is_ws);
+}
+
+inline bool SkSVGAttributeParser::parseExpectedStringToken(const char* expected) {
+ const char* c = fCurPos;
+
+ while (*c && *expected && *c == *expected) {
+ c++;
+ expected++;
+ }
+
+ if (*expected) {
+ return false;
+ }
+
+ fCurPos = c;
+ return true;
+}
+
+bool SkSVGAttributeParser::parseScalarToken(SkScalar* res) {
+ if (const char* next = SkParse::FindScalar(fCurPos, res)) {
+ fCurPos = next;
+ return true;
+ }
+ return false;
+}
+
+bool SkSVGAttributeParser::parseHexToken(uint32_t* res) {
+ if (const char* next = SkParse::FindHex(fCurPos, res)) {
+ fCurPos = next;
+ return true;
+ }
+ return false;
+}
+
+bool SkSVGAttributeParser::parseLengthUnitToken(SkSVGLength::Unit* unit) {
+ static const struct {
+ const char* fUnitName;
+ SkSVGLength::Unit fUnit;
+ } gUnitInfo[] = {
+ { "%" , SkSVGLength::Unit::kPercentage },
+ { "em", SkSVGLength::Unit::kEMS },
+ { "ex", SkSVGLength::Unit::kEXS },
+ { "px", SkSVGLength::Unit::kPX },
+ { "cm", SkSVGLength::Unit::kCM },
+ { "mm", SkSVGLength::Unit::kMM },
+ { "in", SkSVGLength::Unit::kIN },
+ { "pt", SkSVGLength::Unit::kPT },
+ { "pc", SkSVGLength::Unit::kPC },
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gUnitInfo); ++i) {
+ if (this->parseExpectedStringToken(gUnitInfo[i].fUnitName)) {
+ *unit = gUnitInfo[i].fUnit;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SkSVGAttributeParser::parseNamedColorToken(SkColor* c) {
+ if (const char* next = SkParse::FindNamedColor(fCurPos, strlen(fCurPos), c)) {
+ fCurPos = next;
+ return true;
+ }
+ return false;
+}
+
+bool SkSVGAttributeParser::parseHexColorToken(SkColor* c) {
+ uint32_t v;
+ const char* initial = fCurPos;
+
+ if (!this->parseExpectedStringToken("#") || !this->parseHexToken(&v)) {
+ return false;
+ }
+
+ switch (fCurPos - initial) {
+ case 7:
+ // matched #xxxxxxx
+ break;
+ case 4:
+ // matched '#xxx;
+ v = ((v << 12) & 0x00f00000) |
+ ((v << 8) & 0x000ff000) |
+ ((v << 4) & 0x00000ff0) |
+ ((v << 0) & 0x0000000f);
+ break;
+ default:
+ return false;
+ }
+
+ *c = v | 0xff000000;
+ return true;
+}
+
+// https://www.w3.org/TR/SVG/types.html#DataTypeColor
+bool SkSVGAttributeParser::parseColor(SkSVGColor* color) {
+ SkColor c;
+
+ // TODO: rgb(...)
+ if (this->parseHexColorToken(&c) || this->parseNamedColorToken(&c)) {
+ *color = SkSVGColor(c);
+ return true;
+ }
+
+ return false;
+}
+
+// https://www.w3.org/TR/SVG/types.html#DataTypeNumber
+bool SkSVGAttributeParser::parseNumber(SkSVGNumber* number) {
+ // consume WS
+ this->parseWSToken();
+
+ SkScalar s;
+ if (this->parseScalarToken(&s)) {
+ *number = SkSVGNumber(s);
+ // consume trailing separators
+ this->parseSepToken();
+ return true;
+ }
+
+ return false;
+}
+
+// https://www.w3.org/TR/SVG/types.html#DataTypeLength
+bool SkSVGAttributeParser::parseLength(SkSVGLength* length) {
+ SkScalar s;
+ SkSVGLength::Unit u = SkSVGLength::Unit::kNumber;
+
+ if (this->parseScalarToken(&s) &&
+ (this->parseLengthUnitToken(&u) || this->parseSepToken() || this->parseEOSToken())) {
+ *length = SkSVGLength(s, u);
+ // consume trailing separators
+ this->parseSepToken();
+ return true;
+ }
+
+ return false;
+}
diff --git a/experimental/svg/model/SkSVGAttributeParser.h b/experimental/svg/model/SkSVGAttributeParser.h
new file mode 100644
index 0000000000..aef0286504
--- /dev/null
+++ b/experimental/svg/model/SkSVGAttributeParser.h
@@ -0,0 +1,45 @@
+/*
+ * 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 SkSVGAttributeParser_DEFINED
+#define SkSVGAttributeParser_DEFINED
+
+#include "SkSVGTypes.h"
+
+class SkSVGAttributeParser : public SkNoncopyable {
+public:
+ SkSVGAttributeParser(const char[]);
+
+ bool parseColor(SkSVGColor*);
+ bool parseNumber(SkSVGNumber*);
+ bool parseLength(SkSVGLength*);
+
+private:
+ // Stack-only
+ void* operator new(size_t) = delete;
+ void* operator new(size_t, void*) = delete;
+
+ template <typename F>
+ bool advanceWhile(F func);
+
+ bool parseWSToken();
+ bool parseEOSToken();
+ bool parseSepToken();
+ bool parseExpectedStringToken(const char*);
+ bool parseScalarToken(SkScalar*);
+ bool parseHexToken(uint32_t*);
+ bool parseLengthUnitToken(SkSVGLength::Unit*);
+ bool parseNamedColorToken(SkColor*);
+ bool parseHexColorToken(SkColor*);
+
+ // The current position in the input string.
+ const char* fCurPos;
+
+ typedef SkNoncopyable INHERITED;
+};
+
+#endif // SkSVGAttributeParser_DEFINED
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index 4e2f898942..df589230e0 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -10,45 +10,20 @@
#include "SkParse.h"
#include "SkParsePath.h"
#include "SkString.h"
+#include "SkSVGAttributeParser.h"
#include "SkSVGDOM.h"
#include "SkSVGG.h"
#include "SkSVGNode.h"
#include "SkSVGPath.h"
+#include "SkSVGRect.h"
+#include "SkSVGRenderContext.h"
#include "SkSVGSVG.h"
+#include "SkSVGTypes.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) {
@@ -98,7 +73,13 @@ SkMatrix ParseTransform(const char* str) {
bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
- node->setAttribute(attr, SkSVGColorValue(ParseColor(stringValue)));
+ SkSVGColor color;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseColor(&color)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGColorValue(color));
return true;
}
@@ -119,6 +100,18 @@ bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
+bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGLength length;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseLength(&length)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGLengthValue(length));
+ return true;
+}
+
// Breaks a "foo: bar; baz: ..." string into key:value pairs.
class StyleIterator {
public:
@@ -185,16 +178,21 @@ struct AttrParseInfo {
};
SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
- { "d", { SkSVGAttribute::kD, SetPathDataAttribute }},
- { "fill", { SkSVGAttribute::kFill, SetPaintAttribute }},
- { "stroke", { SkSVGAttribute::kStroke, SetPaintAttribute }},
- { "style", { SkSVGAttribute::kUnknown, SetStyleAttributes }},
+ { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
+ { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
+ { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
+ { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
+ { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
{ "transform", { SkSVGAttribute::kTransform, SetTransformAttribute }},
+ { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
+ { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
+ { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
};
SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
{ "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
{ "path", []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
+ { "rect", []() -> sk_sp<SkSVGNode> { return SkSVGRect::Make(); }},
{ "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
};
@@ -294,7 +292,8 @@ sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, const SkSize& cont
void SkSVGDOM::render(SkCanvas* canvas) const {
if (fRoot) {
- fRoot->render(canvas);
+ SkSVGRenderContext ctx(fContainerSize);
+ fRoot->render(canvas, ctx);
}
}
diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp
index 58e0ad4989..eb82834f38 100644
--- a/experimental/svg/model/SkSVGNode.cpp
+++ b/experimental/svg/model/SkSVGNode.cpp
@@ -16,10 +16,6 @@ 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);
@@ -51,6 +47,7 @@ void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
break;
default:
+ SkDebugf("attribute ID <%d> ignored for node <%d>\n", attr, fTag);
break;
}
}
diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h
index 407e69ac63..168b03c73b 100644
--- a/experimental/svg/model/SkSVGNode.h
+++ b/experimental/svg/model/SkSVGNode.h
@@ -19,6 +19,7 @@ class SkSVGValue;
enum class SkSVGTag {
kG,
kPath,
+ kRect,
kSvg
};
@@ -30,7 +31,6 @@ public:
virtual void appendChild(sk_sp<SkSVGNode>) = 0;
- void render(SkCanvas*) const;
void render(SkCanvas*, const SkSVGRenderContext&) const;
void setAttribute(SkSVGAttribute, const SkSVGValue&);
diff --git a/experimental/svg/model/SkSVGPath.cpp b/experimental/svg/model/SkSVGPath.cpp
index 7d905945bc..07e0a3e545 100644
--- a/experimental/svg/model/SkSVGPath.cpp
+++ b/experimental/svg/model/SkSVGPath.cpp
@@ -13,17 +13,6 @@
SkSVGPath::SkSVGPath() : INHERITED(SkSVGTag::kPath) { }
-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::kD:
@@ -35,3 +24,7 @@ void SkSVGPath::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
this->INHERITED::onSetAttribute(attr, v);
}
}
+
+void SkSVGPath::onDraw(SkCanvas* canvas, const SkSVGLengthContext&, const SkPaint& paint) const {
+ canvas->drawPath(fPath, paint);
+}
diff --git a/experimental/svg/model/SkSVGPath.h b/experimental/svg/model/SkSVGPath.h
index b650f67463..e72f0d137e 100644
--- a/experimental/svg/model/SkSVGPath.h
+++ b/experimental/svg/model/SkSVGPath.h
@@ -9,30 +9,26 @@
#define SkSVGPath_DEFINED
#include "SkPath.h"
-#include "SkSVGTransformableNode.h"
+#include "SkSVGShape.h"
-class SkSVGPath final : public SkSVGTransformableNode {
+class SkSVGPath final : public SkSVGShape {
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;
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+
private:
SkSVGPath();
- void doRender(SkCanvas*, const SkPaint*) const;
-
SkPath fPath;
- typedef SkSVGTransformableNode INHERITED;
+ typedef SkSVGShape INHERITED;
};
#endif // SkSVGPath_DEFINED
diff --git a/experimental/svg/model/SkSVGRect.cpp b/experimental/svg/model/SkSVGRect.cpp
new file mode 100644
index 0000000000..288fc48258
--- /dev/null
+++ b/experimental/svg/model/SkSVGRect.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "SkRect.h"
+#include "SkSVGRect.h"
+#include "SkSVGRenderContext.h"
+#include "SkSVGValue.h"
+
+SkSVGRect::SkSVGRect() : INHERITED(SkSVGTag::kRect) {}
+
+void SkSVGRect::setX(const SkSVGLength& x) {
+ fX = x;
+}
+
+void SkSVGRect::setY(const SkSVGLength& y) {
+ fY = y;
+}
+
+void SkSVGRect::setWidth(const SkSVGLength& w) {
+ fWidth = w;
+}
+
+void SkSVGRect::setHeight(const SkSVGLength& h) {
+ fHeight = h;
+}
+
+void SkSVGRect::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
+ switch (attr) {
+ case SkSVGAttribute::kX:
+ if (const auto* x = v.as<SkSVGLengthValue>()) {
+ this->setX(*x);
+ }
+ break;
+ case SkSVGAttribute::kY:
+ if (const auto* y = v.as<SkSVGLengthValue>()) {
+ this->setY(*y);
+ }
+ break;
+ case SkSVGAttribute::kWidth:
+ if (const auto* w = v.as<SkSVGLengthValue>()) {
+ this->setWidth(*w);
+ }
+ break;
+ case SkSVGAttribute::kHeight:
+ if (const auto* h = v.as<SkSVGLengthValue>()) {
+ this->setHeight(*h);
+ }
+ break;
+ default:
+ this->INHERITED::onSetAttribute(attr, v);
+ }
+}
+
+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);
+}
diff --git a/experimental/svg/model/SkSVGRect.h b/experimental/svg/model/SkSVGRect.h
new file mode 100644
index 0000000000..b4cd363d77
--- /dev/null
+++ b/experimental/svg/model/SkSVGRect.h
@@ -0,0 +1,40 @@
+/*
+ * 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 SkSVGRect_DEFINED
+#define SkSVGRect_DEFINED
+
+#include "SkSVGShape.h"
+#include "SkSVGTypes.h"
+
+class SkSVGRect final : public SkSVGShape {
+public:
+ virtual ~SkSVGRect() = default;
+ static sk_sp<SkSVGRect> Make() { return sk_sp<SkSVGRect>(new SkSVGRect()); }
+
+ void setX(const SkSVGLength&);
+ void setY(const SkSVGLength&);
+ void setWidth(const SkSVGLength&);
+ void setHeight(const SkSVGLength&);
+
+protected:
+ void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
+
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+
+private:
+ SkSVGRect();
+
+ SkSVGLength fX = SkSVGLength(0);
+ SkSVGLength fY = SkSVGLength(0);
+ SkSVGLength fWidth = SkSVGLength(0);
+ SkSVGLength fHeight = SkSVGLength(0);
+
+ typedef SkSVGShape INHERITED;
+};
+
+#endif // SkSVGRect_DEFINED
diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp
index 703606c528..38498d36c8 100644
--- a/experimental/svg/model/SkSVGRenderContext.cpp
+++ b/experimental/svg/model/SkSVGRenderContext.cpp
@@ -6,8 +6,44 @@
*/
#include "SkSVGRenderContext.h"
+#include "SkSVGTypes.h"
-SkSVGRenderContext::SkSVGRenderContext() { }
+namespace {
+
+SkScalar length_size_for_type(const SkSize& viewport, SkSVGLengthContext::LengthType t) {
+ switch (t) {
+ case SkSVGLengthContext::LengthType::kHorizontal:
+ return viewport.width();
+ case SkSVGLengthContext::LengthType::kVertical:
+ return viewport.height();
+ case SkSVGLengthContext::LengthType::kOther:
+ return SkScalarSqrt(viewport.width() * viewport.height());
+ }
+
+ SkASSERT(false); // Not reached.
+ return 0;
+}
+
+} // anonymous ns
+
+SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const {
+ switch (l.unit()) {
+ case SkSVGLength::Unit::kNumber:
+ 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;
+}
+
+SkSVGRenderContext::SkSVGRenderContext(const SkSize& initialViewport)
+ : fLengthContext(initialViewport) {}
SkSVGRenderContext& SkSVGRenderContext::operator=(const SkSVGRenderContext& other) {
if (other.fFill.isValid()) {
diff --git a/experimental/svg/model/SkSVGRenderContext.h b/experimental/svg/model/SkSVGRenderContext.h
index 8ebaf12f0c..50a6d59e5e 100644
--- a/experimental/svg/model/SkSVGRenderContext.h
+++ b/experimental/svg/model/SkSVGRenderContext.h
@@ -8,17 +8,39 @@
#ifndef SkSVGRenderContext_DEFINED
#define SkSVGRenderContext_DEFINED
+#include "SkSize.h"
#include "SkPaint.h"
#include "SkTLazy.h"
class SkPaint;
+class SkSVGLength;
+
+class SkSVGLengthContext {
+public:
+ SkSVGLengthContext(const SkSize& viewport) : fViewport(viewport) {}
+
+ enum class LengthType {
+ kHorizontal,
+ kVertical,
+ kOther,
+ };
+
+ void setViewPort(const SkSize& viewport) { fViewport = viewport; }
+
+ SkScalar resolve(const SkSVGLength&, LengthType) const;
+
+private:
+ SkSize fViewport;
+};
class SkSVGRenderContext {
public:
- SkSVGRenderContext();
+ explicit SkSVGRenderContext(const SkSize& initialViewport);
SkSVGRenderContext(const SkSVGRenderContext&) = default;
SkSVGRenderContext& operator=(const SkSVGRenderContext&);
+ const SkSVGLengthContext& lengthContext() const { return fLengthContext; }
+
const SkPaint* fillPaint() const { return fFill.getMaybeNull(); }
const SkPaint* strokePaint() const { return fStroke.getMaybeNull(); }
@@ -29,8 +51,9 @@ private:
SkPaint& ensureFill();
SkPaint& ensureStroke();
- SkTLazy<SkPaint> fFill;
- SkTLazy<SkPaint> fStroke;
+ SkSVGLengthContext fLengthContext;
+ SkTLazy<SkPaint> fFill;
+ SkTLazy<SkPaint> fStroke;
};
#endif // SkSVGRenderContext_DEFINED
diff --git a/experimental/svg/model/SkSVGSVG.cpp b/experimental/svg/model/SkSVGSVG.cpp
index aeccc7082b..42bd280a5e 100644
--- a/experimental/svg/model/SkSVGSVG.cpp
+++ b/experimental/svg/model/SkSVGSVG.cpp
@@ -6,5 +6,49 @@
*/
#include "SkSVGSVG.h"
+#include "SkSVGValue.h"
SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { }
+
+void SkSVGSVG::setX(const SkSVGLength& x) {
+ fX = x;
+}
+
+void SkSVGSVG::setY(const SkSVGLength& y) {
+ fY = y;
+}
+
+void SkSVGSVG::setWidth(const SkSVGLength& w) {
+ fWidth = w;
+}
+
+void SkSVGSVG::setHeight(const SkSVGLength& h) {
+ fHeight = h;
+}
+
+void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
+ switch (attr) {
+ case SkSVGAttribute::kX:
+ if (const auto* x = v.as<SkSVGLengthValue>()) {
+ this->setX(*x);
+ }
+ break;
+ case SkSVGAttribute::kY:
+ if (const auto* y = v.as<SkSVGLengthValue>()) {
+ this->setY(*y);
+ }
+ break;
+ case SkSVGAttribute::kWidth:
+ if (const auto* w = v.as<SkSVGLengthValue>()) {
+ this->setWidth(*w);
+ }
+ break;
+ case SkSVGAttribute::kHeight:
+ if (const auto* h = v.as<SkSVGLengthValue>()) {
+ this->setHeight(*h);
+ }
+ break;
+ default:
+ this->INHERITED::onSetAttribute(attr, v);
+ }
+}
diff --git a/experimental/svg/model/SkSVGSVG.h b/experimental/svg/model/SkSVGSVG.h
index 8e69d144d6..27631f5a31 100644
--- a/experimental/svg/model/SkSVGSVG.h
+++ b/experimental/svg/model/SkSVGSVG.h
@@ -9,6 +9,7 @@
#define SkSVGSVG_DEFINED
#include "SkSVGContainer.h"
+#include "SkSVGTypes.h"
class SkSVGSVG : public SkSVGContainer {
public:
@@ -16,9 +17,22 @@ public:
static sk_sp<SkSVGSVG> Make() { return sk_sp<SkSVGSVG>(new SkSVGSVG()); }
+ void setX(const SkSVGLength&);
+ void setY(const SkSVGLength&);
+ void setWidth(const SkSVGLength&);
+ void setHeight(const SkSVGLength&);
+
+protected:
+ void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
+
private:
SkSVGSVG();
+ SkSVGLength fX = SkSVGLength(0);
+ SkSVGLength fY = SkSVGLength(0);
+ SkSVGLength fWidth = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
+ SkSVGLength fHeight = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
+
typedef SkSVGContainer INHERITED;
};
diff --git a/experimental/svg/model/SkSVGShape.cpp b/experimental/svg/model/SkSVGShape.cpp
new file mode 100644
index 0000000000..d26eff482d
--- /dev/null
+++ b/experimental/svg/model/SkSVGShape.cpp
@@ -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.
+ */
+
+#include "SkSVGRenderContext.h"
+#include "SkSVGShape.h"
+
+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);
+ }
+
+ if (const SkPaint* strokePaint = ctx.strokePaint()) {
+ this->onDraw(canvas, ctx.lengthContext(), *strokePaint);
+ }
+}
+
+void SkSVGShape::appendChild(sk_sp<SkSVGNode>) {
+ SkDebugf("cannot append child nodes to an SVG shape.\n");
+}
diff --git a/experimental/svg/model/SkSVGShape.h b/experimental/svg/model/SkSVGShape.h
new file mode 100644
index 0000000000..2b3ea96d54
--- /dev/null
+++ b/experimental/svg/model/SkSVGShape.h
@@ -0,0 +1,33 @@
+/*
+ * 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 SkSVGShape_DEFINED
+#define SkSVGShape_DEFINED
+
+#include "SkSVGTransformableNode.h"
+
+class SkSVGLengthContext;
+class SkPaint;
+
+class SkSVGShape : public SkSVGTransformableNode {
+public:
+ virtual ~SkSVGShape() = default;
+
+ void appendChild(sk_sp<SkSVGNode>) override;
+
+protected:
+ SkSVGShape(SkSVGTag);
+
+ void onRender(SkCanvas*, const SkSVGRenderContext&) const final;
+
+ virtual void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const = 0;
+
+private:
+ typedef SkSVGTransformableNode INHERITED;
+};
+
+#endif // SkSVGShape_DEFINED
diff --git a/experimental/svg/model/SkSVGTypes.h b/experimental/svg/model/SkSVGTypes.h
new file mode 100644
index 0000000000..6d34d9943a
--- /dev/null
+++ b/experimental/svg/model/SkSVGTypes.h
@@ -0,0 +1,72 @@
+/*
+ * 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 SkSVGTypes_DEFINED
+#define SkSVGTypes_DEFINED
+
+#include "SkColor.h"
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+class SkSVGNumber {
+public:
+ constexpr SkSVGNumber() : fValue(0) {}
+ explicit constexpr SkSVGNumber(SkScalar v) : fValue(v) {}
+ SkSVGNumber(const SkSVGNumber&) = default;
+ SkSVGNumber& operator=(const SkSVGNumber&) = default;
+
+
+ const SkScalar& value() const { return fValue; }
+
+ operator const SkScalar&() const { return fValue; }
+
+private:
+ SkScalar fValue;
+};
+
+class SkSVGLength {
+public:
+ enum class Unit {
+ kUnknown,
+ kNumber,
+ kPercentage,
+ kEMS,
+ kEXS,
+ kPX,
+ kCM,
+ kMM,
+ kIN,
+ kPT,
+ kPC,
+ };
+
+ constexpr SkSVGLength() : fValue(0), fUnit(Unit::kUnknown) {}
+ explicit constexpr SkSVGLength(SkScalar v, Unit u = Unit::kNumber)
+ : fValue(v), fUnit(u) {}
+ SkSVGLength(const SkSVGLength&) = default;
+ SkSVGLength& operator=(const SkSVGLength&) = default;
+
+ const SkScalar& value() const { return fValue; }
+ const Unit& unit() const { return fUnit; }
+
+private:
+ SkScalar fValue;
+ 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
diff --git a/experimental/svg/model/SkSVGValue.cpp b/experimental/svg/model/SkSVGValue.cpp
index 674a200a34..aec49d239f 100644
--- a/experimental/svg/model/SkSVGValue.cpp
+++ b/experimental/svg/model/SkSVGValue.cpp
@@ -5,4 +5,5 @@
* found in the LICENSE file.
*/
+#include "SkSVGTypes.h"
#include "SkSVGValue.h"
diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h
index 3d3cd6efc1..a83c4fe07f 100644
--- a/experimental/svg/model/SkSVGValue.h
+++ b/experimental/svg/model/SkSVGValue.h
@@ -11,14 +11,16 @@
#include "SkColor.h"
#include "SkMatrix.h"
#include "SkPath.h"
+#include "SkSVGTypes.h"
#include "SkTypes.h"
class SkSVGValue : public SkNoncopyable {
public:
enum class Type {
- Color,
- Path,
- Transform,
+ kColor,
+ kLength,
+ kPath,
+ kTransform,
};
Type type() const { return fType; }
@@ -33,6 +35,8 @@ protected:
private:
Type fType;
+
+ typedef SkNoncopyable INHERITED;
};
template <typename SkiaType, SkSVGValue::Type ValueType>
@@ -49,11 +53,12 @@ public:
private:
SkiaType fWrappedValue;
- using INHERITED = SkSVGValue;
+ typedef SkSVGValue INHERITED;
};
-using SkSVGColorValue = SkSVGWrapperValue<SkColor , SkSVGValue::Type::Color >;
-using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::Path >;
-using SkSVGTransformValue = SkSVGWrapperValue<SkMatrix, SkSVGValue::Type::Transform>;
+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>;
#endif // SkSVGValue_DEFINED