thorvg: Update to 0.12.7

This commit is contained in:
Rémi Verschelde 2024-03-09 23:58:59 +01:00
parent 0ace0a1292
commit 6fa77e0f14
No known key found for this signature in database
GPG key ID: C3336907360768E1
28 changed files with 249 additions and 162 deletions

View file

@ -861,13 +861,13 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/thorvg/thorvg
- Version: 0.12.5 (9c8eeaab9629b5d241b1092a3398fe6351c259cd, 2024)
- Version: 0.12.7 (cddae9966cbb48c431ea17c262d6f48393206fd7, 2024)
- License: MIT
Files extracted from upstream source:
See `thorvg/update-thorvg.sh` for extraction instructions. Set the version
number and run the script and apply patches from the `patches` folder.
number and run the script.
## ufbx

View file

@ -10,5 +10,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
#define THORVG_VERSION_STRING "0.12.5"
#define THORVG_VERSION_STRING "0.12.7"
#endif

View file

@ -1223,6 +1223,10 @@ public:
/**
* @brief Loads a picture data directly from a file.
*
* ThorVG efficiently caches the loaded data using the specified @p path as a key.
* This means that loading the same file again will not result in duplicate operations;
* instead, ThorVG will reuse the previously loaded picture data.
*
* @param[in] path A path to the picture file.
*
* @retval Result::Success When succeed.
@ -1238,6 +1242,10 @@ public:
/**
* @brief Loads a picture data from a memory block of a given size.
*
* ThorVG efficiently caches the loaded data using the specified @p data address as a key
* when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations
* for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data.
*
* @param[in] data A pointer to a memory location where the content of the picture file is stored.
* @param[in] size The size in bytes of the memory occupied by the @p data.
* @param[in] copy Decides whether the data should be copied into the engine local buffer.
@ -1299,6 +1307,10 @@ public:
/**
* @brief Loads a raw data from a memory block with a given size.
*
* ThorVG efficiently caches the loaded data using the specified @p data address as a key
* when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations
* for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data.
*
* @param[in] paint A Tvg_Paint pointer to the picture object.
* @param[in] data A pointer to a memory location where the content of the picture raw data is stored.
* @param[in] w The width of the image @p data in pixels.
@ -1544,6 +1556,10 @@ public:
/**
* @brief Loads a scalable font data(ttf) from a file.
*
* ThorVG efficiently caches the loaded data using the specified @p path as a key.
* This means that loading the same file again will not result in duplicate operations;
* instead, ThorVG will reuse the previously loaded font data.
*
* @param[in] path The path to the font file.
*
* @retval Result::Success When succeed.

View file

@ -1,23 +0,0 @@
diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h
index e6d993a41e..5dd3d5a624 100644
--- a/thirdparty/thorvg/src/common/tvgLock.h
+++ b/thirdparty/thorvg/src/common/tvgLock.h
@@ -38,10 +38,10 @@ namespace tvg {
{
Key* key = nullptr;
- ScopedLock(Key& key)
+ ScopedLock(Key& k)
{
- key.mtx.lock();
- this->key = &key;
+ k.mtx.lock();
+ key = &k;
}
~ScopedLock()
@@ -68,3 +68,4 @@ namespace tvg {
#endif //THORVG_THREAD_SUPPORT
#endif //_TVG_LOCK_H_
+

View file

@ -90,6 +90,16 @@ struct Array
return data[idx];
}
const T* begin() const
{
return data;
}
T* begin()
{
return data;
}
T* end()
{
return data + count;

View file

@ -29,7 +29,7 @@
/* Internal Class Implementation */
/************************************************************************/
static float _lineLength(const Point& pt1, const Point& pt2)
static float _lineLengthApprox(const Point& pt1, const Point& pt2)
{
/* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
With alpha = 1, beta = 3/8, giving results with the largest error less
@ -41,6 +41,59 @@ static float _lineLength(const Point& pt1, const Point& pt2)
}
static float _lineLength(const Point& pt1, const Point& pt2)
{
Point diff = {pt2.x - pt1.x, pt2.y - pt1.y};
return sqrtf(diff.x * diff.x + diff.y * diff.y);
}
template<typename LengthFunc>
float _bezLength(const Bezier& cur, LengthFunc lineLengthFunc)
{
Bezier left, right;
auto len = lineLengthFunc(cur.start, cur.ctrl1) + lineLengthFunc(cur.ctrl1, cur.ctrl2) + lineLengthFunc(cur.ctrl2, cur.end);
auto chord = lineLengthFunc(cur.start, cur.end);
if (fabsf(len - chord) > BEZIER_EPSILON) {
tvg::bezSplit(cur, left, right);
return _bezLength(left, lineLengthFunc) + _bezLength(right, lineLengthFunc);
}
return len;
}
template<typename LengthFunc>
float _bezAt(const Bezier& bz, float at, float length, LengthFunc lineLengthFunc)
{
auto biggest = 1.0f;
auto smallest = 0.0f;
auto t = 0.5f;
//just in case to prevent an infinite loop
if (at <= 0) return 0.0f;
if (at >= length) return 1.0f;
while (true) {
auto right = bz;
Bezier left;
bezSplitLeft(right, t, left);
length = _bezLength(left, lineLengthFunc);
if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) {
break;
}
if (length < at) {
smallest = t;
t = (t + biggest) * 0.5f;
} else {
biggest = t;
t = (smallest + t) * 0.5f;
}
}
return t;
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@ -48,7 +101,7 @@ static float _lineLength(const Point& pt1, const Point& pt2)
namespace tvg
{
void bezSplit(const Bezier&cur, Bezier& left, Bezier& right)
void bezSplit(const Bezier& cur, Bezier& left, Bezier& right)
{
auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f;
left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f;
@ -72,15 +125,13 @@ void bezSplit(const Bezier&cur, Bezier& left, Bezier& right)
float bezLength(const Bezier& cur)
{
Bezier left, right;
auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end);
auto chord = _lineLength(cur.start, cur.end);
return _bezLength(cur, _lineLength);
}
if (fabsf(len - chord) > BEZIER_EPSILON) {
bezSplit(cur, left, right);
return bezLength(left) + bezLength(right);
}
return len;
float bezLengthApprox(const Bezier& cur)
{
return _bezLength(cur, _lineLengthApprox);
}
@ -110,31 +161,13 @@ void bezSplitLeft(Bezier& cur, float at, Bezier& left)
float bezAt(const Bezier& bz, float at, float length)
{
auto biggest = 1.0f;
auto smallest = 0.0f;
auto t = 0.5f;
return _bezAt(bz, at, length, _lineLength);
}
//just in case to prevent an infinite loop
if (at <= 0) return 0.0f;
if (at >= length) return 1.0f;
while (true) {
auto right = bz;
Bezier left;
bezSplitLeft(right, t, left);
length = bezLength(left);
if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) {
break;
}
if (length < at) {
smallest = t;
t = (t + biggest) * 0.5f;
} else {
biggest = t;
t = (smallest + t) * 0.5f;
}
}
return t;
float bezAtApprox(const Bezier& bz, float at, float length)
{
return _bezAt(bz, at, length, _lineLengthApprox);
}

View file

@ -44,6 +44,8 @@ void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right);
Point bezPointAt(const Bezier& bz, float t);
float bezAngleAt(const Bezier& bz, float t);
float bezLengthApprox(const Bezier& cur);
float bezAtApprox(const Bezier& bz, float at, float length);
}
#endif //_TVG_BEZIER_H_

View file

@ -68,3 +68,4 @@ namespace tvg {
#endif //THORVG_THREAD_SUPPORT
#endif //_TVG_LOCK_H_

View file

@ -31,6 +31,7 @@
#define MATH_PI 3.14159265358979323846f
#define MATH_PI2 1.57079632679489661923f
#define PATH_KAPPA 0.552284f
#define mathMin(x, y) (((x) < (y)) ? (x) : (y))
#define mathMax(x, y) (((x) > (y)) ? (x) : (y))

View file

@ -47,9 +47,6 @@ void PngLoader::run(unsigned tid)
surface.h = height;
surface.cs = ColorSpace::ABGR8888;
surface.channelSize = sizeof(uint32_t);
if (state.info_png.color.colortype == LCT_RGBA) surface.premultiplied = false;
else surface.premultiplied = true;
}

View file

@ -89,6 +89,7 @@ static char* _skipSpace(const char* str, const char* end)
static char* _copyId(const char* str)
{
if (!str) return nullptr;
if (strlen(str) == 0) return nullptr;
return strdup(str);
}
@ -377,19 +378,25 @@ static void _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* das
static char* _idFromUrl(const char* url)
{
url = _skipSpace(url, nullptr);
if ((*url) == '(') {
++url;
url = _skipSpace(url, nullptr);
auto open = strchr(url, '(');
auto close = strchr(url, ')');
if (!open || !close || open >= close) return nullptr;
open = strchr(url, '#');
if (!open || open >= close) return nullptr;
++open;
--close;
//trim the rest of the spaces if any
while (open < close && *close == ' ') --close;
//quick verification
for (auto id = open; id < close; id++) {
if (*id == ' ' || *id == '\'') return nullptr;
}
if ((*url) == '\'') ++url;
if ((*url) == '#') ++url;
int i = 0;
while (url[i] > ' ' && url[i] != ')' && url[i] != '\'') ++i;
return strDuplicate(url, i);
return strDuplicate(open, (close - open + 1));
}
@ -3494,7 +3501,7 @@ void SvgLoader::clear(bool all)
free(loaderData.svgParse);
loaderData.svgParse = nullptr;
for (auto gradient = loaderData.gradients.data; gradient < loaderData.gradients.end(); ++gradient) {
for (auto gradient = loaderData.gradients.begin(); gradient < loaderData.gradients.end(); ++gradient) {
(*gradient)->clear();
free(*gradient);
}
@ -3506,7 +3513,7 @@ void SvgLoader::clear(bool all)
if (!all) return;
for (auto p = loaderData.images.data; p < loaderData.images.end(); ++p) {
for (auto p = loaderData.images.begin(); p < loaderData.images.end(); ++p) {
free(*p);
}
loaderData.images.reset();

View file

@ -409,7 +409,7 @@ static bool _recognizeShape(SvgNode* node, Shape* shape)
}
case SvgNodeType::Polygon: {
if (node->node.polygon.pts.count < 2) break;
auto pts = node->node.polygon.pts.data;
auto pts = node->node.polygon.pts.begin();
shape->moveTo(pts[0], pts[1]);
for (pts += 2; pts < node->node.polygon.pts.end(); pts += 2) {
shape->lineTo(pts[0], pts[1]);
@ -419,7 +419,7 @@ static bool _recognizeShape(SvgNode* node, Shape* shape)
}
case SvgNodeType::Polyline: {
if (node->node.polyline.pts.count < 2) break;
auto pts = node->node.polyline.pts.data;
auto pts = node->node.polyline.pts.begin();
shape->moveTo(pts[0], pts[1]);
for (pts += 2; pts < node->node.polyline.pts.end(); pts += 2) {
shape->lineTo(pts[0], pts[1]);

View file

@ -201,7 +201,13 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr
fill->radial.fy = cy + r * (fy - cy) / dist;
fill->radial.dx = cx - fill->radial.fx;
fill->radial.dy = cy - fill->radial.fy;
fill->radial.a = fill->radial.dr * fill->radial.dr - fill->radial.dx * fill->radial.dx - fill->radial.dy * fill->radial.dy;
// Prevent loss of precision on Apple Silicon when dr=dy and dx=0 due to FMA
// https://github.com/thorvg/thorvg/issues/2014
auto dr2 = fill->radial.dr * fill->radial.dr;
auto dx2 = fill->radial.dx * fill->radial.dx;
auto dy2 = fill->radial.dy * fill->radial.dy;
fill->radial.a = dr2 - dx2 - dy2;
}
if (fill->radial.a > 0) fill->radial.invA = 1.0f / fill->radial.a;

View file

@ -50,12 +50,6 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw
auto d2 = base[1] - base[2];
auto d3 = base[0] - base[1];
if (d1 == d2 || d2 == d3) {
if (d3.small()) angleIn = angleMid = angleOut = 0;
else angleIn = angleMid = angleOut = mathAtan(d3);
return true;
}
if (d1.small()) {
if (d2.small()) {
if (d3.small()) {
@ -293,13 +287,13 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S
{
if (!outline) return false;
auto pt = outline->pts.data;
if (outline->pts.empty() || outline->cntrs.empty()) {
renderRegion.reset();
return false;
}
auto pt = outline->pts.begin();
auto xMin = pt->x;
auto xMax = pt->x;
auto yMin = pt->y;

View file

@ -182,7 +182,7 @@ struct SwShapeTask : SwTask
shapeDelOutline(&shape, mpool, tid);
//Clip Path
for (auto clip = clips.data; clip < clips.end(); ++clip) {
for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
auto clipper = static_cast<SwTask*>(*clip);
//Clip shape rle
if (shape.rle && !clipper->clip(shape.rle)) goto err;
@ -242,7 +242,7 @@ struct SwSceneTask : SwTask
rleMerge(sceneRle, clipper1->rle(), clipper2->rle());
//Unify the remained clippers
for (auto rd = scene.data + 2; rd < scene.end(); ++rd) {
for (auto rd = scene.begin() + 2; rd < scene.end(); ++rd) {
auto clipper = static_cast<SwTask*>(*rd);
rleMerge(sceneRle, sceneRle, clipper->rle());
}
@ -301,7 +301,7 @@ struct SwImageTask : SwTask
if (image.rle) {
//Clear current task memorypool here if the clippers would use the same memory pool
imageDelOutline(&image, mpool, tid);
for (auto clip = clips.data; clip < clips.end(); ++clip) {
for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
auto clipper = static_cast<SwTask*>(*clip);
if (!clipper->clip(image.rle)) goto err;
}
@ -377,7 +377,7 @@ SwRenderer::~SwRenderer()
bool SwRenderer::clear()
{
for (auto task = tasks.data; task < tasks.end(); ++task) {
for (auto task = tasks.begin(); task < tasks.end(); ++task) {
if ((*task)->disposed) {
delete(*task);
} else {
@ -451,7 +451,7 @@ bool SwRenderer::preRender()
void SwRenderer::clearCompositors()
{
//Free Composite Caches
for (auto comp = compositors.data; comp < compositors.end(); ++comp) {
for (auto comp = compositors.begin(); comp < compositors.end(); ++comp) {
free((*comp)->compositor->image.data);
delete((*comp)->compositor);
delete(*comp);
@ -467,7 +467,7 @@ bool SwRenderer::postRender()
rasterUnpremultiply(surface);
}
for (auto task = tasks.data; task < tasks.end(); ++task) {
for (auto task = tasks.begin(); task < tasks.end(); ++task) {
if ((*task)->disposed) delete(*task);
else (*task)->pushed = false;
}
@ -624,7 +624,7 @@ Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs)
auto reqChannelSize = CHANNEL_SIZE(cs);
//Use cached data
for (auto p = compositors.data; p < compositors.end(); ++p) {
for (auto p = compositors.begin(); p < compositors.end(); ++p) {
if ((*p)->compositor->valid && (*p)->compositor->image.channelSize == reqChannelSize) {
cmp = *p;
break;
@ -723,7 +723,7 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
//TODO: Failed threading them. It would be better if it's possible.
//See: https://github.com/thorvg/thorvg/issues/1409
//Guarantee composition targets get ready.
for (auto clip = clips.data; clip < clips.end(); ++clip) {
for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
static_cast<SwTask*>(*clip)->done();
}
@ -784,7 +784,7 @@ RenderData SwRenderer::prepare(const Array<RenderData>& scene, RenderData data,
//TODO: Failed threading them. It would be better if it's possible.
//See: https://github.com/thorvg/thorvg/issues/1409
//Guarantee composition targets get ready.
for (auto task = scene.data; task < scene.end(); ++task) {
for (auto task = scene.begin(); task < scene.end(); ++task) {
static_cast<SwTask*>(*task)->done();
}
return prepareCommon(task, transform, clips, opacity, flags);

View file

@ -713,7 +713,7 @@ static void _decomposeOutline(RleWorker& rw)
auto outline = rw.outline;
auto first = 0; //index of first point in contour
for (auto cntr = outline->cntrs.data; cntr < outline->cntrs.end(); ++cntr) {
for (auto cntr = outline->cntrs.begin(); cntr < outline->cntrs.end(); ++cntr) {
auto last = *cntr;
auto limit = outline->pts.data + last;
auto start = UPSCALE(outline->pts[first]);

View file

@ -37,13 +37,8 @@ struct Line
static float _lineLength(const Point& pt1, const Point& pt2)
{
/* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
With alpha = 1, beta = 3/8, giving results with the largest error less
than 7% compared to the exact value. */
Point diff = {pt2.x - pt1.x, pt2.y - pt1.y};
if (diff.x < 0) diff.x = -diff.x;
if (diff.y < 0) diff.y = -diff.y;
return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f);
return sqrtf(diff.x * diff.x + diff.y * diff.y);
}

View file

@ -377,9 +377,6 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to)
//a zero-length lineto is a no-op; avoid creating a spurious corner
if (delta.zero()) return;
//compute length of line
auto angle = mathAtan(delta);
/* The lineLength is used to determine the intersection of strokes outlines.
The scale needs to be reverted since the stroke width has not been scaled.
An alternative option is to scale the width of the stroke properly by
@ -387,6 +384,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to)
delta.x = static_cast<SwCoord>(delta.x / stroke.sx);
delta.y = static_cast<SwCoord>(delta.y / stroke.sy);
auto lineLength = mathLength(delta);
auto angle = mathAtan(delta);
delta = {static_cast<SwCoord>(stroke.width), 0};
mathRotate(delta, angle + SW_ANGLE_PI2);
@ -835,7 +833,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline)
uint32_t first = 0;
uint32_t i = 0;
for (auto cntr = outline.cntrs.data; cntr < outline.cntrs.end(); ++cntr, ++i) {
for (auto cntr = outline.cntrs.begin(); cntr < outline.cntrs.end(); ++cntr, ++i) {
auto last = *cntr; //index of last point in contour
auto limit = outline.pts.data + last;

View file

@ -20,33 +20,13 @@
* SOFTWARE.
*/
#include "tvgCommon.h"
#include "tvgFrameModule.h"
#include "tvgPaint.h"
#include "tvgPicture.h"
#include "tvgAnimation.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
struct Animation::Impl
{
Picture* picture = nullptr;
Impl()
{
picture = Picture::gen().release();
PP(picture)->ref();
}
~Impl()
{
if (PP(picture)->unref() == 0) {
delete(picture);
}
}
};
/************************************************************************/
/* External Class Implementation */
/************************************************************************/

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_ANIMATION_H_
#define _TVG_ANIMATION_H_
#include "tvgCommon.h"
#include "tvgPaint.h"
#include "tvgPicture.h"
struct Animation::Impl
{
Picture* picture = nullptr;
Impl()
{
picture = Picture::gen().release();
PP(picture)->ref();
}
~Impl()
{
if (PP(picture)->unref() == 0) {
delete(picture);
}
}
};
#endif //_TVG_ANIMATION_H_

View file

@ -32,17 +32,20 @@ struct LoadModule
INLIST_ITEM(LoadModule);
//Use either hashkey(data) or hashpath(path)
uint64_t hashkey;
char* hashpath = nullptr;
union {
uintptr_t hashkey;
char* hashpath = nullptr;
};
FileType type; //current loader file type
uint16_t sharing = 0; //reference count
bool readied = false; //read done already.
bool pathcache = false; //cached by path
LoadModule(FileType type) : type(type) {}
virtual ~LoadModule()
{
free(hashpath);
if (pathcache) free(hashpath);
}
virtual bool open(const string& path) { return false; }
@ -57,6 +60,12 @@ struct LoadModule
return true;
}
bool cached()
{
if (hashkey) return true;
return false;
}
virtual bool close()
{
if (sharing == 0) return true;

View file

@ -57,9 +57,9 @@
#include "tvgRawLoader.h"
uint64_t HASH_KEY(const char* data, uint64_t size)
uintptr_t HASH_KEY(const char* data)
{
return (((uint64_t) data) << 32) | size;
return reinterpret_cast<uintptr_t>(data);
}
/************************************************************************/
@ -219,7 +219,7 @@ static LoadModule* _findFromCache(const string& path)
auto loader = _activeLoaders.head;
while (loader) {
if (loader->hashpath && !strcmp(loader->hashpath, path.c_str())) {
if (loader->pathcache && !strcmp(loader->hashpath, path.c_str())) {
++loader->sharing;
return loader;
}
@ -237,7 +237,7 @@ static LoadModule* _findFromCache(const char* data, uint32_t size, const string&
ScopedLock lock(key);
auto loader = _activeLoaders.head;
auto key = HASH_KEY(data, size);
auto key = HASH_KEY(data);
while (loader) {
if (loader->type == type && loader->hashkey == key) {
@ -281,7 +281,7 @@ bool LoaderMgr::retrieve(LoadModule* loader)
{
if (!loader) return false;
if (loader->close()) {
{
if (loader->cached()) {
ScopedLock lock(key);
_activeLoaders.remove(loader);
}
@ -300,6 +300,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
if (auto loader = _findByPath(path)) {
if (loader->open(path)) {
loader->hashpath = strdup(path.c_str());
loader->pathcache = true;
{
ScopedLock lock(key);
_activeLoaders.back(loader);
@ -313,6 +314,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
if (auto loader = _find(static_cast<FileType>(i))) {
if (loader->open(path)) {
loader->hashpath = strdup(path.c_str());
loader->pathcache = true;
{
ScopedLock lock(key);
_activeLoaders.back(loader);
@ -338,7 +340,7 @@ LoadModule* LoaderMgr::loader(const char* key)
auto loader = _activeLoaders.head;
while (loader) {
if (loader->hashpath && strstr(loader->hashpath, key)) {
if (loader->pathcache && strstr(loader->hashpath, key)) {
++loader->sharing;
return loader;
}
@ -350,15 +352,21 @@ LoadModule* LoaderMgr::loader(const char* key)
LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy)
{
if (auto loader = _findFromCache(data, size, mimeType)) return loader;
//Note that users could use the same data pointer with the different content.
//Thus caching is only valid for shareable.
if (!copy) {
if (auto loader = _findFromCache(data, size, mimeType)) return loader;
}
//Try with the given MimeType
if (!mimeType.empty()) {
if (auto loader = _findByType(mimeType)) {
if (loader->open(data, size, copy)) {
loader->hashkey = HASH_KEY(data, size);
ScopedLock lock(key);
_activeLoaders.back(loader);
if (!copy) {
loader->hashkey = HASH_KEY(data);
ScopedLock lock(key);
_activeLoaders.back(loader);
}
return loader;
} else {
TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str());
@ -371,8 +379,8 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
auto loader = _find(static_cast<FileType>(i));
if (loader) {
if (loader->open(data, size, copy)) {
loader->hashkey = HASH_KEY(data, size);
{
if (!copy) {
loader->hashkey = HASH_KEY(data);
ScopedLock lock(key);
_activeLoaders.back(loader);
}
@ -387,14 +395,18 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy)
{
//TODO: should we check premultiplied??
if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader;
//Note that users could use the same data pointer with the different content.
//Thus caching is only valid for shareable.
if (!copy) {
//TODO: should we check premultiplied??
if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader;
}
//function is dedicated for raw images only
auto loader = new RawLoader;
if (loader->open(data, w, h, copy)) {
loader->hashkey = HASH_KEY((const char*)data, w * h);
{
if (!copy) {
loader->hashkey = HASH_KEY((const char*)data);
ScopedLock lock(key);
_activeLoaders.back(loader);
}

View file

@ -59,7 +59,7 @@ struct Surface
uint32_t w = 0, h = 0;
ColorSpace cs = ColorSpace::Unsupported;
uint8_t channelSize = 0;
bool premultiplied = 0; //Alpha-premultiplied
bool premultiplied = false; //Alpha-premultiplied
Surface()
{

View file

@ -22,6 +22,7 @@
#include "tvgCommon.h"
#include "tvgSaveModule.h"
#include "tvgPaint.h"
#ifdef THORVG_TVG_SAVER_SUPPORT
#include "tvgTvgSaver.h"
@ -123,7 +124,7 @@ Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compre
//Already on saving an other resource.
if (pImpl->saveModule) {
delete(p);
if (P(p)->refCnt == 0) delete(p);
return Result::InsufficientCondition;
}
@ -132,12 +133,12 @@ Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compre
pImpl->saveModule = saveModule;
return Result::Success;
} else {
delete(p);
if (P(p)->refCnt == 0) delete(p);
delete(saveModule);
return Result::Unknown;
}
}
delete(p);
if (P(p)->refCnt == 0) delete(p);
return Result::NonSupport;
}

View file

@ -26,7 +26,7 @@
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
constexpr auto PATH_KAPPA = 0.552284f;
/************************************************************************/
/* External Class Implementation */
@ -130,11 +130,11 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
auto ryKappa = ry * PATH_KAPPA;
pImpl->grow(6, 13);
pImpl->moveTo(cx, cy - ry);
pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
pImpl->moveTo(cx + rx, cy);
pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
pImpl->close();
return Result::Success;
@ -215,20 +215,20 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry)
pImpl->lineTo(x + w, y + h);
pImpl->lineTo(x, y + h);
pImpl->close();
//circle
//rounded rectangle or circle
} else {
auto hrx = rx * PATH_KAPPA;
auto hry = ry * PATH_KAPPA;
pImpl->grow(10, 17);
pImpl->moveTo(x + w, y + ry);
pImpl->moveTo(x + rx, y);
pImpl->lineTo(x + w - rx, y);
pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
pImpl->lineTo(x + w, y + h - ry);
pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
pImpl->lineTo(x + rx, y + h);
pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
pImpl->lineTo(x, y + ry);
pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
pImpl->lineTo(x + w - rx, y);
pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
pImpl->close();
}

View file

@ -106,7 +106,7 @@ struct Shape::Impl
{
//Path bounding size
if (rs.path.pts.count > 0 ) {
auto pts = rs.path.pts.data;
auto pts = rs.path.pts.begin();
Point min = { pts->x, pts->y };
Point max = { pts->x, pts->y };

View file

@ -123,14 +123,14 @@ struct TaskSchedulerImpl
~TaskSchedulerImpl()
{
for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) {
for (auto tq = taskQueues.begin(); tq < taskQueues.end(); ++tq) {
(*tq)->complete();
}
for (auto thread = threads.data; thread < threads.end(); ++thread) {
for (auto thread = threads.begin(); thread < threads.end(); ++thread) {
(*thread)->join();
delete(*thread);
}
for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) {
for (auto tq = taskQueues.begin(); tq < taskQueues.end(); ++tq) {
delete(*tq);
}
}

View file

@ -1,6 +1,6 @@
#!/bin/bash -e
VERSION=0.12.5
VERSION=0.12.7
cd thirdparty/thorvg/ || true
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/