Merge pull request #69344 from DeeJayLSP/update_thorvg

Update thorvg to 0.8.3
This commit is contained in:
Rémi Verschelde 2022-12-01 23:51:33 +01:00 committed by GitHub
commit d47daf0187
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 287 additions and 144 deletions

View file

@ -668,7 +668,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/Samsung/thorvg
- Version: 0.8.2 (496796f1e5e85bd5fbba36dae987edb1b3945592, 2022)
- Version: 0.8.3 (a0fcf51f80a75f63a066df085f60cdaf715188b6, 2022)
- License: MIT
Files extracted from upstream source:

View file

@ -13,5 +13,5 @@
#define THORVG_JPG_LOADER_SUPPORT 1
#define THORVG_VERSION_STRING "0.8.2"
#define THORVG_VERSION_STRING "0.8.3"
#endif

View file

@ -18,7 +18,7 @@
#include <string>
#ifdef TVG_BUILD
#if defined(_MSC_VER) && !defined(__clang__)
#if defined(_WIN32) && !defined(__clang__)
#define TVG_EXPORT __declspec(dllexport)
#define TVG_DEPRECATED __declspec(deprecated)
#else
@ -74,7 +74,7 @@ class Accessor;
/**
* @brief Enumeration specifying the result from the APIs.
*/
enum class TVG_EXPORT Result
enum class Result
{
Success = 0, ///< The value returned in case of a correct request execution.
InvalidArguments, ///< The value returned in the event of a problem with the arguments given to the API - e.g. empty paths or null pointers.
@ -91,7 +91,7 @@ enum class TVG_EXPORT Result
* Not to be confused with the path commands from the svg path element (like M, L, Q, H and many others).
* TVG interprets all of them and translates to the ones from the PathCommand values.
*/
enum class TVG_EXPORT PathCommand
enum class PathCommand
{
Close = 0, ///< Ends the current sub-path and connects it with its initial point. This command doesn't expect any points.
MoveTo, ///< Sets a new initial point of the sub-path and a new current point. This command expects 1 point: the starting position.
@ -102,7 +102,7 @@ enum class TVG_EXPORT PathCommand
/**
* @brief Enumeration determining the ending type of a stroke in the open sub-paths.
*/
enum class TVG_EXPORT StrokeCap
enum class StrokeCap
{
Square = 0, ///< The stroke is extended in both end-points of a sub-path by a rectangle, with the width equal to the stroke width and the length equal to the half of the stroke width. For zero length sub-paths the square is rendered with the size of the stroke width.
Round, ///< The stroke is extended in both end-points of a sub-path by a half circle, with a radius equal to the half of a stroke width. For zero length sub-paths a full circle is rendered.
@ -112,7 +112,7 @@ enum class TVG_EXPORT StrokeCap
/**
* @brief Enumeration determining the style used at the corners of joined stroked path segments.
*/
enum class TVG_EXPORT StrokeJoin
enum class StrokeJoin
{
Bevel = 0, ///< The outer corner of the joined path segments is bevelled at the join point. The triangular region of the corner is enclosed by a straight line between the outer corners of each stroke.
Round, ///< The outer corner of the joined path segments is rounded. The circular region is centered at the join point.
@ -122,7 +122,7 @@ enum class TVG_EXPORT StrokeJoin
/**
* @brief Enumeration specifying how to fill the area outside the gradient bounds.
*/
enum class TVG_EXPORT FillSpread
enum class FillSpread
{
Pad = 0, ///< The remaining area is filled with the closest stop color.
Reflect, ///< The gradient pattern is reflected outside the gradient area until the expected region is filled.
@ -132,7 +132,7 @@ enum class TVG_EXPORT FillSpread
/**
* @brief Enumeration specifying the algorithm used to establish which parts of the shape are treated as the inside of the shape.
*/
enum class TVG_EXPORT FillRule
enum class FillRule
{
Winding = 0, ///< A line from the point to a location outside the shape is drawn. The intersections of the line with the path segment of the shape are counted. Starting from zero, if the path segment of the shape crosses the line clockwise, one is added, otherwise one is subtracted. If the resulting sum is non zero, the point is inside the shape.
EvenOdd ///< A line from the point to a location outside the shape is drawn and its intersections with the path segments of the shape are counted. If the number of intersections is an odd number, the point is inside the shape.
@ -141,7 +141,7 @@ enum class TVG_EXPORT FillRule
/**
* @brief Enumeration indicating the method used in the composition of two objects - the target and the source.
*/
enum class TVG_EXPORT CompositeMethod
enum class CompositeMethod
{
None = 0, ///< No composition is applied.
ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered.
@ -153,7 +153,7 @@ enum class TVG_EXPORT CompositeMethod
/**
* @brief Enumeration specifying the engine type used for the graphics backend. For multiple backends bitwise operation is allowed.
*/
enum class TVG_EXPORT CanvasEngine
enum class CanvasEngine
{
Sw = (1 << 1), ///< CPU rasterizer.
Gl = (1 << 2) ///< OpenGL rasterizer.

View file

@ -22,10 +22,10 @@
#ifdef _WIN32
#include <malloc.h>
#elif __FreeBSD__
#include<stdlib.h>
#else
#elif defined(__linux__)
#include <alloca.h>
#else
#include <stdlib.h>
#endif
#include "tvgMath.h"

View file

@ -30,7 +30,7 @@
int32_t dw = surface->stride;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx, maxx;
int32_t minx = INT32_MAX, maxx = INT32_MIN;
float dx, u, v, iptr;
uint32_t* buf;
SwSpan* span = nullptr; //used only when rle based.

View file

@ -36,7 +36,6 @@ public:
float vw = 0;
float vh = 0;
float w = 0, h = 0; //default image size
bool preserveAspect = true; //keep aspect ratio by default.
virtual ~LoadModule() {}

View file

@ -118,9 +118,9 @@ unique_ptr<Surface> JpgLoader::bitmap()
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(image);
surface->stride = w;
surface->w = w;
surface->h = h;
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
surface->cs = SwCanvas::ARGB8888;
return unique_ptr<Surface>(surface);

View file

@ -808,7 +808,7 @@ inline int jpeg_decoder::huff_decode(huff_tables *pH, int& extra_bits)
// Tables and macro used to fully decode the DPCM differences.
static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
static const unsigned int s_extend_offset[16] = { 0, ((-1u)<<1) + 1, ((-1u)<<2) + 1, ((-1u)<<3) + 1, ((-1u)<<4) + 1, ((-1u)<<5) + 1, ((-1u)<<6) + 1, ((-1u)<<7) + 1, ((-1u)<<8) + 1, ((-1u)<<9) + 1, ((-1u)<<10) + 1, ((-1u)<<11) + 1, ((-1u)<<12) + 1, ((-1u)<<13) + 1, ((-1u)<<14) + 1, ((-1u)<<15) + 1 };
static const unsigned int s_extend_offset[16] = { 0, ((~0u)<<1) + 1, ((~0u)<<2) + 1, ((~0u)<<3) + 1, ((~0u)<<4) + 1, ((~0u)<<5) + 1, ((~0u)<<6) + 1, ((~0u)<<7) + 1, ((~0u)<<8) + 1, ((~0u)<<9) + 1, ((~0u)<<10) + 1, ((~0u)<<11) + 1, ((~0u)<<12) + 1, ((~0u)<<13) + 1, ((~0u)<<14) + 1, ((~0u)<<15) + 1 };
// The logical AND's in this macro are to shut up static code analysis (aren't really necessary - couldn't find another way to do this)
#define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x))

View file

@ -78,9 +78,9 @@ unique_ptr<Surface> RawLoader::bitmap()
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content);
surface->stride = w;
surface->w = w;
surface->h = h;
surface->stride = (uint32_t)w;
surface->w = (uint32_t)w;
surface->h = (uint32_t)h;
surface->cs = SwCanvas::ARGB8888;
return unique_ptr<Surface>(surface);

View file

@ -42,7 +42,10 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
to->fill.paint.color = from->fill.paint.color;
to->fill.paint.none = from->fill.paint.none;
to->fill.paint.curColor = from->fill.paint.curColor;
if (from->fill.paint.url) to->fill.paint.url = strdup(from->fill.paint.url);
if (from->fill.paint.url) {
if (to->fill.paint.url) free(to->fill.paint.url);
to->fill.paint.url = strdup(from->fill.paint.url);
}
to->fill.flags = (SvgFillFlags)((int)to->fill.flags | (int)SvgFillFlags::Paint);
to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Fill);
}
@ -61,7 +64,10 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
to->stroke.paint.color = from->stroke.paint.color;
to->stroke.paint.none = from->stroke.paint.none;
to->stroke.paint.curColor = from->stroke.paint.curColor;
if (from->stroke.paint.url) to->stroke.paint.url = strdup(from->stroke.paint.url);
if (from->stroke.paint.url) {
if (to->stroke.paint.url) free(to->stroke.paint.url);
to->stroke.paint.url = strdup(from->stroke.paint.url);
}
to->stroke.flags = (SvgStrokeFlags)((int)to->stroke.flags | (int)SvgStrokeFlags::Paint);
to->flags = (SvgStyleFlags)((int)to->flags | (int)SvgStyleFlags::Stroke);
}
@ -122,8 +128,14 @@ void cssCopyStyleAttr(SvgNode* to, const SvgNode* from)
//Copy style attribute
_copyStyle(to->style, from->style);
if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url);
if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url);
if (from->style->clipPath.url) {
if (to->style->clipPath.url) free(to->style->clipPath.url);
to->style->clipPath.url = strdup(from->style->clipPath.url);
}
if (from->style->mask.url) {
if (to->style->mask.url) free(to->style->mask.url);
to->style->mask.url = strdup(from->style->mask.url);
}
}

View file

@ -115,9 +115,54 @@ static bool _parseNumber(const char** content, float* number)
if ((*content) == end) return false;
//Skip comma if any
*content = _skipComma(end);
return true;
}
static constexpr struct
{
AspectRatioAlign align;
const char* tag;
} alignTags[] = {
{ AspectRatioAlign::XMinYMin, "xMinYMin" },
{ AspectRatioAlign::XMidYMin, "xMidYMin" },
{ AspectRatioAlign::XMaxYMin, "xMaxYMin" },
{ AspectRatioAlign::XMinYMid, "xMinYMid" },
{ AspectRatioAlign::XMidYMid, "xMidYMid" },
{ AspectRatioAlign::XMaxYMid, "xMaxYMid" },
{ AspectRatioAlign::XMinYMax, "xMinYMax" },
{ AspectRatioAlign::XMidYMax, "xMidYMax" },
{ AspectRatioAlign::XMaxYMax, "xMaxYMax" },
};
static bool _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice)
{
if (!strcmp(*content, "none")) {
*align = AspectRatioAlign::None;
return true;
}
for (unsigned int i = 0; i < sizeof(alignTags) / sizeof(alignTags[0]); i++) {
if (!strncmp(*content, alignTags[i].tag, 8)) {
*align = alignTags[i].align;
*content += 8;
*content = _skipSpace(*content, nullptr);
break;
}
}
if (!strcmp(*content, "meet")) {
*meetOrSlice = AspectRatioMeetOrSlice::Meet;
} else if (!strcmp(*content, "slice")) {
*meetOrSlice = AspectRatioMeetOrSlice::Slice;
}
return true;
}
/**
* According to https://www.w3.org/TR/SVG/coords.html#Units
*/
@ -554,6 +599,7 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
}
}
} else if (ref && len >= 3 && !strncmp(str, "url", 3)) {
if (*ref) free(*ref);
*ref = _idFromUrl((const char*)(str + 3));
} else {
//Handle named color
@ -802,7 +848,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
}
loader->svgParse->global.x = (int)doc->vx;
} else if (!strcmp(key, "preserveAspectRatio")) {
if (!strcmp(value, "none")) doc->preserveAspect = false;
_parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
} else if (!strcmp(key, "style")) {
return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
#ifdef THORVG_LOG_ENABLED
@ -1156,7 +1202,7 @@ static bool _attrParseSymbolNode(void* data, const char* key, const char* value)
symbol->h = _toFloat(loader->svgParse, value, SvgParserLengthType::Vertical);
symbol->hasHeight = true;
} else if (!strcmp(key, "preserveAspectRatio")) {
if (!strcmp(value, "none")) symbol->preserveAspect = false;
_parseAspectRatio(&value, &symbol->align, &symbol->meetOrSlice);
} else if (!strcmp(key, "overflow")) {
if (!strcmp(value, "visible")) symbol->overflowVisible = true;
} else {
@ -1248,7 +1294,8 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha
loader->svgParse->global.w = 0;
loader->svgParse->global.h = 0;
doc->preserveAspect = true;
doc->align = AspectRatioAlign::XMidYMid;
doc->meetOrSlice = AspectRatioMeetOrSlice::Meet;
func(buf, bufLength, _attrParseSvgNode, loader);
if (loader->svgParse->global.w == 0) {
@ -1309,7 +1356,8 @@ static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const
if (!loader->svgParse->node) return nullptr;
loader->svgParse->node->display = false;
loader->svgParse->node->node.symbol.preserveAspect = true;
loader->svgParse->node->node.symbol.align = AspectRatioAlign::XMidYMid;
loader->svgParse->node->node.symbol.meetOrSlice = AspectRatioMeetOrSlice::Meet;
loader->svgParse->node->node.symbol.overflowVisible = false;
loader->svgParse->node->node.symbol.hasViewBox = false;
@ -1331,6 +1379,7 @@ static bool _attrParsePathNode(void* data, const char* key, const char* value)
SvgPathNode* path = &(node->node.path);
if (!strcmp(key, "d")) {
if (path->path) free(path->path);
//Temporary: need to copy
path->path = _copyId(value);
} else if (!strcmp(key, "style")) {
@ -1801,19 +1850,10 @@ static SvgNode* _getDefsNode(SvgNode* node)
}
static SvgNode* _findChildById(const SvgNode* node, const char* id)
static SvgNode* _findNodeById(SvgNode *node, const char* id)
{
if (!node) return nullptr;
auto child = node->child.data;
for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
if (((*child)->id) && !strcmp((*child)->id, id)) return (*child);
}
return nullptr;
}
static SvgNode* _findNodeById(SvgNode *node, const char* id)
{
SvgNode* result = nullptr;
if (node->id && !strcmp(node->id, id)) return node;
@ -1827,6 +1867,7 @@ static SvgNode* _findNodeById(SvgNode *node, const char* id)
return result;
}
static void _cloneGradStops(Array<Fill::ColorStop>& dst, const Array<Fill::ColorStop>& src)
{
for (uint32_t i = 0; i < src.count; ++i) {
@ -1889,7 +1930,10 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren
child->fill.paint.color = parent->fill.paint.color;
child->fill.paint.none = parent->fill.paint.none;
child->fill.paint.curColor = parent->fill.paint.curColor;
if (parent->fill.paint.url) child->fill.paint.url = _copyId(parent->fill.paint.url);
if (parent->fill.paint.url) {
if (child->fill.paint.url) free(child->fill.paint.url);
child->fill.paint.url = _copyId(parent->fill.paint.url);
}
}
if (!((int)child->fill.flags & (int)SvgFillFlags::Opacity)) {
child->fill.opacity = parent->fill.opacity;
@ -1902,7 +1946,12 @@ static void _styleInherit(SvgStyleProperty* child, const SvgStyleProperty* paren
child->stroke.paint.color = parent->stroke.paint.color;
child->stroke.paint.none = parent->stroke.paint.none;
child->stroke.paint.curColor = parent->stroke.paint.curColor;
child->stroke.paint.url = parent->stroke.paint.url ? _copyId(parent->stroke.paint.url) : nullptr;
if (parent->stroke.paint.url) {
if (child->stroke.paint.url) free(child->stroke.paint.url);
child->stroke.paint.url = _copyId(parent->stroke.paint.url);
} else {
child->stroke.paint.url = nullptr;
}
}
if (!((int)child->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
child->stroke.opacity = parent->stroke.opacity;
@ -1942,7 +1991,10 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from)
to->fill.paint.color = from->fill.paint.color;
to->fill.paint.none = from->fill.paint.none;
to->fill.paint.curColor = from->fill.paint.curColor;
if (from->fill.paint.url) to->fill.paint.url = _copyId(from->fill.paint.url);
if (from->fill.paint.url) {
if (to->fill.paint.url) free(to->fill.paint.url);
to->fill.paint.url = _copyId(from->fill.paint.url);
}
}
if (((int)from->fill.flags & (int)SvgFillFlags::Opacity)) {
to->fill.opacity = from->fill.opacity;
@ -1956,7 +2008,12 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from)
to->stroke.paint.color = from->stroke.paint.color;
to->stroke.paint.none = from->stroke.paint.none;
to->stroke.paint.curColor = from->stroke.paint.curColor;
to->stroke.paint.url = from->stroke.paint.url ? _copyId(from->stroke.paint.url) : nullptr;
if (from->stroke.paint.url) {
if (to->stroke.paint.url) free(to->stroke.paint.url);
to->stroke.paint.url = _copyId(from->stroke.paint.url);
} else {
to->stroke.paint.url = nullptr;
}
}
if (((int)from->stroke.flags & (int)SvgStrokeFlags::Opacity)) {
to->stroke.opacity = from->stroke.opacity;
@ -1992,10 +2049,14 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
//Copy style attribute
_styleCopy(to->style, from->style);
to->style->flags = (SvgStyleFlags)((int)to->style->flags | (int)from->style->flags);
if (from->style->fill.paint.url) to->style->fill.paint.url = strdup(from->style->fill.paint.url);
if (from->style->stroke.paint.url) to->style->stroke.paint.url = strdup(from->style->stroke.paint.url);
if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url);
if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url);
if (from->style->clipPath.url) {
if (to->style->clipPath.url) free(to->style->clipPath.url);
to->style->clipPath.url = strdup(from->style->clipPath.url);
}
if (from->style->mask.url) {
if (to->style->mask.url) free(to->style->mask.url);
to->style->mask.url = strdup(from->style->mask.url);
}
//Copy node attribute
switch (from->type) {
@ -2031,7 +2092,10 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
break;
}
case SvgNodeType::Path: {
if (from->node.path.path) to->node.path.path = strdup(from->node.path.path);
if (from->node.path.path) {
if (to->node.path.path) free(to->node.path.path);
to->node.path.path = strdup(from->node.path.path);
}
break;
}
case SvgNodeType::Polygon: {
@ -2053,7 +2117,10 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
to->node.image.y = from->node.image.y;
to->node.image.w = from->node.image.w;
to->node.image.h = from->node.image.h;
if (from->node.image.href) to->node.image.href = strdup(from->node.image.href);
if (from->node.image.href) {
if (to->node.image.href) free(to->node.image.href);
to->node.image.href = strdup(from->node.image.href);
}
break;
}
default: {
@ -2093,8 +2160,8 @@ static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
for (uint32_t i = 0; i < cloneNodes->count; ++i) {
auto nodeIdPair = cloneNodes->data[i];
auto defs = _getDefsNode(nodeIdPair.node);
auto nodeFrom = _findChildById(defs, nodeIdPair.id);
if (!nodeFrom) nodeFrom = _findChildById(doc, nodeIdPair.id);
auto nodeFrom = _findNodeById(defs, nodeIdPair.id);
if (!nodeFrom) nodeFrom = _findNodeById(doc, nodeIdPair.id);
_cloneNode(nodeFrom, nodeIdPair.node, 0);
if (nodeFrom && nodeFrom->type == SvgNodeType::Symbol && nodeIdPair.node->type == SvgNodeType::Use) {
nodeIdPair.node->node.use.symbol = nodeFrom;
@ -2141,7 +2208,7 @@ static bool _attrParseUseNode(void* data, const char* key, const char* value)
if (!strcmp(key, "href") || !strcmp(key, "xlink:href")) {
id = _idFromHref(value);
defs = _getDefsNode(node);
nodeFrom = _findChildById(defs, id);
nodeFrom = _findNodeById(defs, id);
if (nodeFrom) {
_cloneNode(nodeFrom, node, 0);
if (nodeFrom->type == SvgNodeType::Symbol) use->symbol = nodeFrom;
@ -2695,10 +2762,14 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1];
else parent = loader->doc;
if (!strcmp(tagName, "style")) {
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
loader->cssStyle = node;
loader->doc->node.doc.style = node;
loader->style = true;
// TODO: For now only the first style node is saved. After the css id selector
// is introduced this if condition shouldin't be necessary any more
if (!loader->cssStyle) {
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
loader->cssStyle = node;
loader->doc->node.doc.style = node;
loader->style = true;
}
} else {
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
}
@ -3127,7 +3198,7 @@ void SvgLoader::run(unsigned tid)
_updateStyle(loaderData.doc, nullptr);
}
root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath);
root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, align, meetOrSlice, svgPath);
}
@ -3160,7 +3231,8 @@ bool SvgLoader::header()
if (vh < FLT_EPSILON) vh = h;
}
preserveAspect = loaderData.doc->node.doc.preserveAspect;
align = loaderData.doc->node.doc.align;
meetOrSlice = loaderData.doc->node.doc.meetOrSlice;
} else {
TVGLOG("SVG", "No SVG File. There is no <svg/>");
return false;
@ -3215,31 +3287,9 @@ bool SvgLoader::resize(Paint* paint, float w, float h)
auto sx = w / this->w;
auto sy = h / this->h;
Matrix m = {sx, 0, 0, 0, sy, 0, 0, 0, 1};
paint->transform(m);
if (preserveAspect) {
//Scale
auto scale = sx < sy ? sx : sy;
paint->scale(scale);
//Align
auto tx = 0.0f;
auto ty = 0.0f;
auto tw = this->w * scale;
auto th = this->h * scale;
if (tw > th) ty -= (h - th) * 0.5f;
else tx -= (w - tw) * 0.5f;
paint->translate(-tx, -ty);
} else {
//Align
auto tx = 0.0f;
auto ty = 0.0f;
auto tw = this->w * sx;
auto th = this->h * sy;
if (tw > th) ty -= (h - th) * 0.5f;
else tx -= (w - tw) * 0.5f;
Matrix m = {sx, 0, -tx, 0, sy, -ty, 0, 0, 1};
paint->transform(m);
}
return true;
}

View file

@ -50,6 +50,9 @@ public:
unique_ptr<Paint> paint() override;
private:
AspectRatioAlign align = AspectRatioAlign::XMidYMid;
AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet;
bool header();
void clear();
void run(unsigned tid) override;

View file

@ -145,6 +145,26 @@ enum class SvgParserLengthType
Other
};
enum class AspectRatioAlign
{
None,
XMinYMin,
XMidYMin,
XMaxYMin,
XMinYMid,
XMidYMid,
XMaxYMid,
XMinYMax,
XMidYMax,
XMaxYMax
};
enum class AspectRatioMeetOrSlice
{
Meet,
Slice
};
struct SvgDocNode
{
float w;
@ -155,7 +175,8 @@ struct SvgDocNode
float vh;
SvgNode* defs;
SvgNode* style;
bool preserveAspect;
AspectRatioAlign align;
AspectRatioMeetOrSlice meetOrSlice;
};
struct SvgGNode
@ -171,7 +192,8 @@ struct SvgSymbolNode
{
float w, h;
float vx, vy, vw, vh;
bool preserveAspect;
AspectRatioAlign align;
AspectRatioMeetOrSlice meetOrSlice;
bool overflowVisible;
bool hasViewBox;
bool hasWidth;

View file

@ -49,9 +49,9 @@
*/
#include "tvgMath.h" /* to include math.h before cstring */
#include <cstring>
#include <string>
#include "tvgMath.h"
#include "tvgSvgLoaderCommon.h"
#include "tvgSvgSceneBuilder.h"
#include "tvgSvgPath.h"
@ -68,7 +68,7 @@ struct Box
static bool _appendShape(SvgNode* node, Shape* shape, const Box& vBox, const string& svgPath);
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite = nullptr);
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite = nullptr);
static inline bool _isGroupType(SvgNodeType type)
@ -282,7 +282,7 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
node->style->mask.applying = true;
bool isMaskWhite = true;
auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, &isMaskWhite);
auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true, 0, &isMaskWhite);
if (comp) {
if (node->transform) comp->transform(*node->transform);
@ -560,10 +560,84 @@ static unique_ptr<Picture> _imageBuildHelper(SvgNode* node, const Box& vBox, con
}
static unique_ptr<Scene> _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool* isMaskWhite)
static Matrix _calculateAspectRatioMatrix(AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, float width, float height, const Box& box)
{
auto sx = width / box.w;
auto sy = height / box.h;
auto tvx = box.x * sx;
auto tvy = box.y * sy;
if (align == AspectRatioAlign::None)
return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
//Scale
if (meetOrSlice == AspectRatioMeetOrSlice::Meet) {
if (sx < sy) sy = sx;
else sx = sy;
} else {
if (sx < sy) sx = sy;
else sy = sx;
}
//Align
tvx = box.x * sx;
tvy = box.y * sy;
auto tvw = box.w * sx;
auto tvh = box.h * sy;
switch (align) {
case AspectRatioAlign::XMinYMin: {
break;
}
case AspectRatioAlign::XMidYMin: {
tvx -= (width - tvw) * 0.5f;
break;
}
case AspectRatioAlign::XMaxYMin: {
tvx -= width - tvw;
break;
}
case AspectRatioAlign::XMinYMid: {
tvy -= (height - tvh) * 0.5f;
break;
}
case AspectRatioAlign::XMidYMid: {
tvx -= (width - tvw) * 0.5f;
tvy -= (height - tvh) * 0.5f;
break;
}
case AspectRatioAlign::XMaxYMid: {
tvx -= width - tvw;
tvy -= (height - tvh) * 0.5f;
break;
}
case AspectRatioAlign::XMinYMax: {
tvy -= height - tvh;
break;
}
case AspectRatioAlign::XMidYMax: {
tvx -= (width - tvw) * 0.5f;
tvy -= height - tvh;
break;
}
case AspectRatioAlign::XMaxYMax: {
tvx -= width - tvw;
tvy -= height - tvh;
break;
}
default: {
break;
}
}
return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
}
static unique_ptr<Scene> _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, int depth, bool* isMaskWhite)
{
unique_ptr<Scene> finalScene;
auto scene = _sceneBuildHelper(node, vBox, svgPath, false, isMaskWhite);
auto scene = _sceneBuildHelper(node, vBox, svgPath, false, depth + 1, isMaskWhite);
// mUseTransform = mUseTransform * mTranslate
Matrix mUseTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
@ -585,20 +659,8 @@ static unique_ptr<Scene> _useBuildHelper(const SvgNode* node, const Box& vBox, c
Matrix mViewBox = {1, 0, 0, 0, 1, 0, 0, 0, 1};
if ((!mathEqual(width, vw) || !mathEqual(height, vh)) && vw > 0 && vh > 0) {
auto sx = width / vw;
auto sy = height / vh;
if (symbol.preserveAspect) {
if (sx < sy) sy = sx;
else sx = sy;
}
auto tvx = symbol.vx * sx;
auto tvy = symbol.vy * sy;
auto tvw = vw * sx;
auto tvh = vh * sy;
tvy -= (symbol.h - tvh) * 0.5f;
tvx -= (symbol.w - tvw) * 0.5f;
mViewBox = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
Box box = {symbol.vx, symbol.vy, vw, vh};
mViewBox = _calculateAspectRatioMatrix(symbol.align, symbol.meetOrSlice, width, height, box);
} else if (!mathZero(symbol.vx) || !mathZero(symbol.vy)) {
mViewBox = {1, 0, -symbol.vx, 0, 1, -symbol.vy, 0, 0, 1};
}
@ -642,8 +704,15 @@ static unique_ptr<Scene> _useBuildHelper(const SvgNode* node, const Box& vBox, c
}
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, bool* isMaskWhite)
static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite)
{
/* Exception handling: Prevent invalid SVG data input.
The size is the arbitrary value, we need an experimental size. */
if (depth > 2192) {
TVGERR("SVG", "Infinite recursive call - stopped after %d calls! Svg file may be incorrectly formatted.", depth);
return nullptr;
}
if (_isGroupType(node->type) || mask) {
auto scene = Scene::gen();
// For a Symbol node, the viewBox transformation has to be applied first - see _useBuildHelper()
@ -654,12 +723,15 @@ static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox,
for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
if (_isGroupType((*child)->type)) {
if ((*child)->type == SvgNodeType::Use)
scene->push(_useBuildHelper(*child, vBox, svgPath, isMaskWhite));
scene->push(_useBuildHelper(*child, vBox, svgPath, depth + 1, isMaskWhite));
else
scene->push(_sceneBuildHelper(*child, vBox, svgPath, false, isMaskWhite));
scene->push(_sceneBuildHelper(*child, vBox, svgPath, false, depth + 1, isMaskWhite));
} else if ((*child)->type == SvgNodeType::Image) {
auto image = _imageBuildHelper(*child, vBox, svgPath);
if (image) scene->push(move(image));
if (image) {
scene->push(move(image));
if (isMaskWhite) *isMaskWhite = false;
}
} else if ((*child)->type != SvgNodeType::Mask) {
auto shape = _shapeBuildHelper(*child, vBox, svgPath);
if (shape) {
@ -688,36 +760,18 @@ static unique_ptr<Scene> _sceneBuildHelper(const SvgNode* node, const Box& vBox,
/* External Class Implementation */
/************************************************************************/
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath)
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath)
{
//TODO: aspect ratio is valid only if viewBox was set
if (!node || (node->type != SvgNodeType::Doc)) return nullptr;
Box vBox = {vx, vy, vw, vh};
auto docNode = _sceneBuildHelper(node, vBox, svgPath, false);
auto docNode = _sceneBuildHelper(node, vBox, svgPath, false, 0);
if (!mathEqual(w, vw) || !mathEqual(h, vh)) {
auto sx = w / vw;
auto sy = h / vh;
if (preserveAspect) {
//Scale
auto scale = sx < sy ? sx : sy;
docNode->scale(scale);
//Align
auto tvx = vx * scale;
auto tvy = vy * scale;
auto tvw = vw * scale;
auto tvh = vh * scale;
tvx -= (w - tvw) * 0.5f;
tvy -= (h - tvh) * 0.5f;
docNode->translate(-tvx, -tvy);
} else {
//Align
auto tvx = vx * sx;
auto tvy = vy * sy;
Matrix m = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1};
docNode->transform(m);
}
Matrix m = _calculateAspectRatioMatrix(align, meetOrSlice, w, h, vBox);
docNode->transform(m);
} else if (!mathZero(vx) || !mathZero(vy)) {
docNode->translate(-vx, -vy);
}

View file

@ -25,6 +25,6 @@
#include "tvgCommon.h"
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath);
unique_ptr<Scene> svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath);
#endif //_TVG_SVG_SCENE_BUILDER_H_

View file

@ -26,10 +26,10 @@
#ifdef _WIN32
#include <malloc.h>
#elif __FreeBSD__
#include<stdlib.h>
#else
#elif defined(__linux__)
#include <alloca.h>
#else
#include <stdlib.h>
#endif
#include "tvgXmlParser.h"

View file

@ -23,10 +23,10 @@
#ifdef _WIN32
#include <malloc.h>
#elif __FreeBSD__
#include<stdlib.h>
#else
#elif defined(__linux__)
#include <alloca.h>
#else
#include <stdlib.h>
#endif
#include "tvgTvgCommon.h"

View file

@ -28,10 +28,10 @@
#ifdef _WIN32
#include <malloc.h>
#elif __FreeBSD__
#include<stdlib.h>
#else
#elif defined(__linux__)
#include <alloca.h>
#else
#include <stdlib.h>
#endif
static FILE* _fopen(const char* filename, const char* mode)

View file

@ -1,4 +1,4 @@
VERSION=0.8.2
VERSION=0.8.3
rm -rf AUTHORS inc LICENSE src *.zip
curl -L -O https://github.com/Samsung/thorvg/archive/v$VERSION.zip
bsdtar --strip-components=1 -xvf *.zip
@ -26,3 +26,6 @@ cat << EOF > inc/config.h
#define THORVG_VERSION_STRING "$VERSION"
#endif
EOF
for source in $(find ./ -type f \( -iname \*.h -o -iname \*.cpp \)); do
sed -i -e '$a\' $source
done