-
|
@YGaurora 所以我现在基于现有的 svg 代码,通过遍历 SVGDOM 节点并参考 SVGRenderContext 相关实现代码。 还有就是能否考虑支持下自定义属性,也就是在解析 svg 时,如果不是 svg 标准属性的。都统一收集到一个 KV 中 #include "ConvertSVGLayer.hpp"
#include <tgfx/core/Path.h>
#include <tgfx/core/Rect.h>
#include <tgfx/layers/DisplayList.h>
#include <tgfx/layers/ImageLayer.h>
#include <tgfx/layers/ShapeLayer.h>
#include <tgfx/layers/SolidColor.h>
#include <tgfx/layers/TextLayer.h>
#include <tgfx/svg/SVGDOM.h>
#include <tgfx/svg/node/SVGCircle.h>
#include <tgfx/svg/node/SVGGroup.h>
#include <tgfx/svg/node/SVGPath.h>
#include <tgfx/svg/node/SVGPoly.h>
#include <tgfx/svg/node/SVGRect.h>
#include <tgfx/svg/node/SVGText.h>
namespace kk::svg {
static void applyShapeLayerStyle(tgfx::ShapeLayer *shape, tgfx::SVGNode *node) {
if (auto attribute = node->getFill().get(); attribute) {
if (attribute->type() == tgfx::SVGPaint::Type::Color) {
auto color = attribute->color().color();
shape->addFillStyle(tgfx::SolidColor::Make(color));
}
}
if (auto attribute = node->getStroke().get(); attribute) {
if (attribute->type() == tgfx::SVGPaint::Type::Color) {
auto color = attribute->color().color();
shape->addStrokeStyle(tgfx::SolidColor::Make(color));
}
}
if (auto attribute = node->getStrokeDashArray().get(); attribute) {
std::vector<float> dash{};
for (const auto &item : attribute.value().dashArray()) {
dash.push_back(item.value());
}
shape->setLineDashPattern(dash);
}
if (auto attribute = node->getStrokeDashOffset().get(); attribute) {
shape->setLineDashPhase(attribute.value().value());
}
if (auto attribute = node->getStrokeLineCap().get(); attribute) {
switch (attribute.value()) {
case tgfx::SVGLineCap::Butt:
shape->setLineCap(tgfx::LineCap::Butt);
break;
case tgfx::SVGLineCap::Round:
shape->setLineCap(tgfx::LineCap::Round);
break;
case tgfx::SVGLineCap::Square:
shape->setLineCap(tgfx::LineCap::Square);
break;
default:
break;
}
}
if (auto attribute = node->getStrokeLineJoin().get(); attribute) {
switch (attribute.value().type()) {
case tgfx::SVGLineJoin::Type::Miter:
shape->setLineJoin(tgfx::LineJoin::Miter);
break;
case tgfx::SVGLineJoin::Type::Round:
shape->setLineJoin(tgfx::LineJoin::Round);
break;
case tgfx::SVGLineJoin::Type::Bevel:
shape->setLineJoin(tgfx::LineJoin::Bevel);
break;
default:
break;
}
}
if (auto attribute = node->getStrokeMiterLimit().get(); attribute) {
shape->setMiterLimit(attribute.value());
}
if (auto attribute = node->getStrokeWidth().get(); attribute) {
shape->setLineWidth(attribute.value().value());
}
}
std::shared_ptr<tgfx::Layer> convertSVGDomToLayer(std::shared_ptr<tgfx::SVGDOM> dom) {
if (dom == nullptr) {
return nullptr;
}
auto &rootNode = dom->getRoot();
if (!rootNode->hasChildren()) {
return nullptr;
}
auto containerSize = dom->getContainerSize();
tgfx::Path path;
path.addRect(tgfx::Rect::MakeWH(containerSize.width, containerSize.height));
auto root = tgfx::ShapeLayer::Make();
root->setPath(path);
auto container = tgfx::ShapeLayer::Make();
container->setPath(path);
auto &childrens = rootNode->getChildren();
for (const auto &child : childrens) {
auto layer = convertSVGNodeToLayer(child.get());
if (layer) {
container->addChild(layer);
}
}
root->addChild(container);
auto mask = tgfx::ShapeLayer::Make();
mask->setPath(path);
mask->setFillStyle(tgfx::SolidColor::Make());
root->addChild(mask);
container->setMask(mask);
return root;
}
std::shared_ptr<tgfx::Layer> convertSVGNodeToLayer(tgfx::SVGNode *node) {
auto tag = node->tag();
switch (tag) {
case tgfx::SVGTag::G:
return convertGroup(static_cast<tgfx::SVGGroup *>(node));
case tgfx::SVGTag::Circle:
return convertCircle(static_cast<tgfx::SVGCircle *>(node));
case tgfx::SVGTag::Rect:
return convertRect(static_cast<tgfx::SVGRect *>(node));
case tgfx::SVGTag::Path:
return convertPath(static_cast<tgfx::SVGPath *>(node));
case tgfx::SVGTag::Polygon:
case tgfx::SVGTag::Polyline:
return converPoly(static_cast<tgfx::SVGPoly *>(node));
case tgfx::SVGTag::Text:
return convertText(static_cast<tgfx::SVGText *>(node));
default:
break;
}
return nullptr;
}
std::shared_ptr<tgfx::Layer> convertGroup(tgfx::SVGGroup *node) {
if (!node->hasChildren()) {
return nullptr;
}
auto root = tgfx::Layer::Make();
for (auto const &child : node->getChildren()) {
auto layer = convertSVGNodeToLayer(child.get());
if (layer) {
root->addChild(layer);
}
}
return root;
}
std::shared_ptr<tgfx::ShapeLayer> convertCircle(tgfx::SVGCircle *node) {
return nullptr;
}
std::shared_ptr<tgfx::ShapeLayer> convertPath(tgfx::SVGPath *node) {
auto shape = tgfx::ShapeLayer::Make();
shape->setPath(node->getShapePath());
applyShapeLayerStyle(shape.get(), node);
return shape;
}
std::shared_ptr<tgfx::ShapeLayer> converPoly(tgfx::SVGPoly *node) {
auto points = node->getPoints();
if (points.empty()) {
return nullptr;
}
auto shape = tgfx::ShapeLayer::Make();
tgfx::Path path{};
path.moveTo(points[0]);
for (uint32_t i = 1; i < points.size(); i++) {
path.lineTo(points[i]);
}
path.close();
applyShapeLayerStyle(shape.get(), node);
return shape;
}
std::shared_ptr<tgfx::ShapeLayer> convertRect(tgfx::SVGRect *node) {
auto shape = tgfx::ShapeLayer::Make();
auto x = node->getX().value();
auto y = node->getY().value();
auto width = node->getWidth().value();
auto height = node->getHeight().value();
tgfx::Path rectPath{};
rectPath.addRect(tgfx::Rect::MakeXYWH(x, y, width, height));
shape->setPath(rectPath);
applyShapeLayerStyle(shape.get(), node);
return shape;
}
std::shared_ptr<tgfx::TextLayer> convertText(tgfx::SVGText *node) {
// auto layer = tgfx::TextLayer::Make();
return nullptr;
}
}; // namespace kk::svg
|
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 11 replies
-
|
@0x1306a94 缺少读取文字子节点的接口,确实是遗漏了,会给补充一个接口。 |
Beta Was this translation helpful? Give feedback.
-
|
我们这个月会启动图层高压缩的序列化格式设计,现在还不确定什么时候完成,完成这个之后会提供从SVG到图层序列化格式的转换方法,有可能是运行时接口,也有可能是个离线转换工具。 |
Beta Was this translation helpful? Give feedback.
-
|
@0x1306a94 |
Beta Was this translation helpful? Give feedback.
-
#include "ConvertSVGLayer.hpp"
#include <tgfx/core/Path.h>
#include <tgfx/core/Rect.h>
#include <tgfx/layers/DisplayList.h>
#include <tgfx/layers/ImageLayer.h>
#include <tgfx/layers/ShapeLayer.h>
#include <tgfx/layers/SolidColor.h>
#include <tgfx/layers/TextLayer.h>
#include <tgfx/svg/SVGDOM.h>
#include <tgfx/svg/SVGLengthContext.h>
#include <tgfx/svg/node/SVGCircle.h>
#include <tgfx/svg/node/SVGEllipse.h>
#include <tgfx/svg/node/SVGGroup.h>
#include <tgfx/svg/node/SVGPath.h>
#include <tgfx/svg/node/SVGPoly.h>
#include <tgfx/svg/node/SVGRect.h>
#include <tgfx/svg/node/SVGText.h>
namespace kk::svg {
static void applyShapeLayerStyle(tgfx::ShapeLayer *shape, tgfx::SVGNode *node, const tgfx::SVGLengthContext *lengthContext) {
if (const auto &attribute = node->getFill().get(); attribute && attribute->type() == tgfx::SVGPaint::Type::Color) {
auto color = attribute->color().color();
shape->addFillStyle(tgfx::SolidColor::Make(color));
} else {
shape->addFillStyle(tgfx::SolidColor::Make(tgfx::Color::White()));
}
if (const auto &attribute = node->getStroke().get(); attribute && attribute->type() == tgfx::SVGPaint::Type::Color) {
auto color = attribute->color().color();
shape->addStrokeStyle(tgfx::SolidColor::Make(color));
} else {
shape->addStrokeStyle(tgfx::SolidColor::Make(tgfx::Color::Black()));
}
if (const auto &attribute = node->getStrokeWidth().get(); attribute) {
shape->setLineWidth(attribute.value().value());
}
if (const auto &attribute = node->getStrokeDashArray().get(); attribute) {
std::vector<float> dash{};
for (const auto &item : attribute.value().dashArray()) {
dash.push_back(item.value());
}
shape->setLineDashPattern(dash);
}
if (const auto &attribute = node->getStrokeDashOffset().get(); attribute) {
shape->setLineDashPhase(attribute.value().value());
}
if (const auto &attribute = node->getStrokeLineCap().get(); attribute) {
switch (attribute.value()) {
case tgfx::SVGLineCap::Butt:
shape->setLineCap(tgfx::LineCap::Butt);
break;
case tgfx::SVGLineCap::Round:
shape->setLineCap(tgfx::LineCap::Round);
break;
case tgfx::SVGLineCap::Square:
shape->setLineCap(tgfx::LineCap::Square);
break;
default:
break;
}
}
if (const auto &attribute = node->getStrokeLineJoin().get(); attribute) {
switch (attribute.value().type()) {
case tgfx::SVGLineJoin::Type::Miter:
shape->setLineJoin(tgfx::LineJoin::Miter);
break;
case tgfx::SVGLineJoin::Type::Round:
shape->setLineJoin(tgfx::LineJoin::Round);
break;
case tgfx::SVGLineJoin::Type::Bevel:
shape->setLineJoin(tgfx::LineJoin::Bevel);
break;
default:
break;
}
}
if (const auto &attribute = node->getStrokeMiterLimit().get(); attribute) {
shape->setMiterLimit(attribute.value());
}
}
static std::shared_ptr<tgfx::Typeface> resolveTypeface(const tgfx::SVGText *node, const tgfx::SVGLengthContext *lengthContext) {
using namespace tgfx;
auto weight = [](const SVGFontWeight &w) {
switch (w.type()) {
case SVGFontWeight::Type::W100:
return FontWeight::Thin;
case SVGFontWeight::Type::W200:
return FontWeight::ExtraLight;
case SVGFontWeight::Type::W300:
return FontWeight::Light;
case SVGFontWeight::Type::W400:
return FontWeight::Normal;
case SVGFontWeight::Type::W500:
return FontWeight::Medium;
case SVGFontWeight::Type::W600:
return FontWeight::SemiBold;
case SVGFontWeight::Type::W700:
return FontWeight::Bold;
case SVGFontWeight::Type::W800:
return FontWeight::ExtraBold;
case SVGFontWeight::Type::W900:
return FontWeight::Black;
case SVGFontWeight::Type::Normal:
return FontWeight::Normal;
case SVGFontWeight::Type::Bold:
return FontWeight::Bold;
case SVGFontWeight::Type::Bolder:
return FontWeight::ExtraBold;
case SVGFontWeight::Type::Lighter:
return FontWeight::Light;
case SVGFontWeight::Type::Inherit: {
return FontWeight::Normal;
}
}
};
auto slant = [](const SVGFontStyle &s) {
switch (s.type()) {
case SVGFontStyle::Type::Normal:
return FontSlant::Upright;
case SVGFontStyle::Type::Italic:
return FontSlant::Italic;
case SVGFontStyle::Type::Oblique:
return FontSlant::Oblique;
case SVGFontStyle::Type::Inherit: {
return FontSlant::Upright;
}
}
};
auto fontFamily = node->getFontFamily().get();
if (!fontFamily) {
return nullptr;
}
const auto &family = fontFamily->family();
const auto fontWeight = node->getFontWeight().get().value_or(SVGFontWeight(SVGFontWeight::Type::Normal));
const auto fontStyle = node->getFontStyle().get().value_or(SVGFontStyle(SVGFontStyle::Type::Normal));
const FontStyle style(weight(fontWeight), FontWidth::Normal, slant(fontStyle));
return Typeface::MakeFromName(family, style);
}
static std::vector<float> resolveTextLengths(const tgfx::SVGLengthContext *lengthContext,
const std::vector<tgfx::SVGLength> &lengths,
tgfx::SVGLengthContext::LengthType lengthType,
const tgfx::SVGFontSize &fontSize) {
std::vector<float> resolved;
resolved.reserve(lengths.size());
for (const auto &length : lengths) {
if (length.unit() == tgfx::SVGLength::Unit::EMS || length.unit() == tgfx::SVGLength::Unit::EXS) {
auto resolvedLength =
lengthContext->resolve(fontSize.size(), tgfx::SVGLengthContext::LengthType::Horizontal) *
length.value();
resolved.push_back(resolvedLength);
} else {
resolved.push_back(lengthContext->resolve(length, lengthType));
}
}
return resolved;
}
static void applyTextLayerStyle(tgfx::TextLayer *textLayer, tgfx::SVGText *node, const tgfx::SVGLengthContext *lengthContext) {
if (const auto &attribute = node->getFill().get(); attribute && attribute->type() == tgfx::SVGPaint::Type::Color) {
auto color = attribute->color().color();
textLayer->setTextColor(color);
} else {
textLayer->setTextColor(tgfx::Color::Black());
}
if (const auto &attribute = node->getTextAnchor().get(); attribute) {
auto type = attribute.value().type();
switch (type) {
case tgfx::SVGTextAnchor::Type::Start:
textLayer->setTextAlign(tgfx::TextAlign::Left);
break;
case tgfx::SVGTextAnchor::Type::Middle:
textLayer->setTextAlign(tgfx::TextAlign::Center);
break;
case tgfx::SVGTextAnchor::Type::End:
textLayer->setTextAlign(tgfx::TextAlign::Right);
break;
default:
break;
}
}
}
std::shared_ptr<tgfx::Layer> convertSVGDomToLayer(std::shared_ptr<tgfx::SVGDOM> dom) {
if (dom == nullptr) {
return nullptr;
}
auto &rootNode = dom->getRoot();
if (!rootNode->hasChildren()) {
return nullptr;
}
auto rootWidth = rootNode->getWidth();
auto rootHeight = rootNode->getHeight();
tgfx::SVGLengthContext viewportLengthContext(tgfx::Size::Make(100, 100));
tgfx::Size containerSize{};
if (rootNode->getViewBox().has_value()) {
viewportLengthContext = tgfx::SVGLengthContext(rootNode->getViewBox()->size());
containerSize = tgfx::Size::Make(
viewportLengthContext.resolve(rootWidth, tgfx::SVGLengthContext::LengthType::Horizontal),
viewportLengthContext.resolve(rootHeight, tgfx::SVGLengthContext::LengthType::Vertical));
} else {
containerSize = tgfx::Size::Make(
viewportLengthContext.resolve(rootWidth, tgfx::SVGLengthContext::LengthType::Horizontal),
viewportLengthContext.resolve(rootHeight, tgfx::SVGLengthContext::LengthType::Vertical));
}
tgfx::Path path;
path.addRect(tgfx::Rect::MakeWH(containerSize.width, containerSize.height));
auto root = tgfx::ShapeLayer::Make();
root->setPath(path);
// root->setMatrix(rootNode->getTransform());
auto container = tgfx::ShapeLayer::Make();
container->setPath(path);
auto &childrens = rootNode->getChildren();
for (const auto &child : childrens) {
auto layer = convertSVGNodeToLayer(child.get(), &viewportLengthContext);
if (layer) {
container->addChild(layer);
}
}
root->addChild(container);
auto mask = tgfx::ShapeLayer::Make();
mask->setPath(path);
mask->setFillStyle(tgfx::SolidColor::Make());
root->addChild(mask);
container->setMask(mask);
return root;
}
std::shared_ptr<tgfx::Layer> convertSVGNodeToLayer(tgfx::SVGNode *node, const tgfx::SVGLengthContext *lengthContext) {
auto tag = node->tag();
switch (tag) {
case tgfx::SVGTag::G:
return convertGroup(static_cast<tgfx::SVGGroup *>(node), lengthContext);
case tgfx::SVGTag::Circle:
return convertCircle(static_cast<tgfx::SVGCircle *>(node), lengthContext);
case tgfx::SVGTag::Ellipse:
return convertEllipse(static_cast<tgfx::SVGEllipse *>(node), lengthContext);
case tgfx::SVGTag::Rect:
return convertRect(static_cast<tgfx::SVGRect *>(node), lengthContext);
case tgfx::SVGTag::Path:
return convertPath(static_cast<tgfx::SVGPath *>(node), lengthContext);
case tgfx::SVGTag::Polygon:
case tgfx::SVGTag::Polyline:
return converPoly(static_cast<tgfx::SVGPoly *>(node), lengthContext);
case tgfx::SVGTag::Text:
return convertText(static_cast<tgfx::SVGText *>(node), lengthContext);
default:
break;
}
return nullptr;
}
std::shared_ptr<tgfx::Layer> convertGroup(tgfx::SVGGroup *node, const tgfx::SVGLengthContext *lengthContext) {
if (!node->hasChildren()) {
return nullptr;
}
auto root = tgfx::Layer::Make();
for (auto const &child : node->getChildren()) {
auto layer = convertSVGNodeToLayer(child.get(), lengthContext);
if (layer) {
root->addChild(layer);
}
}
return root;
}
std::shared_ptr<tgfx::ShapeLayer> convertCircle(tgfx::SVGCircle *node, const tgfx::SVGLengthContext *lengthContext) {
const auto cx = lengthContext->resolve(node->getCx(), tgfx::SVGLengthContext::LengthType::Horizontal);
const auto cy = lengthContext->resolve(node->getCy(), tgfx::SVGLengthContext::LengthType::Vertical);
const auto r = lengthContext->resolve(node->getR(), tgfx::SVGLengthContext::LengthType::Other);
tgfx::Path path;
path.addOval(tgfx::Rect::MakeXYWH(cx - r, cy - r, 2 * r, 2 * r));
path.transform(node->getTransform());
auto shape = tgfx::ShapeLayer::Make();
shape->setPath(path);
applyShapeLayerStyle(shape.get(), node, lengthContext);
return shape;
}
std::shared_ptr<tgfx::ShapeLayer> convertEllipse(tgfx::SVGEllipse *node, const tgfx::SVGLengthContext *lengthContext) {
const auto cx = lengthContext->resolve(node->getCx(), tgfx::SVGLengthContext::LengthType::Horizontal);
const auto cy = lengthContext->resolve(node->getCy(), tgfx::SVGLengthContext::LengthType::Vertical);
const auto [rx, ry] = lengthContext->resolveOptionalRadii(node->getRx(), node->getRy());
if (rx <= 0 || ry <= 0) {
return nullptr;
}
tgfx::Path path{};
path.addOval(tgfx::Rect::MakeXYWH(cx - rx, cy - ry, rx * 2, ry * 2));
path.transform(node->getTransform());
auto shape = tgfx::ShapeLayer::Make();
shape->setPath(path);
applyShapeLayerStyle(shape.get(), node, lengthContext);
return shape;
}
std::shared_ptr<tgfx::ShapeLayer> convertPath(tgfx::SVGPath *node, const tgfx::SVGLengthContext *lengthContext) {
auto shape = tgfx::ShapeLayer::Make();
shape->setPath(node->getShapePath());
shape->setMatrix(node->getTransform());
applyShapeLayerStyle(shape.get(), node, lengthContext);
return shape;
}
std::shared_ptr<tgfx::ShapeLayer> converPoly(tgfx::SVGPoly *node, const tgfx::SVGLengthContext *lengthContext) {
auto points = node->getPoints();
if (points.empty()) {
return nullptr;
}
auto shape = tgfx::ShapeLayer::Make();
tgfx::Path path{};
path.moveTo(points[0]);
for (uint32_t i = 1; i < points.size(); i++) {
path.lineTo(points[i]);
}
path.close();
path.transform(node->getTransform());
shape->setPath(path);
applyShapeLayerStyle(shape.get(), node, lengthContext);
return shape;
}
std::shared_ptr<tgfx::ShapeLayer> convertRect(tgfx::SVGRect *node, const tgfx::SVGLengthContext *lengthContext) {
auto shape = tgfx::ShapeLayer::Make();
const auto rect = lengthContext->resolveRect(node->getX(), node->getY(), node->getWidth(), node->getHeight());
const auto [rx, ry] = lengthContext->resolveOptionalRadii(node->getRx(), node->getRy());
tgfx::RRect rrect;
rrect.setRectXY(rect, std::min(rx, rect.width() / 2), std::min(ry, rect.height() / 2));
tgfx::Path path{};
path.addRRect(rrect);
path.transform(node->getTransform());
shape->setPath(path);
applyShapeLayerStyle(shape.get(), node, lengthContext);
return shape;
}
std::shared_ptr<tgfx::TextLayer> convertText(tgfx::SVGText *node, const tgfx::SVGLengthContext *lengthContext) {
// 暂时只支持单个文本节点
std::shared_ptr<tgfx::SVGTextLiteral> literal = nullptr;
for (const auto &child : node->getTextChildren()) {
if (child->tag() == tgfx::SVGTag::TextLiteral) {
literal = std::static_pointer_cast<tgfx::SVGTextLiteral>(child);
break;
}
}
if (literal == nullptr) {
return nullptr;
}
auto text = literal->getText();
if (text.empty()) {
return nullptr;
}
auto typeface = resolveTypeface(node, lengthContext);
auto fontSize = tgfx::SVGFontSize(tgfx::SVGLength(10.0f, tgfx::SVGLength::Unit::PT));
if (auto attribute = node->getFontSize().get(); attribute) {
fontSize = attribute.value();
}
auto x = resolveTextLengths(lengthContext, node->getX(), tgfx::SVGLengthContext::LengthType::Horizontal, fontSize);
auto y = resolveTextLengths(lengthContext, node->getY(), tgfx::SVGLengthContext::LengthType::Vertical, fontSize);
auto dx = resolveTextLengths(lengthContext, node->getDx(), tgfx::SVGLengthContext::LengthType::Horizontal, fontSize);
auto dy = resolveTextLengths(lengthContext, node->getDy(), tgfx::SVGLengthContext::LengthType::Vertical, fontSize);
if (x.empty() || y.empty()) {
return nullptr;
}
auto finalFontSize = lengthContext->resolve(fontSize.size(), tgfx::SVGLengthContext::LengthType::Vertical);
tgfx::Font font(typeface, finalFontSize);
auto offsetX = x[0] + (dx.empty() ? 0.0f : dx[0]);
auto offsetY = y[0] + (dy.empty() ? 0.0f : dy[0]);
// auto textBlob = tgfx::TextBlob::MakeFrom(text, font);
// if (textBlob == nullptr) {
// return nullptr;
// }
//
// auto bound = textBlob->getTightBounds();
//
// if (const auto &attribute = node->getTextAnchor().get(); attribute) {
// const auto alignmentFactor = attribute->getAlignmentFactor();
// offsetX = offsetX + alignmentFactor * bound.width();
// }
auto matrix = tgfx::Matrix::MakeTrans(offsetX, offsetY);
matrix.postConcat(node->getTransform());
auto layer = tgfx::TextLayer::Make();
layer->setFont(font);
layer->setMatrix(matrix);
layer->setText(text);
applyTextLayerStyle(layer.get(), node, lengthContext);
return layer;
}
}; // namespace kk::svg |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
@YGaurora 再请教下,使用 TextShaper 创建 TextBlob 后按照 SVGText 里面的修正了水平方向对齐 或许我应该自定义一个 Layer 直接渲染 TextShaper 创建的 TextBlob ?
|
Beta Was this translation helpful? Give feedback.





@0x1306a94
修改已合入主分支 c73fb3b
在SVGTextContainer新增了getTextChildren(),获取子文字节点
在SVGNode新增了getUnparsedAttributes(),和渲染SVG不相关的属性、不属于SVG规范的属性都不会转换进入node,会存在这个接口的对象中。