}
-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);
+ }
+
}
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;
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));
memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient));
}
+ _cloneGradStops(&(grad->stops), from->stops);
return grad;
}
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;
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);
}
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;
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;
}
-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;
}
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;
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);
}
}
}
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);
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();
}
}
-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;
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);
}
-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) {
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);
}
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);
}
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);
}