Update thorvg to 0.8.3
This commit is contained in:
parent
6fdbf79046
commit
88b7d5c3c5
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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() {}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue