[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
This commit is contained in:
fmalita 2016-08-03 10:21:11 -07:00 committed by Commit bot
parent 9e3d3d8b36
commit bffc256687
21 changed files with 674 additions and 78 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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&);

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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()) {

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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");
}

View File

@ -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

View File

@ -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

View File

@ -5,4 +5,5 @@
* found in the LICENSE file.
*/
#include "SkSVGTypes.h"
#include "SkSVGValue.h"

View File

@ -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

View File

@ -46,6 +46,8 @@
'sources': [
'../experimental/svg/model/SkSVGAttribute.h',
'../experimental/svg/model/SkSVGAttribute.cpp',
'../experimental/svg/model/SkSVGAttributeParser.h',
'../experimental/svg/model/SkSVGAttributeParser.cpp',
'../experimental/svg/model/SkSVGContainer.h',
'../experimental/svg/model/SkSVGContainer.cpp',
'../experimental/svg/model/SkSVGDOM.h',
@ -55,12 +57,17 @@
'../experimental/svg/model/SkSVGNode.cpp',
'../experimental/svg/model/SkSVGPath.h',
'../experimental/svg/model/SkSVGPath.cpp',
'../experimental/svg/model/SkSVGRect.h',
'../experimental/svg/model/SkSVGRect.cpp',
'../experimental/svg/model/SkSVGRenderContext.h',
'../experimental/svg/model/SkSVGRenderContext.cpp',
'../experimental/svg/model/SkSVGShape.h',
'../experimental/svg/model/SkSVGShape.cpp',
'../experimental/svg/model/SkSVGSVG.h',
'../experimental/svg/model/SkSVGSVG.cpp',
'../experimental/svg/model/SkSVGTransformableNode.h',
'../experimental/svg/model/SkSVGTransformableNode.cpp',
'../experimental/svg/model/SkSVGTypes.h',
'../experimental/svg/model/SkSVGValue.h',
'../experimental/svg/model/SkSVGValue.cpp',
],