[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:
parent
9e3d3d8b36
commit
bffc256687
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
194
experimental/svg/model/SkSVGAttributeParser.cpp
Normal file
194
experimental/svg/model/SkSVGAttributeParser.cpp
Normal 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;
|
||||
}
|
45
experimental/svg/model/SkSVGAttributeParser.h
Normal file
45
experimental/svg/model/SkSVGAttributeParser.h
Normal 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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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&);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
68
experimental/svg/model/SkSVGRect.cpp
Normal file
68
experimental/svg/model/SkSVGRect.cpp
Normal 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);
|
||||
}
|
40
experimental/svg/model/SkSVGRect.h
Normal file
40
experimental/svg/model/SkSVGRect.h
Normal 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
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
25
experimental/svg/model/SkSVGShape.cpp
Normal file
25
experimental/svg/model/SkSVGShape.cpp
Normal 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");
|
||||
}
|
33
experimental/svg/model/SkSVGShape.h
Normal file
33
experimental/svg/model/SkSVGShape.h
Normal 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
|
72
experimental/svg/model/SkSVGTypes.h
Normal file
72
experimental/svg/model/SkSVGTypes.h
Normal 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
|
@ -5,4 +5,5 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkSVGTypes.h"
|
||||
#include "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
|
||||
|
@ -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',
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user