mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-09 06:04:03 +00:00
Merge "SvgLoader: Support to linear, radial gradient" into tizen
This commit is contained in:
commit
22581040f3
5 changed files with 279 additions and 50 deletions
|
@ -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;
|
for(vector<Fill::ColorStop*>::iterator itrStop = src.begin(); itrStop != src.end(); itrStop++) {
|
||||||
copy(src.begin(), src.end(), dst.begin());
|
Fill::ColorStop *stop = (Fill::ColorStop *)malloc(sizeof(Fill::ColorStop));
|
||||||
return dst;
|
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 = (SvgStyleGradient*)calloc(1, sizeof(SvgStyleGradient));
|
||||||
grad->type = from->type;
|
grad->type = from->type;
|
||||||
grad->id = _copyId(from->id->c_str());
|
grad->id = from->id ? _copyId(from->id->c_str()) : nullptr;
|
||||||
grad->ref = _copyId(from->ref->c_str());
|
grad->ref = from->ref ? _copyId(from->ref->c_str()) : nullptr;
|
||||||
grad->spread = from->spread;
|
grad->spread = from->spread;
|
||||||
grad->usePercentage = from->usePercentage;
|
grad->usePercentage = from->usePercentage;
|
||||||
grad->userSpace = from->userSpace;
|
grad->userSpace = from->userSpace;
|
||||||
|
@ -1390,7 +1397,6 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from)
|
||||||
grad->transform = (Matrix*)calloc(1, sizeof(Matrix));
|
grad->transform = (Matrix*)calloc(1, sizeof(Matrix));
|
||||||
memcpy(grad->transform, from->transform, sizeof(Matrix));
|
memcpy(grad->transform, from->transform, sizeof(Matrix));
|
||||||
}
|
}
|
||||||
grad->stops = _cloneGradStops(from->stops);
|
|
||||||
if (grad->type == SvgGradientType::Linear) {
|
if (grad->type == SvgGradientType::Linear) {
|
||||||
grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
|
grad->linear = (SvgLinearGradient*)calloc(1, sizeof(SvgLinearGradient));
|
||||||
memcpy(grad->linear, from->linear, 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));
|
memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cloneGradStops(&(grad->stops), from->stops);
|
||||||
return grad;
|
return grad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1562,14 +1569,14 @@ FIND_FACTORY(Group, groupTags);
|
||||||
FIND_FACTORY(Graphics, graphicsTags);
|
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")) {
|
if (!strcmp(value, "reflect")) {
|
||||||
spread = SvgGradientSpread::Reflect;
|
spread = FillSpread::Reflect;
|
||||||
} else if (!strcmp(value, "repeat")) {
|
} else if (!strcmp(value, "repeat")) {
|
||||||
spread = SvgGradientSpread::Repeat;
|
spread = FillSpread::Repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
return spread;
|
return spread;
|
||||||
|
@ -1730,7 +1737,7 @@ static SvgStyleGradient* _createRadialGradient(SvgLoaderData* loader, const char
|
||||||
static bool _attrParseStops(void* data, const char* key, const char* value)
|
static bool _attrParseStops(void* data, const char* key, const char* value)
|
||||||
{
|
{
|
||||||
SvgLoaderData* loader = (SvgLoaderData*)data;
|
SvgLoaderData* loader = (SvgLoaderData*)data;
|
||||||
SvgGradientStop* stop = loader->svgParse->gradStop;
|
Fill::ColorStop* stop = loader->svgParse->gradStop;
|
||||||
|
|
||||||
if (!strcmp(key, "offset")) {
|
if (!strcmp(key, "offset")) {
|
||||||
stop->offset = _toOffset(value);
|
stop->offset = _toOffset(value);
|
||||||
|
@ -2008,7 +2015,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
|
||||||
}
|
}
|
||||||
loader->latestGradient = gradient;
|
loader->latestGradient = gradient;
|
||||||
} else if (!strcmp(tagName, "stop")) {
|
} 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;
|
loader->svgParse->gradStop = stop;
|
||||||
/* default value for opacity */
|
/* default value for opacity */
|
||||||
stop->a = 255;
|
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.b = parent->fill.paint.b;
|
||||||
child->fill.paint.none = parent->fill.paint.none;
|
child->fill.paint.none = parent->fill.paint.none;
|
||||||
child->fill.paint.curColor = parent->fill.paint.curColor;
|
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)) {
|
if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) {
|
||||||
child->fill.opacity = parent->fill.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;
|
SvgStyleGradient* result = nullptr;
|
||||||
|
|
||||||
for (vector<SvgStyleGradient*>::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) {
|
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);
|
result = _cloneGradient(*itrGrad);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2122,9 +2129,9 @@ static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, const
|
||||||
|
|
||||||
if (result && result->ref) {
|
if (result && result->ref) {
|
||||||
for (vector<SvgStyleGradient*>::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) {
|
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()) {
|
if (!result->stops.empty()) {
|
||||||
result->stops = _cloneGradStops((*itrGrad)->stops);
|
_cloneGradStops(&(result->stops), (*itrGrad)->stops);
|
||||||
}
|
}
|
||||||
//TODO: Properly inherit other property
|
//TODO: Properly inherit other property
|
||||||
break;
|
break;
|
||||||
|
@ -2138,15 +2145,15 @@ static SvgStyleGradient* _gradientDup(vector<SvgStyleGradient*> gradList, const
|
||||||
|
|
||||||
static void _updateGradient(SvgNode* node, vector<SvgStyleGradient*> gradList)
|
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++) {
|
for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) {
|
||||||
_updateGradient(*itrChild, gradList);
|
_updateGradient(*itrChild, gradList);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (node->style->fill.paint.url) {
|
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) {
|
} 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);
|
free(grad->linear);
|
||||||
if (grad->transform) free(grad->transform);
|
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(*itrStop);
|
||||||
}
|
}
|
||||||
free(grad);
|
free(grad);
|
||||||
|
@ -2284,7 +2291,9 @@ bool SvgLoader::read()
|
||||||
else {
|
else {
|
||||||
if (!loader->loaderData.gradients.empty()) {
|
if (!loader->loaderData.gradients.empty()) {
|
||||||
vector<SvgStyleGradient*> gradientList;
|
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);
|
_updateGradient(loader->loaderData.doc, gradientList);
|
||||||
gradientList.clear();
|
gradientList.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,14 +97,6 @@ enum class SvgStyleType
|
||||||
CompOp
|
CompOp
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SvgGradientSpread
|
|
||||||
{
|
|
||||||
Pad = 0,
|
|
||||||
Reflect,
|
|
||||||
Repeat,
|
|
||||||
Last
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SvgFillRule
|
enum class SvgFillRule
|
||||||
{
|
{
|
||||||
Winding = 0,
|
Winding = 0,
|
||||||
|
@ -240,11 +232,11 @@ struct _SvgStyleGradient
|
||||||
SvgGradientType type;
|
SvgGradientType type;
|
||||||
string *id;
|
string *id;
|
||||||
string *ref;
|
string *ref;
|
||||||
SvgGradientSpread spread;
|
FillSpread spread;
|
||||||
vector<SvgGradientStop *> stops;
|
|
||||||
SvgRadialGradient* radial;
|
SvgRadialGradient* radial;
|
||||||
SvgLinearGradient* linear;
|
SvgLinearGradient* linear;
|
||||||
Matrix* transform;
|
Matrix* transform;
|
||||||
|
vector<Fill::ColorStop *> stops;
|
||||||
bool userSpace;
|
bool userSpace;
|
||||||
bool usePercentage;
|
bool usePercentage;
|
||||||
};
|
};
|
||||||
|
@ -309,7 +301,7 @@ struct SvgParser
|
||||||
{
|
{
|
||||||
SvgNode* node;
|
SvgNode* node;
|
||||||
SvgStyleGradient* styleGrad;
|
SvgStyleGradient* styleGrad;
|
||||||
SvgGradientStop* gradStop;
|
Fill::ColorStop* gradStop;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
|
@ -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;
|
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) {
|
if (style->fill.paint.none) {
|
||||||
//Do nothing
|
//Do nothing
|
||||||
} else if (style->fill.paint.gradient) {
|
} 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) {
|
} else if (style->fill.paint.curColor) {
|
||||||
//Apply the current style color
|
//Apply the current style color
|
||||||
float fa = ((float)style->fill.opacity / 255.0);
|
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) {
|
switch (node->type) {
|
||||||
case SvgNodeType::Path: {
|
case SvgNodeType::Path: {
|
||||||
if (node->node.path.path) {
|
if (node->node.path.path) {
|
||||||
|
@ -162,15 +351,15 @@ unique_ptr<tvg::Shape> _shapeBuildHelper(SvgNode* node)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shape = move(_applyProperty(node, move(shape)));
|
shape = move(_applyProperty(node, move(shape), vx, vy, vw, vh));
|
||||||
return shape;
|
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) {
|
if (node->type == SvgNodeType::Doc || node->type == SvgNodeType::G) {
|
||||||
auto scene = tvg::Scene::gen();
|
auto scene = Scene::gen();
|
||||||
if (node->transform) {
|
if (node->transform) {
|
||||||
float tx = 0, ty = 0, s = 0, z = 0;
|
float tx = 0, ty = 0, s = 0, z = 0;
|
||||||
_getTransformationData(node->transform, &tx, &ty, &s, &z);
|
_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++) {
|
for (vector<SvgNode*>::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) {
|
||||||
SvgNode* child = *itrChild;
|
SvgNode* child = *itrChild;
|
||||||
if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild));
|
if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(*itrChild, vx, vy, vw, vh));
|
||||||
else scene->push(_shapeBuildHelper(*itrChild));
|
else scene->push(_shapeBuildHelper(*itrChild, vx, vy, vw, vh));
|
||||||
}
|
}
|
||||||
return move(scene);
|
return move(scene);
|
||||||
}
|
}
|
||||||
|
@ -209,7 +398,7 @@ unique_ptr<Scene> SvgSceneBuilder::build(SvgNode* node)
|
||||||
viewBox.h = node->node.doc.vh;
|
viewBox.h = node->node.doc.vh;
|
||||||
preserveAspect = node->node.doc.preserveAspect;
|
preserveAspect = node->node.doc.preserveAspect;
|
||||||
staticViewBox = true;
|
staticViewBox = true;
|
||||||
return _sceneBuildHelper(node);
|
return _sceneBuildHelper(node, viewBox.x, viewBox.y, viewBox.w, viewBox.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
20
test/svgs/lineargrad1.svg
Normal file
20
test/svgs/lineargrad1.svg
Normal 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
19
test/svgs/radialgrad1.svg
Normal 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 |
Loading…
Add table
Reference in a new issue