thorvg/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp
Hermet Park ef4d7a3956 common shape: expand rectangle arguement to support both corner radius x, y
this is useful for svg loader

Change-Id: Ia11c2d1c6ea88f3fd65c7f75cef8b59bef426bcb
2020-07-07 13:09:46 +09:00

216 lines
7.1 KiB
C++

/*
* Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef _TVG_SVG_SCENE_BUILDER_CPP_
#define _TVG_SVG_SCENE_BUILDER_CPP_
#include "tvgSvgSceneBuilder.h"
static void _getTransformationData(Matrix* m, float* tx, float* ty, float* s, float* z)
{
float rz, si, cs, zcs, zsi;
*tx = m->e13;
*ty = m->e23;
cs = m->e11;
si = m->e12;
rz = atan2(si, cs);
*z = rz * (180.0 / M_PI);
zcs = cosf(rz);
zsi = sinf(rz);
m->e11 = m->e11 * zcs + m->e12 * zsi;
m->e22 = m->e21 * (-1 * zsi) + m->e22 * zcs;
*s = m->e11 > m->e22 ? m->e11 : m->e22;
}
unique_ptr<tvg::Shape> _applyProperty(SvgNode* node, unique_ptr<tvg::Shape> vg)
{
SvgStyleProperty* style = node->style;
//Apply the transformation
if (node->transform) {
float tx = 0, ty = 0, s = 0, z = 0;
_getTransformationData(node->transform, &tx, &ty, &s, &z);
vg->scale(s);
vg->rotate(z);
vg->translate(tx, ty);
}
if (node->type == SvgNodeType::Doc) return vg;
//If fill property is nullptr then do nothing
if (style->fill.paint.none) {
//Do nothing
} else if (style->fill.paint.gradient) {
//TODO: Support gradient style
} else if (style->fill.paint.curColor) {
//Apply the current style color
float fa = ((float)style->fill.opacity / 255.0);
vg->fill(((float)style->r) * fa, ((float)style->g) * fa, ((float)style->b) * fa, style->fill.opacity);
} else {
//Apply the fill color
float fa = ((float)style->fill.opacity / 255.0);
vg->fill(((float)style->fill.paint.r) * fa, ((float)style->fill.paint.g) * fa, ((float)style->fill.paint.b) * fa, style->fill.opacity);
}
//Apply node opacity
if (style->opacity < 255) {
uint8_t r, g, b, a;
vg->fill(&r, &g, &b, &a);
float fa = ((float)style->opacity / 255.0);
vg->fill(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa);
}
if (node->type == SvgNodeType::G) return vg;
//Apply the stroke style property
vg->stroke(style->stroke.width);
vg->stroke(style->stroke.cap);
vg->stroke(style->stroke.join);
//If stroke property is nullptr then do nothing
if (style->stroke.paint.none) {
//Do nothing
} else if (style->stroke.paint.gradient) {
//TODO: Support gradient style
} else if (style->stroke.paint.url) {
//TODO: Apply the color pointed by url
} else if (style->stroke.paint.curColor) {
//Apply the current style color
vg->stroke(style->r, style->g, style->b, style->stroke.opacity);
} else {
//Apply the stroke color
vg->stroke(style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b, style->stroke.opacity);
}
//Apply node opacity to stroke color
if (style->opacity < 255) {
uint8_t r, g, b, a;
vg->strokeColor(&r, &g, &b, &a);
float fa = ((float)style->opacity / 255.0);
vg->stroke(((float)r) * fa, ((float)g) * fa, ((float)b) * fa, ((float)a) * fa);
}
return vg;
}
unique_ptr<tvg::Shape> _shapeBuildHelper(SvgNode* node)
{
auto shape = tvg::Shape::gen();
switch (node->type) {
case SvgNodeType::Path: {
if (node->node.path.path) {
auto pathResult = svgPathToTvgPath(node->node.path.path->c_str());
shape->appendPath(get<0>(pathResult).data(), get<0>(pathResult).size(), get<1>(pathResult).data(), get<1>(pathResult).size());
}
break;
}
case SvgNodeType::Ellipse: {
shape->appendCircle(node->node.ellipse.cx, node->node.ellipse.cy, node->node.ellipse.rx, node->node.ellipse.ry);
break;
}
case SvgNodeType::Polygon: {
if (node->node.polygon.pointsCount < 2) break;
shape->moveTo(node->node.polygon.points[0], node->node.polygon.points[1]);
for (int i = 2; i < node->node.polygon.pointsCount; i += 2) {
shape->lineTo(node->node.polygon.points[i], node->node.polygon.points[i + 1]);
}
shape->close();
break;
}
case SvgNodeType::Polyline: {
if (node->node.polygon.pointsCount < 2) break;
shape->moveTo(node->node.polygon.points[0], node->node.polygon.points[1]);
for (int i = 2; i < node->node.polygon.pointsCount; i += 2) {
shape->lineTo(node->node.polygon.points[i], node->node.polygon.points[i + 1]);
}
break;
}
case SvgNodeType::Circle: {
shape->appendCircle(node->node.circle.cx, node->node.circle.cy, node->node.circle.r, node->node.circle.r);
break;
}
case SvgNodeType::Rect: {
shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx, node->node.rect.ry);
break;
}
case SvgNodeType::Line: {
shape->moveTo(node->node.line.x1, node->node.line.y1);
shape->lineTo(node->node.line.x2, node->node.line.y2);
break;
}
default: {
break;
}
}
shape = move(_applyProperty(node, move(shape)));
return shape;
}
unique_ptr<tvg::Scene> _sceneBuildHelper(SvgNode* node)
{
if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) {
auto scene = tvg::Scene::gen();
if (node->transform) {
float tx = 0, ty = 0, s = 0, z = 0;
_getTransformationData(node->transform, &tx, &ty, &s, &z);
scene->scale(s);
scene->rotate(z);
scene->translate(tx, ty);
}
for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) {
SvgNode* child = *itrChild;
if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild));
else scene->push(_shapeBuildHelper(*itrChild));
}
return move(scene);
}
return nullptr;
}
SvgSceneBuilder::SvgSceneBuilder()
{
}
SvgSceneBuilder::~SvgSceneBuilder()
{
}
unique_ptr<Scene> SvgSceneBuilder::build(SvgNode* node)
{
if (!node || (node->type != SvgNodeType::Doc)) return nullptr;
viewBox.x = node->node.doc.vx;
viewBox.y = node->node.doc.vy;
viewBox.w = node->node.doc.vw;
viewBox.h = node->node.doc.vh;
preserveAspect = node->node.doc.preserveAspect;
staticViewBox = true;
return _sceneBuildHelper(node);
}
#endif //_TVG_SVG_SCENE_BUILDER_CPP_