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
This commit is contained in:
parent
fc49d56feb
commit
6ceef3dd67
34
experimental/svg/model/SkSVGAttribute.cpp
Normal file
34
experimental/svg/model/SkSVGAttribute.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
41
experimental/svg/model/SkSVGAttribute.h
Normal file
41
experimental/svg/model/SkSVGAttribute.h
Normal file
@ -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
|
21
experimental/svg/model/SkSVGContainer.cpp
Normal file
21
experimental/svg/model/SkSVGContainer.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
31
experimental/svg/model/SkSVGContainer.h
Normal file
31
experimental/svg/model/SkSVGContainer.h
Normal file
@ -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
|
244
experimental/svg/model/SkSVGDOM.cpp
Normal file
244
experimental/svg/model/SkSVGDOM.cpp
Normal file
@ -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;
|
||||
}
|
39
experimental/svg/model/SkSVGDOM.h
Normal file
39
experimental/svg/model/SkSVGDOM.h
Normal file
@ -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
|
25
experimental/svg/model/SkSVGG.h
Normal file
25
experimental/svg/model/SkSVGG.h
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.
|
||||
*/
|
||||
|
||||
#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
|
60
experimental/svg/model/SkSVGNode.cpp
Normal file
60
experimental/svg/model/SkSVGNode.cpp
Normal file
@ -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();
|
||||
}
|
56
experimental/svg/model/SkSVGNode.h
Normal file
56
experimental/svg/model/SkSVGNode.h
Normal file
@ -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
|
37
experimental/svg/model/SkSVGPath.cpp
Normal file
37
experimental/svg/model/SkSVGPath.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
38
experimental/svg/model/SkSVGPath.h
Normal file
38
experimental/svg/model/SkSVGPath.h
Normal file
@ -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
|
52
experimental/svg/model/SkSVGRenderContext.cpp
Normal file
52
experimental/svg/model/SkSVGRenderContext.cpp
Normal file
@ -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);
|
||||
}
|
36
experimental/svg/model/SkSVGRenderContext.h
Normal file
36
experimental/svg/model/SkSVGRenderContext.h
Normal file
@ -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
|
10
experimental/svg/model/SkSVGSVG.cpp
Normal file
10
experimental/svg/model/SkSVGSVG.cpp
Normal file
@ -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) { }
|
25
experimental/svg/model/SkSVGSVG.h
Normal file
25
experimental/svg/model/SkSVGSVG.h
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.
|
||||
*/
|
||||
|
||||
#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
|
26
experimental/svg/model/SkSVGTransformableNode.cpp
Normal file
26
experimental/svg/model/SkSVGTransformableNode.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
34
experimental/svg/model/SkSVGTransformableNode.h
Normal file
34
experimental/svg/model/SkSVGTransformableNode.h
Normal file
@ -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
|
8
experimental/svg/model/SkSVGValue.cpp
Normal file
8
experimental/svg/model/SkSVGValue.cpp
Normal file
@ -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"
|
59
experimental/svg/model/SkSVGValue.h
Normal file
59
experimental/svg/model/SkSVGValue.h
Normal file
@ -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
|
@ -94,6 +94,7 @@
|
||||
'../samplecode/SampleStringArt.cpp',
|
||||
'../samplecode/SampleStrokePath.cpp',
|
||||
'../samplecode/SampleSubpixelTranslate.cpp',
|
||||
'../samplecode/SampleSVGFile.cpp',
|
||||
'../samplecode/SampleText.cpp',
|
||||
'../samplecode/SampleTextAlpha.cpp',
|
||||
'../samplecode/SampleTextBox.cpp',
|
||||
@ -135,6 +136,7 @@
|
||||
'experimental.gyp:experimental',
|
||||
'lua.gyp:lua',
|
||||
'pdf.gyp:pdf',
|
||||
'svg.gyp:svgdom',
|
||||
'views.gyp:views',
|
||||
'xml.gyp:xml',
|
||||
],
|
||||
|
40
gyp/svg.gyp
40
gyp/svg.gyp
@ -31,5 +31,45 @@
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
'target_name': 'svgdom',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library': 1,
|
||||
'dependencies': [
|
||||
'skia_lib.gyp:skia_lib',
|
||||
'xml.gyp:xml',
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(skia_include_path)/private',
|
||||
'../experimental/svg/model',
|
||||
],
|
||||
'sources': [
|
||||
'../experimental/svg/model/SkSVGAttribute.h',
|
||||
'../experimental/svg/model/SkSVGAttribute.cpp',
|
||||
'../experimental/svg/model/SkSVGContainer.h',
|
||||
'../experimental/svg/model/SkSVGContainer.cpp',
|
||||
'../experimental/svg/model/SkSVGDOM.h',
|
||||
'../experimental/svg/model/SkSVGDOM.cpp',
|
||||
'../experimental/svg/model/SkSVGG.h',
|
||||
'../experimental/svg/model/SkSVGNode.h',
|
||||
'../experimental/svg/model/SkSVGNode.cpp',
|
||||
'../experimental/svg/model/SkSVGPath.h',
|
||||
'../experimental/svg/model/SkSVGPath.cpp',
|
||||
'../experimental/svg/model/SkSVGRenderContext.h',
|
||||
'../experimental/svg/model/SkSVGRenderContext.cpp',
|
||||
'../experimental/svg/model/SkSVGSVG.h',
|
||||
'../experimental/svg/model/SkSVGSVG.cpp',
|
||||
'../experimental/svg/model/SkSVGTransformableNode.h',
|
||||
'../experimental/svg/model/SkSVGTransformableNode.cpp',
|
||||
'../experimental/svg/model/SkSVGValue.h',
|
||||
'../experimental/svg/model/SkSVGValue.cpp',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'../experimental/svg/model',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
],
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
|
||||
class AttrIter {
|
||||
public:
|
||||
AttrIter(const class SkDOM&, const Node*);
|
||||
AttrIter(const SkDOM&, const Node*);
|
||||
const char* next(const char** value);
|
||||
private:
|
||||
const Attr* fAttr;
|
||||
|
@ -73,10 +73,10 @@ protected:
|
||||
|
||||
public:
|
||||
// public for ported implementation, not meant for clients to call
|
||||
virtual bool startElement(const char elem[]);
|
||||
virtual bool addAttribute(const char name[], const char value[]);
|
||||
virtual bool endElement(const char elem[]);
|
||||
virtual bool text(const char text[], int len);
|
||||
bool startElement(const char elem[]);
|
||||
bool addAttribute(const char name[], const char value[]);
|
||||
bool endElement(const char elem[]);
|
||||
bool text(const char text[], int len);
|
||||
void* fParser;
|
||||
protected:
|
||||
SkXMLParserError* fError;
|
||||
|
@ -80,6 +80,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
extern SampleView* CreateSampleSVGFileView(const char filename[]);
|
||||
|
||||
class SVGFileFactory : public SkViewFactory {
|
||||
SkString fFilename;
|
||||
public:
|
||||
SVGFileFactory(const SkString& filename) : fFilename(filename) {}
|
||||
SkView* operator() () const override {
|
||||
return CreateSampleSVGFileView(fFilename.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef SAMPLE_PDF_FILE_VIEWER
|
||||
extern SampleView* CreateSamplePdfFileViewer(const char filename[]);
|
||||
|
||||
@ -678,6 +689,8 @@ DEFINE_int32(msaa, 0, "Request multisampling with this count.");
|
||||
DEFINE_bool(deepColor, false, "Request deep color (10-bit/channel or more) display buffer.");
|
||||
DEFINE_string(pictureDir, "", "Read pictures from here.");
|
||||
DEFINE_string(picture, "", "Path to single picture.");
|
||||
DEFINE_string(svg, "", "Path to single SVG file.");
|
||||
DEFINE_string(svgDir, "", "Read SVGs from here.");
|
||||
DEFINE_string(sequence, "", "Path to file containing the desired samples/gms to show.");
|
||||
DEFINE_bool(sort, false, "Sort samples by title.");
|
||||
DEFINE_bool(list, false, "List samples?");
|
||||
@ -711,6 +724,19 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
|
||||
fCurrIndex = fSamples.count();
|
||||
*fSamples.append() = new PictFileFactory(path);
|
||||
}
|
||||
if (!FLAGS_svg.isEmpty()) {
|
||||
SkString path(FLAGS_svg[0]);
|
||||
fCurrIndex = fSamples.count();
|
||||
*fSamples.append() = new SVGFileFactory(path);
|
||||
}
|
||||
if (!FLAGS_svgDir.isEmpty()) {
|
||||
SkOSFile::Iter iter(FLAGS_svgDir[0], "svg");
|
||||
SkString filename;
|
||||
while (iter.next(&filename)) {
|
||||
*fSamples.append() = new SVGFileFactory(
|
||||
SkOSPath::Join(FLAGS_svgDir[0], filename.c_str()));
|
||||
}
|
||||
}
|
||||
#ifdef SAMPLE_PDF_FILE_VIEWER
|
||||
if (!FLAGS_pdfPath.isEmpty()) {
|
||||
SkOSFile::Iter iter(FLAGS_pdfPath[0], "pdf");
|
||||
|
63
samplecode/SampleSVGFile.cpp
Normal file
63
samplecode/SampleSVGFile.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 "SampleCode.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDOM.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkSVGDOM.h"
|
||||
#include "SkView.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class SVGFileView : public SampleView {
|
||||
public:
|
||||
SVGFileView(const char path[]) {
|
||||
SkFILEStream svgStream(path);
|
||||
if (!svgStream.isValid()) {
|
||||
SkDebugf("file not found: \"path\"\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
SkDOM xmlDom;
|
||||
if (!xmlDom.build(svgStream)) {
|
||||
SkDebugf("XML parsing failed: \"path\"\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
fDom = SkSVGDOM::MakeFromDOM(xmlDom, SkSize::Make(this->width(), this->height()));
|
||||
}
|
||||
|
||||
virtual ~SVGFileView() = default;
|
||||
|
||||
protected:
|
||||
void onDrawContent(SkCanvas* canvas) override {
|
||||
if (fDom) {
|
||||
fDom->render(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
void onSizeChange() override {
|
||||
if (fDom) {
|
||||
fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
|
||||
}
|
||||
|
||||
this->INHERITED::onSizeChange();
|
||||
}
|
||||
|
||||
private:
|
||||
sk_sp<SkSVGDOM> fDom;
|
||||
|
||||
typedef SampleView INHERITED;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SampleView* CreateSampleSVGFileView(const char filename[]);
|
||||
SampleView* CreateSampleSVGFileView(const char filename[]) {
|
||||
return new SVGFileView(filename);
|
||||
}
|
Loading…
Reference in New Issue
Block a user