Merge pull request #75508 from RedworkDE/thorvg-0.8.4

Update thorvg to 0.8.4
This commit is contained in:
Rémi Verschelde 2023-04-02 15:25:34 +02:00 committed by GitHub
commit 2a43ebd9be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 206 additions and 62 deletions

View File

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

View File

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

View File

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

View File

@ -335,6 +335,20 @@ public:
*/ */
CompositeMethod composite(const Paint** target) const noexcept; 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. * @brief Return the unique id value of the paint instance.
* *

View File

@ -76,7 +76,9 @@ struct SwShapeTask : SwTask
void run(unsigned tid) override 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; uint8_t strokeAlpha = 0;
auto visibleStroke = false; auto visibleStroke = false;
@ -98,7 +100,7 @@ struct SwShapeTask : SwTask
sdata->fillColor(nullptr, nullptr, nullptr, &alpha); sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255); alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
visibleFill = (alpha > 0 || sdata->fill()); visibleFill = (alpha > 0 || sdata->fill());
if (visibleFill || visibleStroke) { if (visibleFill || visibleStroke || usedAsClip) {
shapeReset(&shape); shapeReset(&shape);
if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
} }
@ -110,7 +112,7 @@ struct SwShapeTask : SwTask
//Fill //Fill
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
if (visibleFill) { if (visibleFill || usedAsClip) {
/* We assume that if stroke width is bigger than 2, /* We assume that if stroke width is bigger than 2,
shape outline below stroke could be full covered by stroke drawing. shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition. 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; 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->stride = stride;
surface->w = w; surface->w = w;
surface->h = h; surface->h = h;
surface->cs = cs; surface->cs = colorSpace;
vport.x = vport.y = 0; vport.x = vport.y = 0;
vport.w = surface->w; 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) bool SwRenderer::init(uint32_t threads)
{ {
if ((initEngineCnt++) > 0) return true; if ((initEngineCnt++) > 0) return true;

View File

@ -48,7 +48,7 @@ public:
bool clear() override; bool clear() override;
bool sync() 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); bool mempool(bool shared);
Compositor* target(const RenderRegion& region) override; Compositor* target(const RenderRegion& region) override;
@ -56,6 +56,8 @@ public:
bool endComposite(Compositor* cmp) override; bool endComposite(Compositor* cmp) override;
void clearCompositors(); void clearCompositors();
uint32_t colorSpace() override;
static SwRenderer* gen(); static SwRenderer* gen();
static bool init(uint32_t threads); static bool init(uint32_t threads);
static int32_t init(); 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 vw = 0;
float vh = 0; float vh = 0;
float w = 0, h = 0; //default image size float w = 0, h = 0; //default image size
uint32_t colorSpace = SwCanvas::ARGB8888;
virtual ~LoadModule() {} virtual ~LoadModule() {}
@ -48,7 +49,7 @@ public:
virtual bool read() = 0; virtual bool read() = 0;
virtual bool close() = 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; } 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) static inline bool mathIdentity(const Matrix* m)
{ {
if (!mathEqual(m->e11, 1.0f) || !mathZero(m->e12) || !mathZero(m->e13) || 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(); if (rTransform) rTransform->update();
//No rotational. //No rotation and no skewing
if (pTransform && !mathRightAngle(&pTransform->m)) return false; if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return false;
if (rTransform && !mathRightAngle(&rTransform->m)) return false; if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return false;
//Perpendicular Rectangle? //Perpendicular Rectangle?
auto pt1 = pts + 0; 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 Result Paint::opacity(uint8_t o) noexcept
{ {
if (pImpl->opacity == o) return Result::Success; if (pImpl->opacity == o) return Result::Success;

View File

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

View File

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

View File

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

View File

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

View File

@ -60,6 +60,11 @@ struct Scene::Impl
Array<Paint*> paints; Array<Paint*> paints;
uint8_t opacity; //for composition uint8_t opacity; //for composition
RenderMethod* renderer = nullptr; //keep it for explicit clear RenderMethod* renderer = nullptr; //keep it for explicit clear
Scene* scene = nullptr;
Impl(Scene* s) : scene(s)
{
}
~Impl() ~Impl()
{ {
@ -81,8 +86,14 @@ struct Scene::Impl
bool needComposition(uint32_t opacity) 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. //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 scene has several children or only scene, it may require composition.
if (paints.count > 1) return true; 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() PngLoader::PngLoader()
{ {
image = static_cast<png_imagep>(calloc(1, sizeof(png_image))); image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
@ -110,16 +128,21 @@ bool PngLoader::close()
return true; return true;
} }
unique_ptr<Surface> PngLoader::bitmap() unique_ptr<Surface> PngLoader::bitmap(uint32_t colorSpace)
{ {
if (!content) return nullptr; if (!content) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(content, w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface))); auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content); surface->buffer = content;
surface->stride = w; surface->stride = w;
surface->w = w; surface->w = w;
surface->h = h; surface->h = h;
surface->cs = SwCanvas::ARGB8888; surface->cs = colorSpace;
return unique_ptr<Surface>(surface); return unique_ptr<Surface>(surface);
} }

View File

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

View File

@ -28,6 +28,24 @@
/* Internal Class Implementation */ /* 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() void JpgLoader::clear()
{ {
jpgdDelete(decoder); jpgdDelete(decoder);
@ -110,18 +128,22 @@ bool JpgLoader::close()
} }
unique_ptr<Surface> JpgLoader::bitmap() unique_ptr<Surface> JpgLoader::bitmap(uint32_t colorSpace)
{ {
this->done(); this->done();
if (!image) return nullptr; 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))); 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->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w); surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h); surface->h = static_cast<uint32_t>(h);
surface->cs = SwCanvas::ARGB8888; surface->cs = colorSpace;
return unique_ptr<Surface>(surface); return unique_ptr<Surface>(surface);
} }

View File

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

View File

@ -28,6 +28,23 @@
/* Internal Class Implementation */ /* 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 */ /* 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; if (!content) return false;
memcpy((void*)content, data, sizeof(uint32_t) * w * h); memcpy((void*)content, data, sizeof(uint32_t) * w * h);
} }
else content = data; else content = const_cast<uint32_t*>(data);
return true; 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 (!content) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(content, w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface))); auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content); surface->buffer = content;
surface->stride = (uint32_t)w; surface->stride = static_cast<uint32_t>(w);
surface->w = (uint32_t)w; surface->w = static_cast<uint32_t>(w);
surface->h = (uint32_t)h; surface->h = static_cast<uint32_t>(h);
surface->cs = SwCanvas::ARGB8888; surface->cs = colorSpace;
return unique_ptr<Surface>(surface); return unique_ptr<Surface>(surface);
} }

View File

@ -25,7 +25,7 @@
class RawLoader : public LoadModule class RawLoader : public LoadModule
{ {
public: public:
const uint32_t* content = nullptr; uint32_t* content = nullptr;
bool copy = false; bool copy = false;
~RawLoader(); ~RawLoader();
@ -35,7 +35,7 @@ public:
bool read() override; bool read() override;
bool close() 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 (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w;
else //if other then it's radius else //if other then it's radius
{ {
float max = (float)svgParse->global.w; float max = svgParse->global.w;
if (max < svgParse->global.h) if (max < svgParse->global.h)
max = (float)svgParse->global.h; max = svgParse->global.h;
parsedValue = (parsedValue / 100.0) * max; parsedValue = (parsedValue / 100.0) * max;
} }
} }
@ -341,7 +341,7 @@ static void _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* das
++end; ++end;
//Refers to the diagonal length of the viewport. //Refers to the diagonal length of the viewport.
//https://www.w3.org/TR/SVG2/coords.html#Units //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); (*dash).array.push(parsedValue);
str = end; 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; 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); *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] == ')') { } 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 == ',') { if (red && *red == ',') {
tg = _parserColor(red + 1, &green); tg = _parseColor(red + 1, &green);
if (green && *green == ',') { if (green && *green == ',') {
tb = _parserColor(green + 1, &blue); tb = _parseColor(green + 1, &blue);
if (blue && blue[0] == ')' && blue[1] == '\0') { if (blue && blue[0] == ')' && blue[1] == '\0') {
*r = tr; *r = tr;
*g = tg; *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->vy)) {
if (_parseNumber(&value, &doc->vw)) { if (_parseNumber(&value, &doc->vw)) {
_parseNumber(&value, &doc->vh); _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")) { } else if (!strcmp(key, "preserveAspectRatio")) {
_parseAspectRatio(&value, &doc->align, &doc->meetOrSlice); _parseAspectRatio(&value, &doc->align, &doc->meetOrSlice);
} else if (!strcmp(key, "style")) { } 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 (loader->svgParse->global.w == 0) {
if (doc->w < FLT_EPSILON) loader->svgParse->global.w = 1; 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 (loader->svgParse->global.h == 0) {
if (doc->h < FLT_EPSILON) loader->svgParse->global.h = 1; 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; return loader->svgParse->node;
@ -2375,7 +2375,7 @@ static void _recalcRadialFyAttr(SvgLoaderData* loader, SvgRadialGradient* radial
static void _recalcRadialRAttr(SvgLoaderData* loader, SvgRadialGradient* radial, bool userSpace) 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 // 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) 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 (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
if (loaderData.doc) { if (loaderData.doc) {

View File

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

View File

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

View File

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

View File

@ -137,7 +137,11 @@ float svgUtilStrtof(const char *nPtr, char **endPtr)
pow10 *= 10ULL; 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); val += static_cast<float>(decimalPart) / static_cast<float>(pow10);
a = iter; 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) bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data)
{ {
const char *itr = buf, *itrEnd = buf + bufLength; 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) { while (itr < itrEnd) {
const char* p = _skipWhiteSpacesAndXmlEntities(itr, itrEnd); const char* p = _skipWhiteSpacesAndXmlEntities(itr, itrEnd);
const char *key, *keyEnd, *value, *valueEnd; const char *key, *keyEnd, *value, *valueEnd;
char* tval; char* tval;
if (p == itrEnd) return true; if (p == itrEnd) goto success;
key = p; key = p;
for (keyEnd = key; keyEnd < itrEnd; keyEnd++) { for (keyEnd = key; keyEnd < itrEnd; keyEnd++) {
if ((*keyEnd == '=') || (isspace((unsigned char)*keyEnd))) break; if ((*keyEnd == '=') || (isspace((unsigned char)*keyEnd))) break;
} }
if (keyEnd == itrEnd) return false; if (keyEnd == itrEnd) goto error;
if (keyEnd == key) continue; if (keyEnd == key) continue;
if (*keyEnd == '=') value = keyEnd + 1; if (*keyEnd == '=') value = keyEnd + 1;
else { else {
value = (const char*)memchr(keyEnd, '=', itrEnd - keyEnd); value = (const char*)memchr(keyEnd, '=', itrEnd - keyEnd);
if (!value) return false; if (!value) goto error;
value++; value++;
} }
keyEnd = _simpleXmlUnskipXmlEntities(keyEnd, key); keyEnd = _simpleXmlUnskipXmlEntities(keyEnd, key);
value = _skipWhiteSpacesAndXmlEntities(value, itrEnd); value = _skipWhiteSpacesAndXmlEntities(value, itrEnd);
if (value == itrEnd) return false; if (value == itrEnd) goto error;
if ((*value == '"') || (*value == '\'')) { if ((*value == '"') || (*value == '\'')) {
valueEnd = (const char*)memchr(value + 1, *value, itrEnd - value); valueEnd = (const char*)memchr(value + 1, *value, itrEnd - value);
if (!valueEnd) return false; if (!valueEnd) goto error;
value++; value++;
} else { } else {
valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd); valueEnd = _simpleXmlFindWhiteSpace(value, itrEnd);
@ -364,7 +364,14 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
} }
} }
} }
success:
free(tmpBuf);
return true; 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 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 bsdtar --strip-components=1 -xvf *.zip
rm *.zip rm *.zip
rm -rf .github docs pc res test tools tvgcompat .git* *.md *.txt wasm_build.sh rm -rf .github docs pc res test tools tvgcompat .git* *.md *.txt wasm_build.sh