Update thorvg to 0.8.4

This commit is contained in:
RedworkDE 2023-03-30 22:19:59 +02:00
parent dbf1a7277f
commit cfed867da1
28 changed files with 206 additions and 62 deletions

View File

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

View File

@ -4,7 +4,7 @@ Junsu Choi <jsuya.choi@samsung.com>
Pranay Samanta <pranay.ks@samsung.com>
Mateusz Palkowski <m.palkowski@samsung.com>
Subhransu Mohanty <sub.mohanty@samsung.com>
Mira Grudzinska <m.grudzinska@samsung.com>
Mira Grudzinska <veleveta@gmail.com>
Michal Szczecinski <m.szczecinsk@partner.samsung.com>
Shinwoo Kim <cinoo.kim@samsung.com>
Piotr Kalota <p.kalota@samsung.com>

View File

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

View File

@ -335,6 +335,20 @@ public:
*/
CompositeMethod composite(const Paint** target) const noexcept;
/**
* @brief Gets the composition source object and the composition method.
*
* @param[out] source The paint of the composition source object.
* @param[out] method The method used to composite the source object with the target.
*
* @return Result::Success when the paint object used as a composition target, Result::InsufficientCondition otherwise.
*
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
*
* @BETA_API
*/
Result composite(const Paint** source, CompositeMethod* method) const noexcept;
/**
* @brief Return the unique id value of the paint instance.
*

View File

@ -76,7 +76,9 @@ struct SwShapeTask : SwTask
void run(unsigned tid) override
{
if (opacity == 0) return; //Invisible
auto compMethod = CompositeMethod::None;
auto usedAsClip = (sdata->composite(nullptr, &compMethod) == Result::Success) && (compMethod == CompositeMethod::ClipPath);
if (opacity == 0 && !usedAsClip) return; //Invisible
uint8_t strokeAlpha = 0;
auto visibleStroke = false;
@ -98,7 +100,7 @@ struct SwShapeTask : SwTask
sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
visibleFill = (alpha > 0 || sdata->fill());
if (visibleFill || visibleStroke) {
if (visibleFill || visibleStroke || usedAsClip) {
shapeReset(&shape);
if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
}
@ -110,7 +112,7 @@ struct SwShapeTask : SwTask
//Fill
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
if (visibleFill) {
if (visibleFill || usedAsClip) {
/* We assume that if stroke width is bigger than 2,
shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition.
@ -291,7 +293,7 @@ bool SwRenderer::viewport(const RenderRegion& vp)
}
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace)
{
if (!buffer || stride == 0 || w == 0 || h == 0 || w > stride) return false;
@ -301,7 +303,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
surface->stride = stride;
surface->w = w;
surface->h = h;
surface->cs = cs;
surface->cs = colorSpace;
vport.x = vport.y = 0;
vport.w = surface->w;
@ -644,6 +646,13 @@ SwRenderer::SwRenderer():mpool(globalMpool)
}
uint32_t SwRenderer::colorSpace()
{
if (surface) return surface->cs;
return tvg::SwCanvas::ARGB8888;
}
bool SwRenderer::init(uint32_t threads)
{
if ((initEngineCnt++) > 0) return true;

View File

@ -48,7 +48,7 @@ public:
bool clear() override;
bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace);
bool mempool(bool shared);
Compositor* target(const RenderRegion& region) override;
@ -56,6 +56,8 @@ public:
bool endComposite(Compositor* cmp) override;
void clearCompositors();
uint32_t colorSpace() override;
static SwRenderer* gen();
static bool init(uint32_t threads);
static int32_t init();

View File

@ -72,7 +72,7 @@ Accessor::~Accessor()
}
Accessor::Accessor()
Accessor::Accessor() : pImpl(nullptr)
{
}

View File

@ -36,6 +36,7 @@ public:
float vw = 0;
float vh = 0;
float w = 0, h = 0; //default image size
uint32_t colorSpace = SwCanvas::ARGB8888;
virtual ~LoadModule() {}
@ -48,7 +49,7 @@ public:
virtual bool read() = 0;
virtual bool close() = 0;
virtual unique_ptr<Surface> bitmap() { return nullptr; }
virtual unique_ptr<Surface> bitmap(uint32_t colorSpace) { return nullptr; }
virtual unique_ptr<Paint> paint() { return nullptr; }
};

View File

@ -53,6 +53,12 @@ static inline bool mathRightAngle(const Matrix* m)
}
static inline bool mathSkewed(const Matrix* m)
{
return (fabsf(m->e21 + m->e12) > FLT_EPSILON);
}
static inline bool mathIdentity(const Matrix* m)
{
if (!mathEqual(m->e11, 1.0f) || !mathZero(m->e12) || !mathZero(m->e13) ||

View File

@ -38,9 +38,9 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform,
if (rTransform) rTransform->update();
//No rotational.
if (pTransform && !mathRightAngle(&pTransform->m)) return false;
if (rTransform && !mathRightAngle(&rTransform->m)) return false;
//No rotation and no skewing
if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return false;
if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return false;
//Perpendicular Rectangle?
auto pt1 = pts + 0;
@ -384,6 +384,19 @@ CompositeMethod Paint::composite(const Paint** target) const noexcept
}
Result Paint::composite(const Paint** source, CompositeMethod* method) const noexcept
{
if (source) *source = pImpl->compSource;
auto met = (pImpl->compSource && pImpl->compSource->pImpl->compData ?
pImpl->compSource->pImpl->compData->method : CompositeMethod::None);
if (method) *method = met;
if (pImpl->compSource != nullptr && met != CompositeMethod::None)
return Result::Success;
return Result::InsufficientCondition;
}
Result Paint::opacity(uint8_t o) noexcept
{
if (pImpl->opacity == o) return Result::Success;

View File

@ -62,6 +62,7 @@ namespace tvg
StrategyMethod* smethod = nullptr;
RenderTransform* rTransform = nullptr;
Composite* compData = nullptr;
Paint* compSource = nullptr;
uint32_t renderFlag = RenderUpdateFlag::None;
uint32_t ctxFlag = ContextFlag::Invalid;
uint32_t id;
@ -136,6 +137,7 @@ namespace tvg
if (!target && method == CompositeMethod::None) return true;
compData = static_cast<Composite*>(calloc(1, sizeof(Composite)));
}
target->pImpl->compSource = source;
compData->target = target;
compData->source = source;
compData->method = method;

View File

@ -66,6 +66,7 @@ struct Picture::Impl
void* rdata = nullptr; //engine data
float w = 0, h = 0;
bool resizing = false;
uint32_t rendererColorSpace = 0;
~Impl()
{
@ -100,7 +101,7 @@ struct Picture::Impl
}
}
free(surface);
if ((surface = loader->bitmap().release())) {
if ((surface = loader->bitmap(rendererColorSpace).release())) {
loader->close();
return RenderUpdateFlag::Image;
}
@ -124,6 +125,7 @@ struct Picture::Impl
void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{
rendererColorSpace = renderer.colorSpace();
auto flag = reload();
if (surface) {

View File

@ -106,6 +106,8 @@ public:
virtual Compositor* target(const RenderRegion& region) = 0;
virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0;
virtual bool endComposite(Compositor* cmp) = 0;
virtual uint32_t colorSpace() = 0;
};
}

View File

@ -25,7 +25,7 @@
/* External Class Implementation */
/************************************************************************/
Scene::Scene() : pImpl(new Impl())
Scene::Scene() : pImpl(new Impl(this))
{
Paint::pImpl->id = TVG_CLASS_ID_SCENE;
Paint::pImpl->method(new PaintMethod<Scene::Impl>(pImpl));

View File

@ -60,6 +60,11 @@ struct Scene::Impl
Array<Paint*> paints;
uint8_t opacity; //for composition
RenderMethod* renderer = nullptr; //keep it for explicit clear
Scene* scene = nullptr;
Impl(Scene* s) : scene(s)
{
}
~Impl()
{
@ -81,8 +86,14 @@ struct Scene::Impl
bool needComposition(uint32_t opacity)
{
if (opacity == 0 || paints.count == 0) return false;
//Masking may require composition (even if opacity == 255)
auto compMethod = scene->composite(nullptr);
if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) return true;
//Half translucent requires intermediate composition.
if (opacity == 255 || opacity == 0) return false;
if (opacity == 255) return false;
//If scene has several children or only scene, it may require composition.
if (paints.count > 1) return true;

View File

@ -42,6 +42,24 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h)
}
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
PngLoader::PngLoader()
{
image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
@ -110,16 +128,21 @@ bool PngLoader::close()
return true;
}
unique_ptr<Surface> PngLoader::bitmap()
unique_ptr<Surface> PngLoader::bitmap(uint32_t colorSpace)
{
if (!content) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(content, w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content);
surface->buffer = content;
surface->stride = w;
surface->w = w;
surface->h = h;
surface->cs = SwCanvas::ARGB8888;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View File

@ -36,11 +36,11 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
private:
png_imagep image = nullptr;
const uint32_t* content = nullptr;
uint32_t* content = nullptr;
};
#endif //_TVG_PNG_LOADER_H_

View File

@ -28,6 +28,24 @@
/* Internal Class Implementation */
/************************************************************************/
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
void JpgLoader::clear()
{
jpgdDelete(decoder);
@ -110,18 +128,22 @@ bool JpgLoader::close()
}
unique_ptr<Surface> JpgLoader::bitmap()
unique_ptr<Surface> JpgLoader::bitmap(uint32_t colorSpace)
{
this->done();
if (!image) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(reinterpret_cast<uint32_t*>(image), w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(image);
surface->buffer = reinterpret_cast<uint32_t*>(image);
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;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View File

@ -44,7 +44,7 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
void run(unsigned tid) override;
};

View File

@ -28,6 +28,23 @@
/* Internal Class Implementation */
/************************************************************************/
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@ -54,7 +71,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy)
if (!content) return false;
memcpy((void*)content, data, sizeof(uint32_t) * w * h);
}
else content = data;
else content = const_cast<uint32_t*>(data);
return true;
}
@ -72,16 +89,20 @@ bool RawLoader::close()
}
unique_ptr<Surface> RawLoader::bitmap()
unique_ptr<Surface> RawLoader::bitmap(uint32_t colorSpace)
{
if (!content) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(content, w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content);
surface->stride = (uint32_t)w;
surface->w = (uint32_t)w;
surface->h = (uint32_t)h;
surface->cs = SwCanvas::ARGB8888;
surface->buffer = content;
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View File

@ -25,7 +25,7 @@
class RawLoader : public LoadModule
{
public:
const uint32_t* content = nullptr;
uint32_t* content = nullptr;
bool copy = false;
~RawLoader();
@ -35,7 +35,7 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
};

View File

@ -180,9 +180,9 @@ static float _toFloat(const SvgParser* svgParse, const char* str, SvgParserLengt
else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w;
else //if other then it's radius
{
float max = (float)svgParse->global.w;
float max = svgParse->global.w;
if (max < svgParse->global.h)
max = (float)svgParse->global.h;
max = svgParse->global.h;
parsedValue = (parsedValue / 100.0) * max;
}
}
@ -341,7 +341,7 @@ static void _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* das
++end;
//Refers to the diagonal length of the viewport.
//https://www.w3.org/TR/SVG2/coords.html#Units
parsedValue = (sqrtf(pow(loader->svgParse->global.w, 2) + pow(loader->svgParse->global.h, 2)) / sqrtf(2.0f)) * (parsedValue / 100.0f);
parsedValue = (sqrtf(powf(loader->svgParse->global.w, 2) + powf(loader->svgParse->global.h, 2)) / sqrtf(2.0f)) * (parsedValue / 100.0f);
}
(*dash).array.push(parsedValue);
str = end;
@ -376,7 +376,7 @@ static char* _idFromUrl(const char* url)
}
static unsigned char _parserColor(const char* value, char** end)
static unsigned char _parseColor(const char* value, char** end)
{
float r;
@ -586,11 +586,11 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
*b = strtol(tmp, nullptr, 16);
}
} else if (len >= 10 && (str[0] == 'r' || str[0] == 'R') && (str[1] == 'g' || str[1] == 'G') && (str[2] == 'b' || str[2] == 'B') && str[3] == '(' && str[len - 1] == ')') {
tr = _parserColor(str + 4, &red);
tr = _parseColor(str + 4, &red);
if (red && *red == ',') {
tg = _parserColor(red + 1, &green);
tg = _parseColor(red + 1, &green);
if (green && *green == ',') {
tb = _parserColor(green + 1, &blue);
tb = _parseColor(green + 1, &blue);
if (blue && blue[0] == ')' && blue[1] == '\0') {
*r = tr;
*g = tg;
@ -840,13 +840,13 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
if (_parseNumber(&value, &doc->vy)) {
if (_parseNumber(&value, &doc->vw)) {
_parseNumber(&value, &doc->vh);
loader->svgParse->global.h = (uint32_t)doc->vh;
loader->svgParse->global.h = doc->vh;
}
loader->svgParse->global.w = (uint32_t)doc->vw;
loader->svgParse->global.w = doc->vw;
}
loader->svgParse->global.y = (int)doc->vy;
loader->svgParse->global.y = doc->vy;
}
loader->svgParse->global.x = (int)doc->vx;
loader->svgParse->global.x = doc->vx;
} else if (!strcmp(key, "preserveAspectRatio")) {
_parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
} else if (!strcmp(key, "style")) {
@ -1300,11 +1300,11 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha
if (loader->svgParse->global.w == 0) {
if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1;
else loader->svgParse->global.w = (uint32_t)doc->w;
else loader->svgParse->global.w = doc->w;
}
if (loader->svgParse->global.h == 0) {
if (doc->h < FLT_EPSILON) loader->svgParse->global.h = 1;
else loader->svgParse->global.h = (uint32_t)doc->h;
else loader->svgParse->global.h = doc->h;
}
return loader->svgParse->node;
@ -2375,7 +2375,7 @@ static void _recalcRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial
static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace)
{
// scaling factor based on the Units paragraph from : https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
if (userSpace && !radial->isRPercentage) radial->r = radial->r / (sqrtf(pow(loader->svgParse->global.h, 2) + pow(loader->svgParse->global.w, 2)) / sqrtf(2.0));
if (userSpace && !radial->isRPercentage) radial->r = radial->r / (sqrtf(powf(loader->svgParse->global.h, 2) + powf(loader->svgParse->global.w, 2)) / sqrtf(2.0));
}
@ -3180,6 +3180,12 @@ SvgLoader::~SvgLoader()
void SvgLoader::run(unsigned tid)
{
//According to the SVG standard the value of the width/height of the viewbox set to 0 disables rendering
if (renderingDisabled) {
root = Scene::gen();
return;
}
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
if (loaderData.doc) {

View File

@ -52,6 +52,7 @@ public:
private:
AspectRatioAlign align = AspectRatioAlign::XMidYMid;
AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet;
bool renderingDisabled = false;
bool header();
void clear();

View File

@ -425,8 +425,7 @@ struct SvgParser
SvgStopStyleFlags flags;
struct
{
int x, y;
uint32_t w, h;
float x, y, w, h;
} global;
struct
{

View File

@ -255,7 +255,6 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox
node->style->clipPath.applying = true;
auto comp = Shape::gen();
comp->fill(255, 255, 255, 255);
if (node->transform) comp->transform(*node->transform);
auto child = compNode->child.data;
@ -348,7 +347,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, const Box& vBox, const stri
//If stroke property is nullptr then do nothing
if (style->stroke.paint.none) {
//Do nothing
vg->stroke(0.0f);
} else if (style->stroke.paint.gradient) {
Box bBox = vBox;
if (!style->stroke.paint.gradient->userSpace) bBox = _boundingBox(vg);

View File

@ -137,7 +137,11 @@ float svgUtilStrtof(const char *nPtr, char **endPtr)
pow10 *= 10ULL;
}
}
} else if (isspace(*iter)) { //skip if there is a space after the dot.
a = iter;
goto success;
}
val += static_cast<float>(decimalPart) / static_cast<float>(pow10);
a = iter;
}

View File

@ -304,38 +304,38 @@ bool isIgnoreUnsupportedLogElements(TVG_UNUSED const char* tagName)
bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data)
{
const char *itr = buf, *itrEnd = buf + bufLength;
char* tmpBuf = (char*)alloca(bufLength + 1);
char* tmpBuf = (char*)malloc(bufLength + 1);
if (!buf || !func) return false;
if (!buf || !func || !tmpBuf) goto error;
while (itr < itrEnd) {
const char* p = _skipWhiteSpacesAndXmlEntities(itr, itrEnd);
const char *key, *keyEnd, *value, *valueEnd;
char* tval;
if (p == itrEnd) return true;
if (p == itrEnd) goto success;
key = p;
for (keyEnd = key; keyEnd < itrEnd; keyEnd++) {
if ((*keyEnd == '=') || (isspace((unsigned char)*keyEnd))) break;
}
if (keyEnd == itrEnd) return false;
if (keyEnd == itrEnd) goto error;
if (keyEnd == key) continue;
if (*keyEnd == '=') value = keyEnd + 1;
else {
value = (const char*)memchr(keyEnd, '=', itrEnd - keyEnd);
if (!value) return false;
if (!value) goto error;
value++;
}
keyEnd = _simpleXmlUnskipXmlEntities(keyEnd, key);
value = _skipWhiteSpacesAndXmlEntities(value, itrEnd);
if (value == itrEnd) return false;
if (value == itrEnd) goto error;
if ((*value == '"') || (*value == '\'')) {
valueEnd = (const char*)memchr(value + 1, *value, itrEnd - value);
if (!valueEnd) return false;
if (!valueEnd) goto error;
value++;
} else {
valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd);
@ -364,7 +364,14 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
}
}
}
success:
free(tmpBuf);
return true;
error:
free(tmpBuf);
return false;
}

View File

@ -1,6 +1,6 @@
VERSION=0.8.3
VERSION=0.8.4
rm -rf AUTHORS inc LICENSE src *.zip
curl -L -O https://github.com/Samsung/thorvg/archive/v$VERSION.zip
curl -L -O https://github.com/thorvg/thorvg/archive/v$VERSION.zip
bsdtar --strip-components=1 -xvf *.zip
rm *.zip
rm -rf .github docs pc res test tools tvgcompat .git* *.md *.txt wasm_build.sh