parent
3ad046920d
commit
ab3f14d34e
|
@ -825,13 +825,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.
|
||||
|
||||
|
||||
## vhacd
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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_
|
||||
+
|
|
@ -90,6 +90,16 @@ struct Array
|
|||
return data[idx];
|
||||
}
|
||||
|
||||
const T* begin() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
T* begin()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
T* end()
|
||||
{
|
||||
return data + count;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -68,3 +68,4 @@ namespace tvg {
|
|||
#endif //THORVG_THREAD_SUPPORT
|
||||
|
||||
#endif //_TVG_LOCK_H_
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
/************************************************************************/
|
||||
|
|
|
@ -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_
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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/
|
||||
|
|
Loading…
Reference in New Issue