Merge "SvgLoader: Support to linear, radial gradient" into tizen

This commit is contained in:
Hermet Park 2020-07-10 00:19:51 +00:00 committed by Gerrit Code Review
commit 22581040f3
5 changed files with 279 additions and 50 deletions

View file

@ -1365,11 +1365,18 @@ static SvgNode* _findChildById(SvgNode* node, const char* id)
}
static vector<SvgGradientStop*> _cloneGradStops(vector<SvgGradientStop*> src)
static void _cloneGradStops(vector<Fill::ColorStop*> *dst, vector<Fill::ColorStop*> src)
{
vector<SvgGradientStop*> dst;
copy(src.begin(), src.end(), dst.begin());
return dst;
for(vector<Fill::ColorStop*>::iterator itrStop = src.begin(); itrStop != src.end(); itrStop++) {
Fill::ColorStop *stop = (Fill::ColorStop *)malloc(sizeof(Fill::ColorStop));
stop->r = (*itrStop)->r;
stop->g = (*itrStop)->g;
stop->b = (*itrStop)->b;
stop->a = (*itrStop)->a;
stop->offset = (*itrStop)->offset;
dst->push_back(stop);
}
}
@ -1381,8 +1388,8 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
grad = (SvgStyleGradient*)calloc(1, sizeof(SvgStyleGradient));
grad->type = from->type;
grad->id = _copyId(from->id->c_str());
grad->ref = _copyId(from->ref->c_str());
grad->id = from->id ? _copyId(from->id->c_str()) : nullptr;
grad->ref = from->ref ? _copyId(from->ref->c_str()) : nullptr;
grad->spread = from->spread;
grad->usePercentage = from->usePercentage;
grad->userSpace = from->userSpace;
@ -1390,7 +1397,6 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
grad->transform = (Matrix*)calloc(1, sizeof(Matrix));
memcpy(grad->transform, from->transform, sizeof(Matrix));
}
grad->stops = _cloneGradStops(from->stops);
if (grad->type == SvgGradientType::Linear) {
grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
memcpy(grad->linear, from->linear, sizeof(SvgLinearGradient));
@ -1399,6 +1405,7 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient));
}
_cloneGradStops(&(grad->stops), from->stops);
return grad;
}
@ -1562,14 +1569,14 @@ FIND_FACTORY(Group, groupTags);
FIND_FACTORY(Graphics, graphicsTags);
SvgGradientSpread _parseSpreadValue(const char* value)
FillSpread _parseSpreadValue(const char* value)
{
SvgGradientSpread spread = SvgGradientSpread::Pad;
FillSpread spread = FillSpread::Pad;
if (!strcmp(value, "reflect")) {
spread = SvgGradientSpread::Reflect;
spread = FillSpread::Reflect;
} else if (!strcmp(value, "repeat")) {
spread = SvgGradientSpread::Repeat;
spread = FillSpread::Repeat;
}
return spread;
@ -1730,7 +1737,7 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char
static bool _attrParseStops(void* data, const char* key, const char* value)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
SvgGradientStop* stop = loader->svgParse->gradStop;
Fill::ColorStop* stop = loader->svgParse->gradStop;
if (!strcmp(key, "offset")) {
stop->offset = _toOffset(value);
@ -2008,7 +2015,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
}
loader->latestGradient = gradient;
} else if (!strcmp(tagName, "stop")) {
SvgGradientStop* stop = (SvgGradientStop*)calloc(1, sizeof(SvgGradientStop));
Fill::ColorStop* stop = (Fill::ColorStop*)calloc(1, sizeof(Fill::ColorStop));
loader->svgParse->gradStop = stop;
/* default value for opacity */
stop->a = 255;
@ -2067,7 +2074,7 @@ static void _styleInherit(SvgStyleProperty* child, SvgStyleProperty* parent)
child->fill.paint.b = parent->fill.paint.b;
child->fill.paint.none = parent->fill.paint.none;
child->fill.paint.curColor = parent->fill.paint.curColor;
child->fill.paint.url = parent->fill.paint.url ? _copyId(parent->fill.paint.url->c_str()) : nullptr;
if (parent->fill.paint.url) child->fill.paint.url = _copyId(parent->fill.paint.url->c_str());
}
if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) {
child->fill.opacity = parent->fill.opacity;
@ -2109,12 +2116,12 @@ static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle)
}
static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, const char* id)
static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, string* id)
{
SvgStyleGradient* result = nullptr;
for (vector<SvgStyleGradient*>::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) {
if ((*itrGrad)->id->compare(string(id))) {
if (!((*itrGrad)->id->compare(*id))) {
result = _cloneGradient(*itrGrad);
break;
}
@ -2122,9 +2129,9 @@ static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, const
if (result && result->ref) {
for (vector<SvgStyleGradient*>::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) {
if ((*itrGrad)->id->compare(*result->ref)) {
if (!((*itrGrad)->id->compare(*result->ref))) {
if (!result->stops.empty()) {
result->stops = _cloneGradStops((*itrGrad)->stops);
_cloneGradStops(&(result->stops), (*itrGrad)->stops);
}
//TODO: Properly inherit other property
break;
@ -2138,15 +2145,15 @@ static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, const
static void _updateGradient(SvgNode* node, vector<SvgStyleGradient*> gradList)
{
if (node->child.empty()) {
if (!node->child.empty()) {
for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) {
_updateGradient(*itrChild, gradList);
}
} else {
if (node->style->fill.paint.url) {
node->style->fill.paint.gradient = _gradientDup(gradList, node->style->fill.paint.url->c_str());
node->style->fill.paint.gradient = _gradientDup(gradList, node->style->fill.paint.url);
} else if (node->style->stroke.paint.url) {
node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url->c_str());
//node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url);
}
}
}
@ -2161,7 +2168,7 @@ static void _freeGradientStyle(SvgStyleGradient* grad)
free(grad->linear);
if (grad->transform) free(grad->transform);
for(vector<SvgGradientStop*>::iterator itrStop = grad->stops.begin(); itrStop != grad->stops.end(); itrStop++) {
for(vector<Fill::ColorStop*>::iterator itrStop = grad->stops.begin(); itrStop != grad->stops.end(); itrStop++) {
free(*itrStop);
}
free(grad);
@ -2284,7 +2291,9 @@ bool SvgLoader::read()
else {
if (!loader->loaderData.gradients.empty()) {
vector<SvgStyleGradient*> gradientList;
std::copy(loader->loaderData.gradients.begin(), loader->loaderData.gradients.end(), gradientList.begin());
for(vector<SvgStyleGradient*>::iterator itrGrad = loader->loaderData.gradients.begin(); itrGrad != loader->loaderData.gradients.end(); itrGrad++) {
gradientList.push_back(*itrGrad);
}
_updateGradient(loader->loaderData.doc, gradientList);
gradientList.clear();
}

View file

@ -97,14 +97,6 @@ enum class SvgStyleType
CompOp
};
enum class SvgGradientSpread
{
Pad = 0,
Reflect,
Repeat,
Last
};
enum class SvgFillRule
{
Winding = 0,
@ -221,7 +213,7 @@ struct SvgGradientStop
struct SvgPaint
{
SvgStyleGradient* gradient;
string* url;
string *url;
uint8_t r;
uint8_t g;
uint8_t b;
@ -238,13 +230,13 @@ struct SvgDash
struct _SvgStyleGradient
{
SvgGradientType type;
string* id;
string* ref;
SvgGradientSpread spread;
vector<SvgGradientStop *> stops;
string *id;
string *ref;
FillSpread spread;
SvgRadialGradient* radial;
SvgLinearGradient* linear;
Matrix* transform;
vector<Fill::ColorStop *> stops;
bool userSpace;
bool usePercentage;
};
@ -286,8 +278,8 @@ struct _SvgNode
SvgNodeType type;
SvgNode* parent;
vector<SvgNode*> child;
string* id;
SvgStyleProperty* style;
string *id;
SvgStyleProperty *style;
Matrix* transform;
union {
SvgGNode g;
@ -309,7 +301,7 @@ struct SvgParser
{
SvgNode* node;
SvgStyleGradient* styleGrad;
SvgGradientStop* gradStop;
Fill::ColorStop* gradStop;
struct
{
int x, y;
@ -334,4 +326,4 @@ struct SvgLoaderData
bool result = false;
};
#endif
#endif

View file

@ -40,7 +40,188 @@ static void _getTransformationData(Matrix* m, float* tx, float* ty, float* s, fl
}
unique_ptr<tvg::Shape> _applyProperty(SvgNode* node, unique_ptr<tvg::Shape> vg)
unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh)
{
Fill::ColorStop* stops;
int stopCount = 0;
float fillOpacity = 255.0f;
float gx, gy, gw, gh;
auto fillGrad = LinearGradient::gen();
if (g->usePercentage) {
g->linear->x1 = g->linear->x1 * rw + rx;
g->linear->y1 = g->linear->y1 * rh + ry;
g->linear->x2 = g->linear->x2 * rw + rx;
g->linear->y2 = g->linear->y2 * rh + ry;
}
//In case of objectBoundingBox it need proper scaling
if (!g->userSpace) {
float scaleX = 1.0, scaleReversedX = 1.0;
float scaleY = 1.0, scaleReversedY = 1.0;
//Check the smallest size, find the scale value
if (rh > rw) {
scaleY = ((float)rw) / rh;
scaleReversedY = ((float)rh) / rw;
} else {
scaleX = ((float)rh) / rw;
scaleReversedX = ((float)rw) / rh;
}
vg->bounds(&gx, &gy, &gw, &gh);
float cy = ((float)gh) * 0.5 + gy;
float cy_scaled = (((float)gh) * 0.5) * scaleReversedY;
float cx = ((float)gw) * 0.5 + gx;
float cx_scaled = (((float)gw) * 0.5) * scaleReversedX;
//= T(gx, gy) x S(scaleX, scaleY) x T(cx_scaled - cx, cy_scaled - cy) x (radial->x, radial->y)
g->linear->x1 = g->linear->x1 * scaleX + scaleX * (cx_scaled - cx) + gx;
g->linear->y1 = g->linear->y1 * scaleY + scaleY * (cy_scaled - cy) + gy;
g->linear->x2 = g->linear->x2 * scaleX + scaleX * (cx_scaled - cx) + gx;
g->linear->y2 = g->linear->y2 * scaleY + scaleY * (cy_scaled - cy) + gy;
}
if (g->transform) {
float cy = ((float) rh) * 0.5 + ry;
float cx = ((float) rw) * 0.5 + rx;
//Calc start point
//= T(x - cx, y - cy) x g->transform x T(cx, cy)
g->linear->x1 = cx * (g->transform->e11 + g->transform->e31 * (g->linear->x1 - cx)) +
cx * (g->transform->e12 + g->transform->e32 * (g->linear->x1 - cx)) +
cx * (g->transform->e13 + g->transform->e33 * (g->linear->x1 - cx));
g->linear->y1 = cy * (g->transform->e21 + g->transform->e31 * (g->linear->y1 - cy)) +
cy * (g->transform->e22 + g->transform->e32 * (g->linear->y1 - cy)) +
cy * (g->transform->e23 + g->transform->e33 * (g->linear->y1 - cy));
//Calc end point
g->linear->x2 = cx * (g->transform->e11 + g->transform->e31 * (g->linear->x2 - cx)) +
cx * (g->transform->e12 + g->transform->e32 * (g->linear->x2 - cx)) +
cx * (g->transform->e13 + g->transform->e33 * (g->linear->x2 - cx));
g->linear->y2 = cy * (g->transform->e21 + g->transform->e31 * (g->linear->y2 - cy)) +
cy * (g->transform->e22 + g->transform->e32 * (g->linear->y2 - cy)) +
cy * (g->transform->e23 + g->transform->e33 * (g->linear->y2 - cy));
}
fillGrad->linear(g->linear->x1, g->linear->y1, g->linear->x2, g->linear->y2);
fillGrad->spread(g->spread);
//Update the stops
stopCount = g->stops.size();
if (stopCount > 0) {
float opacity;
float fopacity = fillOpacity / 255.0f; //fill opacity if any exists.
int i = 0;
stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop));
for (vector<Fill::ColorStop*>::iterator itrStop = g->stops.begin(); itrStop != g->stops.end(); itrStop++) {
//Use premultiplied color
opacity = ((float)(*itrStop)->a / 255) * fopacity;
stops[i].r = ((*itrStop)->r * opacity);
stops[i].g = ((*itrStop)->g * opacity);
stops[i].b = ((*itrStop)->b * opacity);
stops[i].a = ((*itrStop)->a * fopacity);
stops[i].offset = (*itrStop)->offset;
i++;
}
fillGrad->colorStops(stops, stopCount);
free(stops);
}
return move(fillGrad);
}
unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, Shape* vg, float rx, float ry, float rw, float rh)
{
Fill::ColorStop *stops;
int stopCount = 0;
float gx, gy, gw, gh;
int radius;
float fillOpacity = 255.0f;
auto fillGrad = RadialGradient::gen();
radius = sqrt(pow(rw, 2) + pow(rh, 2)) / sqrt(2.0);
if (!g->userSpace) {
//That is according to Units in here
//https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
int min = (rh > rw) ? rw : rh;
radius = sqrt(pow(min, 2) + pow(min, 2)) / sqrt(2.0);
}
if (g->usePercentage) {
g->radial->cx = g->radial->cx * rw + rx;
g->radial->cy = g->radial->cy * rh + ry;
g->radial->r = g->radial->r * radius;
g->radial->fx = g->radial->fx * rw + rx;
g->radial->fy = g->radial->fy * rh + ry;
}
//In case of objectBoundingBox it need proper scaling
if (!g->userSpace) {
float scaleX = 1.0, scaleReversedX = 1.0;
float scaleY = 1.0, scaleReversedY = 1.0;
//Check the smallest size, find the scale value
if (rh > rw) {
scaleY = ((float)rw) / rh;
scaleReversedY = ((float)rh) / rw;
} else {
scaleX = ((float)rh) / rw;
scaleReversedX = ((float)rw) / rh;
}
vg->bounds(&gx, &gy, &gw, &gh);
float cy = ((float)gh) * 0.5 + gy;
float cy_scaled = (((float)gh) * 0.5) * scaleReversedY;
float cx = ((float)gw) * 0.5 + gx;
float cx_scaled = (((float)gw) * 0.5) * scaleReversedX;
//= T(gx, gy) x S(scaleX, scaleY) x T(cx_scaled - cx, cy_scaled - cy) x (radial->x, radial->y)
g->radial->cx = g->radial->cx * scaleX + scaleX * (cx_scaled - cx) + gx;
g->radial->cy = g->radial->cy * scaleY + scaleY * (cy_scaled - cy) + gy;
}
//TODO: Radial gradient transformation is not yet supported.
//if (g->transform) {}
//TODO: Tvg is not support to focal
//if (g->radial->fx != 0 && g->radial->fy != 0) {
// fillGrad->radial(g->radial->fx, g->radial->fy, g->radial->r);
//}
fillGrad->radial(g->radial->cx, g->radial->cy, g->radial->r);
fillGrad->spread(g->spread);
//Update the stops
stopCount = g->stops.size();
if (stopCount > 0) {
float opacity;
float fopacity = fillOpacity / 255.0f; //fill opacity if any exists.
int i = 0;
stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop));
for (vector<Fill::ColorStop*>::iterator itrStop = g->stops.begin(); itrStop != g->stops.end(); itrStop++) {
//Use premultiplied color
opacity = ((float)(*itrStop)->a / 255) * fopacity;
stops[i].r = ((*itrStop)->r * opacity);
stops[i].g = ((*itrStop)->g * opacity);
stops[i].b = ((*itrStop)->b * opacity);
stops[i].a = ((*itrStop)->a * fopacity);
stops[i].offset = (*itrStop)->offset;
i++;
}
fillGrad->colorStops(stops, stopCount);
free(stops);
}
return move(fillGrad);
}
unique_ptr<Shape> _applyProperty(SvgNode* node, unique_ptr<Shape> vg, float vx, float vy, float vw, float vh)
{
SvgStyleProperty* style = node->style;
@ -59,7 +240,15 @@ unique_ptr<tvg::Shape> _applyProperty(SvgNode* node, unique_ptr<tvg::Shape> vg)
if (style->fill.paint.none) {
//Do nothing
} else if (style->fill.paint.gradient) {
//TODO: Support gradient style
if (!style->fill.paint.gradient->userSpace) vg->bounds(&vx, &vy, &vw, &vh);
if (style->fill.paint.gradient->type == SvgGradientType::Linear) {
auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg.get(), vx, vy, vw, vh);
vg->fill(move(linear));
} else if (style->fill.paint.gradient->type == SvgGradientType::Radial) {
auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg.get(), vx, vy, vw, vh);
vg->fill(move(radial));
}
} else if (style->fill.paint.curColor) {
//Apply the current style color
float fa = ((float)style->fill.opacity / 255.0);
@ -113,9 +302,9 @@ unique_ptr<tvg::Shape> _applyProperty(SvgNode* node, unique_ptr<tvg::Shape> vg)
}
unique_ptr<tvg::Shape> _shapeBuildHelper(SvgNode* node)
unique_ptr<Shape> _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh)
{
auto shape = tvg::Shape::gen();
auto shape = Shape::gen();
switch (node->type) {
case SvgNodeType::Path: {
if (node->node.path.path) {
@ -162,15 +351,15 @@ unique_ptr<tvg::Shape> _shapeBuildHelper(SvgNode* node)
break;
}
}
shape = move(_applyProperty(node, move(shape)));
shape = move(_applyProperty(node, move(shape), vx, vy, vw, vh));
return shape;
}
unique_ptr<tvg::Scene> _sceneBuildHelper(SvgNode* node)
unique_ptr<Scene> _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh)
{
if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) {
auto scene = tvg::Scene::gen();
auto scene = Scene::gen();
if (node->transform) {
float tx = 0, ty = 0, s = 0, z = 0;
_getTransformationData(node->transform, &tx, &ty, &s, &z);
@ -180,8 +369,8 @@ unique_ptr<tvg::Scene> _sceneBuildHelper(SvgNode* node)
}
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));
if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild, vx, vy, vw, vh));
else scene->push(_shapeBuildHelper(*itrChild, vx, vy, vw, vh));
}
return move(scene);
}
@ -209,7 +398,7 @@ unique_ptr<Scene> SvgSceneBuilder::build(SvgNode* node)
viewBox.h = node->node.doc.vh;
preserveAspect = node->node.doc.preserveAspect;
staticViewBox = true;
return _sceneBuildHelper(node);
return _sceneBuildHelper(node, viewBox.x, viewBox.y, viewBox.w, viewBox.h);
}

20
test/svgs/lineargrad1.svg Normal file
View file

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs
id="defs4">
<linearGradient
id="linearGradient1"
x1="0"
y1="0"
x2="0.2"
y2="0.2"
spreadMethod="reflect">
<stop
style="stop-color:#ff0000;stop-opacity:1;"
offset="0"/>
<stop
style="stop-color:#0000ff;stop-opacity:1;"
offset="1"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#linearGradient1)"/>
</svg>

After

Width:  |  Height:  |  Size: 514 B

19
test/svgs/radialgrad1.svg Normal file
View file

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs
id="defs4">
<radialGradient
id="radialGradient1"
r="0.2"
cx="0.3"
cy="0.3"
spreadMethod="reflect">
<stop
style="stop-color:#ff0000;stop-opacity:1;"
offset="0"/>
<stop
style="stop-color:#0000ff;stop-opacity:1;"
offset="1"/>
</radialGradient>
</defs>
<rect x="0" y="0" width="100" height="100" fill="url(#radialGradient1)"/>
</svg>

After

Width:  |  Height:  |  Size: 501 B