mirror of
https://github.com/godotengine/godot.git
synced 2024-11-24 13:12:42 +00:00
Merge pull request #91788 from akien-mga/thorvg-0.13.3
thorvg: Update to 0.13.3, add webp loader
This commit is contained in:
commit
1cf283dd26
@ -12,8 +12,8 @@ thirdparty_obj = []
|
||||
thirdparty_dir = "#thirdparty/thorvg/"
|
||||
thirdparty_sources = [
|
||||
# common
|
||||
"src/common/tvgBezier.cpp",
|
||||
"src/common/tvgCompressor.cpp",
|
||||
"src/common/tvgLines.cpp",
|
||||
"src/common/tvgMath.cpp",
|
||||
"src/common/tvgStr.cpp",
|
||||
# SVG parser
|
||||
@ -24,7 +24,9 @@ thirdparty_sources = [
|
||||
"src/loaders/svg/tvgSvgUtil.cpp",
|
||||
"src/loaders/svg/tvgXmlParser.cpp",
|
||||
"src/loaders/raw/tvgRawLoader.cpp",
|
||||
# image loaders
|
||||
"src/loaders/external_png/tvgPngLoader.cpp",
|
||||
"src/loaders/external_webp/tvgWebpLoader.cpp",
|
||||
"src/loaders/jpg/tvgJpgd.cpp",
|
||||
"src/loaders/jpg/tvgJpgLoader.cpp",
|
||||
# renderer common
|
||||
@ -74,7 +76,10 @@ env_thirdparty.Prepend(
|
||||
thirdparty_dir + "src/renderer/sw_engine",
|
||||
thirdparty_dir + "src/loaders/raw",
|
||||
thirdparty_dir + "src/loaders/external_png",
|
||||
thirdparty_dir + "src/loaders/external_webp",
|
||||
thirdparty_dir + "src/loaders/jpg",
|
||||
"#thirdparty/libpng",
|
||||
"#thirdparty/libwebp/src",
|
||||
]
|
||||
)
|
||||
|
||||
|
2
thirdparty/README.md
vendored
2
thirdparty/README.md
vendored
@ -882,7 +882,7 @@ instead of `miniz.h` as an external dependency.
|
||||
## thorvg
|
||||
|
||||
- Upstream: https://github.com/thorvg/thorvg
|
||||
- Version: 0.12.9 (afa6d8499bd49141d99d5e40a4620bd9f6bc0467, 2024)
|
||||
- Version: 0.13.3 (6235068cad8cad176ccd0cbcf82f25e985fbc258, 2024)
|
||||
- License: MIT
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
8
thirdparty/thorvg/AUTHORS
vendored
8
thirdparty/thorvg/AUTHORS
vendored
@ -1,10 +1,10 @@
|
||||
Hermet Park <hermet@lottiefiles.com>
|
||||
Hermet Park <hermet@lottiefiles.com>, <chuneon.park@samsung.com>
|
||||
Prudhvi Raj Vasireddi <prudhvi.raj@samsung.com>
|
||||
Junsu Choi <jsuya.choi@samsung.com>
|
||||
Pranay Samanta <pranay.ks@samsung.com>
|
||||
Mateusz Palkowski <m.palkowski@samsung.com>
|
||||
Subhransu Mohanty <sub.mohanty@samsung.com>
|
||||
Mira Grudzinska <veleveta@gmail.com>
|
||||
Mira Grudzinska <veleveta@gmail.com>, <m.grudzinska@samsung.com>
|
||||
Michal Szczecinski <m.szczecinsk@partner.samsung.com>
|
||||
Shinwoo Kim <cinoo.kim@samsung.com>
|
||||
Piotr Kalota <p.kalota@samsung.com>
|
||||
@ -18,10 +18,12 @@ Rémi Verschelde <rverschelde@gmail.com>
|
||||
Martin Liska <mliksa@suse.cz>
|
||||
Vincenzo Pupillo <vincenzo.pupillo@unimi.it>
|
||||
EunSik Jeong <rinechran@outlook.jp>
|
||||
Samsung Electronics Co., Ltd
|
||||
Rafał Mikrut <mikrutrafal@protonmail.com>
|
||||
Martin Capitanio <capnm@capitanio.org>
|
||||
RuiwenTang <tangruiwen1989@gmail.com>
|
||||
YouJin Lee <ol-of@naver.com>
|
||||
SergeyLebedkin <sergii@lottiefiles.com>
|
||||
Jinny You <jinny@lottiefiles.com>
|
||||
Nattu Adnan <nattu@reallynattu.com>
|
||||
Gabor Kiss-Vamosi <kisvegabor@gmail.com>
|
||||
Lorcán Mc Donagh <lorcan@lmdsp.com>
|
||||
|
3
thirdparty/thorvg/inc/config.h
vendored
3
thirdparty/thorvg/inc/config.h
vendored
@ -5,10 +5,11 @@
|
||||
#define THORVG_SVG_LOADER_SUPPORT
|
||||
#define THORVG_PNG_LOADER_SUPPORT
|
||||
#define THORVG_JPG_LOADER_SUPPORT
|
||||
#define THORVG_WEBP_LOADER_SUPPORT
|
||||
#define THORVG_THREAD_SUPPORT
|
||||
|
||||
// For internal debugging:
|
||||
//#define THORVG_LOG_ENABLED
|
||||
|
||||
#define THORVG_VERSION_STRING "0.12.10"
|
||||
#define THORVG_VERSION_STRING "0.13.3"
|
||||
#endif
|
||||
|
68
thirdparty/thorvg/inc/thorvg.h
vendored
68
thirdparty/thorvg/inc/thorvg.h
vendored
@ -1645,7 +1645,7 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Sets the target buffer for the rasterization.
|
||||
* @brief Sets the drawing target for the rasterization.
|
||||
*
|
||||
* The buffer of a desirable size should be allocated and owned by the caller.
|
||||
*
|
||||
@ -1714,13 +1714,22 @@ public:
|
||||
~GlCanvas();
|
||||
|
||||
/**
|
||||
* @brief Sets the target buffer for the rasterization.
|
||||
* @brief Sets the drawing target for rasterization.
|
||||
*
|
||||
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
|
||||
* This function specifies the drawing target where the rasterization will occur. It can target
|
||||
* a specific framebuffer object (FBO) or the main surface.
|
||||
*
|
||||
* @param[in] id The GL target ID, usually indicating the FBO ID. A value of @c 0 specifies the main surface.
|
||||
* @param[in] w The width (in pixels) of the raster image.
|
||||
* @param[in] h The height (in pixels) of the raster image.
|
||||
*
|
||||
* @warning This API is experimental and not officially supported. It may be modified or removed in future versions.
|
||||
* @warning Drawing on the main surface is currently not permitted. If the identifier (@p id) is set to @c 0, the operation will be aborted.
|
||||
*
|
||||
* @note Currently, this only allows the GL_RGBA8 color space format.
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept;
|
||||
*/
|
||||
Result target(int32_t id, uint32_t w, uint32_t h) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Creates a new GlCanvas object.
|
||||
@ -1828,7 +1837,7 @@ public:
|
||||
*
|
||||
* This class supports the display and control of animation frames.
|
||||
*
|
||||
* @note Experimental API
|
||||
* @since 0.13
|
||||
*/
|
||||
|
||||
class TVG_API Animation
|
||||
@ -1845,9 +1854,11 @@ public:
|
||||
* @retval Result::InsufficientCondition if the given @p no is the same as the current frame value.
|
||||
* @retval Result::NonSupport The current Picture data does not support animations.
|
||||
*
|
||||
* @note For efficiency, ThorVG ignores updates to the new frame value if the difference from the current frame value
|
||||
* is less than 0.001. In such cases, it returns @c Result::InsufficientCondition.
|
||||
*
|
||||
* @see totalFrame()
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result frame(float no) noexcept;
|
||||
|
||||
@ -1862,7 +1873,6 @@ public:
|
||||
*
|
||||
* @warning The picture instance is owned by Animation. It should not be deleted manually.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Picture* picture() const noexcept;
|
||||
|
||||
@ -1876,7 +1886,6 @@ public:
|
||||
* @see Animation::frame(float no)
|
||||
* @see Animation::totalFrame()
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
float curFrame() const noexcept;
|
||||
|
||||
@ -1888,7 +1897,6 @@ public:
|
||||
* @note Frame numbering starts from 0.
|
||||
* @note If the Picture is not properly configured, this function will return 0.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
float totalFrame() const noexcept;
|
||||
|
||||
@ -1899,16 +1907,52 @@ public:
|
||||
*
|
||||
* @note If the Picture is not properly configured, this function will return 0.
|
||||
*
|
||||
* @% Experimental API
|
||||
*/
|
||||
float duration() const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Specifies the playback segment of the animation.
|
||||
*
|
||||
* The set segment is designated as the play area of the animation.
|
||||
* This is useful for playing a specific segment within the entire animation.
|
||||
* After setting, the number of animation frames and the playback time are calculated
|
||||
* by mapping the playback segment as the entire range.
|
||||
*
|
||||
* @param[in] begin segment start.
|
||||
* @param[in] end segment end.
|
||||
*
|
||||
* @retval Result::Success When succeed.
|
||||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||
* @retval Result::InvalidArguments When the given parameter is invalid.
|
||||
* @retval Result::NonSupport When it's not animatable.
|
||||
*
|
||||
* @note Range from 0.0~1.0
|
||||
* @note If a marker has been specified, its range will be disregarded.
|
||||
* @see LottieAnimation::segment(const char* marker)
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result segment(float begin, float end) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Gets the current segment.
|
||||
*
|
||||
* @param[out] begin segment start.
|
||||
* @param[out] end segment end.
|
||||
*
|
||||
* @retval Result::Success When succeed.
|
||||
* @retval Result::InsufficientCondition In case the animation is not loaded.
|
||||
* @retval Result::InvalidArguments When the given parameter is invalid.
|
||||
* @retval Result::NonSupport When it's not animatable.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result segment(float* begin, float* end = nullptr) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Creates a new Animation object.
|
||||
*
|
||||
* @return A new Animation object.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
static std::unique_ptr<Animation> gen() noexcept;
|
||||
|
||||
|
1
thirdparty/thorvg/src/common/tvgArray.h
vendored
1
thirdparty/thorvg/src/common/tvgArray.h
vendored
@ -61,6 +61,7 @@ struct Array
|
||||
|
||||
void push(Array<T>& rhs)
|
||||
{
|
||||
if (rhs.count == 0) return;
|
||||
grow(rhs.count);
|
||||
memcpy(data + count, rhs.data, rhs.count * sizeof(T));
|
||||
count += rhs.count;
|
||||
|
@ -458,11 +458,11 @@ size_t b64Decode(const char* encoded, const size_t len, char** decoded)
|
||||
auto value2 = B64_INDEX[(size_t)encoded[1]];
|
||||
output[idx++] = (value1 << 2) + ((value2 & 0x30) >> 4);
|
||||
|
||||
if (!encoded[2] || encoded[2] == '=' || encoded[2] == '.') break;
|
||||
if (!encoded[2] || encoded[3] < 0 || encoded[2] == '=' || encoded[2] == '.') break;
|
||||
auto value3 = B64_INDEX[(size_t)encoded[2]];
|
||||
output[idx++] = ((value2 & 0x0f) << 4) + ((value3 & 0x3c) >> 2);
|
||||
|
||||
if (!encoded[3] || encoded[3] == '=' || encoded[3] == '.') break;
|
||||
if (!encoded[3] || encoded[3] < 0 || encoded[3] == '=' || encoded[3] == '.') break;
|
||||
auto value4 = B64_INDEX[(size_t)encoded[3]];
|
||||
output[idx++] = ((value3 & 0x03) << 6) + value4;
|
||||
encoded += 4;
|
||||
|
@ -21,9 +21,9 @@
|
||||
*/
|
||||
|
||||
#include "tvgMath.h"
|
||||
#include "tvgBezier.h"
|
||||
#include "tvgLines.h"
|
||||
|
||||
#define BEZIER_EPSILON 1e-4f
|
||||
#define BEZIER_EPSILON 1e-2f
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
@ -101,6 +101,25 @@ float _bezAt(const Bezier& bz, float at, float length, LengthFunc lineLengthFunc
|
||||
namespace tvg
|
||||
{
|
||||
|
||||
float lineLength(const Point& pt1, const Point& pt2)
|
||||
{
|
||||
return _lineLength(pt1, pt2);
|
||||
}
|
||||
|
||||
|
||||
void lineSplitAt(const Line& cur, float at, Line& left, Line& right)
|
||||
{
|
||||
auto len = lineLength(cur.pt1, cur.pt2);
|
||||
auto dx = ((cur.pt2.x - cur.pt1.x) / len) * at;
|
||||
auto dy = ((cur.pt2.y - cur.pt1.y) / len) * at;
|
||||
left.pt1 = cur.pt1;
|
||||
left.pt2.x = left.pt1.x + dx;
|
||||
left.pt2.y = left.pt1.y + dy;
|
||||
right.pt1 = left.pt2;
|
||||
right.pt2 = cur.pt2;
|
||||
}
|
||||
|
||||
|
||||
void bezSplit(const Bezier& cur, Bezier& left, Bezier& right)
|
||||
{
|
||||
auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f;
|
||||
@ -219,7 +238,7 @@ float bezAngleAt(const Bezier& bz, float t)
|
||||
pt.x *= 3;
|
||||
pt.y *= 3;
|
||||
|
||||
return atan2(pt.x, pt.y) * 180.0f / 3.141592f;
|
||||
return mathRad2Deg(atan2(pt.x, pt.y));
|
||||
}
|
||||
|
||||
|
@ -20,14 +20,24 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _TVG_BEZIER_H_
|
||||
#define _TVG_BEZIER_H_
|
||||
#ifndef _TVG_LINES_H_
|
||||
#define _TVG_LINES_H_
|
||||
|
||||
#include "tvgCommon.h"
|
||||
|
||||
namespace tvg
|
||||
{
|
||||
|
||||
struct Line
|
||||
{
|
||||
Point pt1;
|
||||
Point pt2;
|
||||
};
|
||||
|
||||
float lineLength(const Point& pt1, const Point& pt2);
|
||||
void lineSplitAt(const Line& cur, float at, Line& left, Line& right);
|
||||
|
||||
|
||||
struct Bezier
|
||||
{
|
||||
Point start;
|
||||
@ -48,4 +58,4 @@ float bezLengthApprox(const Bezier& cur);
|
||||
float bezAtApprox(const Bezier& bz, float at, float length);
|
||||
}
|
||||
|
||||
#endif //_TVG_BEZIER_H_
|
||||
#endif //_TVG_LINES_H_
|
12
thirdparty/thorvg/src/common/tvgMath.h
vendored
12
thirdparty/thorvg/src/common/tvgMath.h
vendored
@ -44,6 +44,18 @@ bool mathIdentity(const Matrix* m);
|
||||
void mathMultiply(Point* pt, const Matrix* transform);
|
||||
|
||||
|
||||
static inline float mathDeg2Rad(float degree)
|
||||
{
|
||||
return degree * (MATH_PI / 180.0f);
|
||||
}
|
||||
|
||||
|
||||
static inline float mathRad2Deg(float radian)
|
||||
{
|
||||
return radian * (180.0f / MATH_PI);
|
||||
}
|
||||
|
||||
|
||||
static inline bool mathZero(float a)
|
||||
{
|
||||
return (fabsf(a) < FLT_EPSILON) ? true : false;
|
||||
|
3
thirdparty/thorvg/src/common/tvgStr.cpp
vendored
3
thirdparty/thorvg/src/common/tvgStr.cpp
vendored
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <memory.h>
|
||||
#include "tvgMath.h"
|
||||
@ -197,6 +198,8 @@ float strToFloat(const char *nPtr, char **endPtr)
|
||||
|
||||
success:
|
||||
if (endPtr) *endPtr = (char *)(a);
|
||||
if (!std::isfinite(val)) return 0.0f;
|
||||
|
||||
return minus * val;
|
||||
|
||||
error:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
|
||||
* Copyright (c) 2023 - 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
|
||||
@ -21,8 +21,9 @@
|
||||
*/
|
||||
|
||||
#include <memory.h>
|
||||
#include "tvgLoader.h"
|
||||
#include "tvgPngLoader.h"
|
||||
#include <webp/decode.h>
|
||||
|
||||
#include "tvgWebpLoader.h"
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
@ -30,23 +31,17 @@
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
void PngLoader::run(unsigned tid)
|
||||
void WebpLoader::run(unsigned tid)
|
||||
{
|
||||
auto width = static_cast<unsigned>(w);
|
||||
auto height = static_cast<unsigned>(h);
|
||||
|
||||
state.info_raw.colortype = LCT_RGBA; //request this image format
|
||||
|
||||
if (lodepng_decode(&surface.buf8, &width, &height, &state, data, size)) {
|
||||
TVGERR("PNG", "Failed to decode image");
|
||||
}
|
||||
|
||||
//setup the surface
|
||||
surface.stride = width;
|
||||
surface.w = width;
|
||||
surface.h = height;
|
||||
surface.cs = ColorSpace::ABGR8888;
|
||||
//TODO: acquire the current colorspace format & pre-multiplied alpha image.
|
||||
surface.buf8 = WebPDecodeBGRA(data, size, nullptr, nullptr);
|
||||
surface.stride = (uint32_t)w;
|
||||
surface.w = (uint32_t)w;
|
||||
surface.h = (uint32_t)h;
|
||||
surface.channelSize = sizeof(uint32_t);
|
||||
surface.cs = ColorSpace::ARGB8888;
|
||||
surface.premultiplied = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -54,62 +49,58 @@ void PngLoader::run(unsigned tid)
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
PngLoader::PngLoader() : ImageLoader(FileType::Png)
|
||||
WebpLoader::WebpLoader() : ImageLoader(FileType::Webp)
|
||||
{
|
||||
lodepng_state_init(&state);
|
||||
}
|
||||
|
||||
|
||||
PngLoader::~PngLoader()
|
||||
WebpLoader::~WebpLoader()
|
||||
{
|
||||
this->done();
|
||||
|
||||
if (freeData) free(data);
|
||||
free(surface.buf8);
|
||||
lodepng_state_cleanup(&state);
|
||||
data = nullptr;
|
||||
size = 0;
|
||||
freeData = false;
|
||||
WebPFree(surface.buf8);
|
||||
}
|
||||
|
||||
|
||||
bool PngLoader::open(const string& path)
|
||||
bool WebpLoader::open(const string& path)
|
||||
{
|
||||
auto pngFile = fopen(path.c_str(), "rb");
|
||||
if (!pngFile) return false;
|
||||
auto webpFile = fopen(path.c_str(), "rb");
|
||||
if (!webpFile) return false;
|
||||
|
||||
auto ret = false;
|
||||
|
||||
//determine size
|
||||
if (fseek(pngFile, 0, SEEK_END) < 0) goto finalize;
|
||||
if (((size = ftell(pngFile)) < 1)) goto finalize;
|
||||
if (fseek(pngFile, 0, SEEK_SET)) goto finalize;
|
||||
if (fseek(webpFile, 0, SEEK_END) < 0) goto finalize;
|
||||
if (((size = ftell(webpFile)) < 1)) goto finalize;
|
||||
if (fseek(webpFile, 0, SEEK_SET)) goto finalize;
|
||||
|
||||
data = (unsigned char *) malloc(size);
|
||||
if (!data) goto finalize;
|
||||
|
||||
freeData = true;
|
||||
|
||||
if (fread(data, size, 1, pngFile) < 1) goto finalize;
|
||||
if (fread(data, size, 1, webpFile) < 1) goto finalize;
|
||||
|
||||
lodepng_state_init(&state);
|
||||
|
||||
unsigned int width, height;
|
||||
if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto finalize;
|
||||
int width, height;
|
||||
if (!WebPGetInfo(data, size, &width, &height)) goto finalize;
|
||||
|
||||
w = static_cast<float>(width);
|
||||
h = static_cast<float>(height);
|
||||
|
||||
ret = true;
|
||||
|
||||
goto finalize;
|
||||
|
||||
finalize:
|
||||
fclose(pngFile);
|
||||
fclose(webpFile);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PngLoader::open(const char* data, uint32_t size, bool copy)
|
||||
bool WebpLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
unsigned int width, height;
|
||||
if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false;
|
||||
|
||||
if (copy) {
|
||||
this->data = (unsigned char *) malloc(size);
|
||||
if (!this->data) return false;
|
||||
@ -120,28 +111,32 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
|
||||
freeData = false;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
if (!WebPGetInfo(this->data, size, &width, &height)) return false;
|
||||
|
||||
w = static_cast<float>(width);
|
||||
h = static_cast<float>(height);
|
||||
surface.cs = ColorSpace::ARGB8888;
|
||||
this->size = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PngLoader::read()
|
||||
bool WebpLoader::read()
|
||||
{
|
||||
if (!data || w == 0 || h == 0) return false;
|
||||
|
||||
if (!LoadModule::read()) return true;
|
||||
|
||||
if (!data || w == 0 || h == 0) return false;
|
||||
|
||||
TaskScheduler::request(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Surface* PngLoader::bitmap()
|
||||
Surface* WebpLoader::bitmap()
|
||||
{
|
||||
this->done();
|
||||
|
||||
return ImageLoader::bitmap();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
|
||||
* Copyright (c) 2023 - 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
|
||||
@ -20,32 +20,30 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _TVG_PNG_LOADER_H_
|
||||
#define _TVG_PNG_LOADER_H_
|
||||
#ifndef _TVG_WEBP_LOADER_H_
|
||||
#define _TVG_WEBP_LOADER_H_
|
||||
|
||||
#include "tvgLodePng.h"
|
||||
#include "tvgLoader.h"
|
||||
#include "tvgTaskScheduler.h"
|
||||
|
||||
|
||||
class PngLoader : public ImageLoader, public Task
|
||||
class WebpLoader : public ImageLoader, public Task
|
||||
{
|
||||
private:
|
||||
LodePNGState state;
|
||||
unsigned char* data = nullptr;
|
||||
unsigned long size = 0;
|
||||
bool freeData = false;
|
||||
|
||||
void run(unsigned tid) override;
|
||||
|
||||
public:
|
||||
PngLoader();
|
||||
~PngLoader();
|
||||
WebpLoader();
|
||||
~WebpLoader();
|
||||
|
||||
bool open(const string& path) override;
|
||||
bool open(const char* data, uint32_t size, bool copy) override;
|
||||
bool read() override;
|
||||
|
||||
Surface* bitmap() override;
|
||||
|
||||
private:
|
||||
void run(unsigned tid) override;
|
||||
|
||||
unsigned char* data = nullptr;
|
||||
unsigned long size = 0;
|
||||
bool freeData = false;
|
||||
};
|
||||
|
||||
#endif //_TVG_PNG_LOADER_H_
|
||||
#endif //_TVG_WEBP_LOADER_H_
|
2628
thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp
vendored
2628
thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp
vendored
File diff suppressed because it is too large
Load Diff
174
thirdparty/thorvg/src/loaders/png/tvgLodePng.h
vendored
174
thirdparty/thorvg/src/loaders/png/tvgLodePng.h
vendored
@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020 - 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
LodePNG version 20200306
|
||||
|
||||
Copyright (c) 2005-2020 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#ifndef _TVG_LODEPNG_H_
|
||||
#define _TVG_LODEPNG_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*The PNG color types (also used for raw image).*/
|
||||
enum LodePNGColorType
|
||||
{
|
||||
LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/
|
||||
LCT_RGB = 2, /*RGB: 8,16 bit*/
|
||||
LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/
|
||||
LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/
|
||||
LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/
|
||||
/*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid
|
||||
byte value from 0 to 255 that could be present in an invalid PNG file header. Do
|
||||
not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use
|
||||
the valid color type names above, or numeric values like 1 or 7 when checking for
|
||||
particular disallowed color type byte values, or cast to integer to print it.*/
|
||||
LCT_MAX_OCTET_VALUE = 255
|
||||
};
|
||||
|
||||
/*Settings for zlib decompression*/
|
||||
struct LodePNGDecompressSettings
|
||||
{
|
||||
/* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */
|
||||
unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/
|
||||
unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/
|
||||
|
||||
/*use custom zlib decoder instead of built in one (default: null)*/
|
||||
unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*);
|
||||
/*use custom deflate decoder instead of built in one (default: null) if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate)*/
|
||||
unsigned (*custom_inflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*);
|
||||
|
||||
const void* custom_context; /*optional custom settings for custom functions*/
|
||||
};
|
||||
|
||||
/*
|
||||
Color mode of an image. Contains all information required to decode the pixel
|
||||
bits to RGBA colors. This information is the same as used in the PNG file
|
||||
format, and is used both for PNG and raw image data in LodePNG.
|
||||
*/
|
||||
struct LodePNGColorMode
|
||||
{
|
||||
/*header (IHDR)*/
|
||||
LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/
|
||||
unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/
|
||||
|
||||
/*
|
||||
palette (PLTE and tRNS)
|
||||
|
||||
Dynamically allocated with the colors of the palette, including alpha.
|
||||
This field may not be allocated directly, use lodepng_color_mode_init first,
|
||||
then lodepng_palette_add per color to correctly initialize it (to ensure size
|
||||
of exactly 1024 bytes).
|
||||
|
||||
The alpha channels must be set as well, set them to 255 for opaque images.
|
||||
|
||||
When decoding, by default you can ignore this palette, since LodePNG already
|
||||
fills the palette colors in the pixels of the raw RGBA output.
|
||||
|
||||
The palette is only supported for color type 3.
|
||||
*/
|
||||
unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/
|
||||
size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/
|
||||
|
||||
/*
|
||||
transparent color key (tRNS)
|
||||
|
||||
This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit.
|
||||
For grayscale PNGs, r, g and b will all 3 be set to the same.
|
||||
|
||||
When decoding, by default you can ignore this information, since LodePNG sets
|
||||
pixels with this key to transparent already in the raw RGBA output.
|
||||
|
||||
The color key is only supported for color types 0 and 2.
|
||||
*/
|
||||
unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/
|
||||
unsigned key_r; /*red/grayscale component of color key*/
|
||||
unsigned key_g; /*green component of color key*/
|
||||
unsigned key_b; /*blue component of color key*/
|
||||
};
|
||||
|
||||
/*Information about the PNG image, except pixels, width and height.*/
|
||||
struct LodePNGInfo
|
||||
{
|
||||
/*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
|
||||
unsigned compression_method;/*compression method of the original file. Always 0.*/
|
||||
unsigned filter_method; /*filter method of the original file*/
|
||||
unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/
|
||||
LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/
|
||||
};
|
||||
|
||||
/*
|
||||
Settings for the decoder. This contains settings for the PNG and the Zlib
|
||||
decoder, but not the Info settings from the Info structs.
|
||||
*/
|
||||
struct LodePNGDecoderSettings
|
||||
{
|
||||
LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/
|
||||
|
||||
/* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */
|
||||
unsigned ignore_crc; /*ignore CRC checksums*/
|
||||
unsigned ignore_critical; /*ignore unknown critical chunks*/
|
||||
unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/
|
||||
/* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable
|
||||
errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some
|
||||
strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters
|
||||
in string keys, etc... */
|
||||
|
||||
unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
|
||||
};
|
||||
|
||||
/*The settings, state and information for extended encoding and decoding.*/
|
||||
struct LodePNGState
|
||||
{
|
||||
LodePNGDecoderSettings decoder; /*the decoding settings*/
|
||||
LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/
|
||||
LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/
|
||||
unsigned error;
|
||||
};
|
||||
|
||||
void lodepng_state_init(LodePNGState* state);
|
||||
void lodepng_state_cleanup(LodePNGState* state);
|
||||
unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize);
|
||||
unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize);
|
||||
|
||||
#endif //_TVG_LODEPNG_H_
|
@ -49,6 +49,22 @@ static void _copyStyle(SvgStyleProperty* to, const SvgStyleProperty* from)
|
||||
to->flagsImportance = (to->flagsImportance | SvgStyleFlags::Color);
|
||||
}
|
||||
}
|
||||
if (((from->flags & SvgStyleFlags::PaintOrder) && !(to->flags & SvgStyleFlags::PaintOrder)) ||
|
||||
_isImportanceApplicable(to->flagsImportance, from->flagsImportance, SvgStyleFlags::PaintOrder)) {
|
||||
to->paintOrder = from->paintOrder;
|
||||
to->flags = (to->flags | SvgStyleFlags::PaintOrder);
|
||||
if (from->flagsImportance & SvgStyleFlags::PaintOrder) {
|
||||
to->flagsImportance = (to->flagsImportance | SvgStyleFlags::PaintOrder);
|
||||
}
|
||||
}
|
||||
if (((from->flags & SvgStyleFlags::Display) && !(to->flags & SvgStyleFlags::Display)) ||
|
||||
_isImportanceApplicable(to->flagsImportance, from->flagsImportance, SvgStyleFlags::Display)) {
|
||||
to->display = from->display;
|
||||
to->flags = (to->flags | SvgStyleFlags::Display);
|
||||
if (from->flagsImportance & SvgStyleFlags::Display) {
|
||||
to->flagsImportance = (to->flagsImportance | SvgStyleFlags::Display);
|
||||
}
|
||||
}
|
||||
//Fill
|
||||
if (((from->fill.flags & SvgFillFlags::Paint) && !(to->flags & SvgStyleFlags::Fill)) ||
|
||||
_isImportanceApplicable(to->flagsImportance, from->flagsImportance, SvgStyleFlags::Fill)) {
|
||||
|
202
thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
vendored
202
thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
vendored
@ -103,15 +103,19 @@ static const char* _skipComma(const char* content)
|
||||
}
|
||||
|
||||
|
||||
static bool _parseNumber(const char** content, float* number)
|
||||
static bool _parseNumber(const char** content, const char** end, float* number)
|
||||
{
|
||||
char* end = nullptr;
|
||||
const char* _end = end ? *end : nullptr;
|
||||
|
||||
*number = strToFloat(*content, &end);
|
||||
*number = strToFloat(*content, (char**)&_end);
|
||||
//If the start of string is not number
|
||||
if ((*content) == end) return false;
|
||||
if ((*content) == _end) {
|
||||
if (end) *end = _end;
|
||||
return false;
|
||||
}
|
||||
//Skip comma if any
|
||||
*content = _skipComma(end);
|
||||
*content = _skipComma(_end);
|
||||
if (end) *end = _end;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -576,7 +580,82 @@ static constexpr struct
|
||||
};
|
||||
|
||||
|
||||
static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** ref)
|
||||
static bool _hslToRgb(float hue, float satuation, float brightness, uint8_t* red, uint8_t* green, uint8_t* blue)
|
||||
{
|
||||
if (!red || !green || !blue) return false;
|
||||
|
||||
float sv, vsf, f, p, q, t, v;
|
||||
float _red = 0, _green = 0, _blue = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
if (mathZero(satuation)) _red = _green = _blue = brightness;
|
||||
else {
|
||||
if (mathEqual(hue, 360.0)) hue = 0.0f;
|
||||
hue /= 60.0f;
|
||||
|
||||
v = (brightness <= 0.5f) ? (brightness * (1.0f + satuation)) : (brightness + satuation - (brightness * satuation));
|
||||
p = brightness + brightness - v;
|
||||
|
||||
if (!mathZero(v)) sv = (v - p) / v;
|
||||
else sv = 0;
|
||||
|
||||
i = static_cast<uint8_t>(hue);
|
||||
f = hue - i;
|
||||
|
||||
vsf = v * sv * f;
|
||||
|
||||
t = p + vsf;
|
||||
q = v - vsf;
|
||||
|
||||
switch (i) {
|
||||
case 0: {
|
||||
_red = v;
|
||||
_green = t;
|
||||
_blue = p;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
_red = q;
|
||||
_green = v;
|
||||
_blue = p;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
_red = p;
|
||||
_green = v;
|
||||
_blue = t;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
_red = p;
|
||||
_green = q;
|
||||
_blue = v;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
_red = t;
|
||||
_green = p;
|
||||
_blue = v;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
_red = v;
|
||||
_green = p;
|
||||
_blue = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*red = static_cast<uint8_t>(roundf(_red * 255.0f));
|
||||
*green = static_cast<uint8_t>(roundf(_green * 255.0f));
|
||||
*blue = static_cast<uint8_t>(roundf(_blue * 255.0f));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** ref)
|
||||
{
|
||||
unsigned int len = strlen(str);
|
||||
char *red, *green, *blue;
|
||||
@ -596,6 +675,7 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
|
||||
tmp[1] = str[3];
|
||||
*b = strtol(tmp, nullptr, 16);
|
||||
}
|
||||
return true;
|
||||
} else if (len == 7 && str[0] == '#') {
|
||||
if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3]) && isxdigit(str[4]) && isxdigit(str[5]) && isxdigit(str[6])) {
|
||||
char tmp[3] = { '\0', '\0', '\0' };
|
||||
@ -609,6 +689,7 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
|
||||
tmp[1] = str[6];
|
||||
*b = strtol(tmp, nullptr, 16);
|
||||
}
|
||||
return true;
|
||||
} 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 = _parseColor(str + 4, &red);
|
||||
if (red && *red == ',') {
|
||||
@ -622,9 +703,35 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (ref && len >= 3 && !strncmp(str, "url", 3)) {
|
||||
if (*ref) free(*ref);
|
||||
*ref = _idFromUrl((const char*)(str + 3));
|
||||
return true;
|
||||
} else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') {
|
||||
float_t th, ts, tb;
|
||||
const char *content, *hue, *satuation, *brightness;
|
||||
content = str + 4;
|
||||
content = _skipSpace(content, nullptr);
|
||||
if (_parseNumber(&content, &hue, &th) && hue) {
|
||||
th = float(uint32_t(th) % 360);
|
||||
hue = _skipSpace(hue, nullptr);
|
||||
hue = (char*)_skipComma(hue);
|
||||
hue = _skipSpace(hue, nullptr);
|
||||
if (_parseNumber(&hue, &satuation, &ts) && satuation && *satuation == '%') {
|
||||
ts /= 100.0f;
|
||||
satuation = _skipSpace(satuation + 1, nullptr);
|
||||
satuation = (char*)_skipComma(satuation);
|
||||
satuation = _skipSpace(satuation, nullptr);
|
||||
if (_parseNumber(&satuation, &brightness, &tb) && brightness && *brightness == '%') {
|
||||
tb /= 100.0f;
|
||||
brightness = _skipSpace(brightness + 1, nullptr);
|
||||
if (brightness && brightness[0] == ')' && brightness[1] == '\0') {
|
||||
return _hslToRgb(th, ts, tb, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Handle named color
|
||||
for (unsigned int i = 0; i < (sizeof(colors) / sizeof(colors[0])); i++) {
|
||||
@ -632,10 +739,11 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
|
||||
*r = (((uint8_t*)(&(colors[i].value)))[2]);
|
||||
*g = (((uint8_t*)(&(colors[i].value)))[1]);
|
||||
*b = (((uint8_t*)(&(colors[i].value)))[0]);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -745,8 +853,8 @@ static Matrix* _parseTransformationMatrix(const char* value)
|
||||
//Transform to signed.
|
||||
points[0] = fmodf(points[0], 360.0f);
|
||||
if (points[0] < 0) points[0] += 360.0f;
|
||||
auto c = cosf(points[0] * (MATH_PI / 180.0f));
|
||||
auto s = sinf(points[0] * (MATH_PI / 180.0f));
|
||||
auto c = cosf(mathDeg2Rad(points[0]));
|
||||
auto s = sinf(mathDeg2Rad(points[0]));
|
||||
if (ptCount == 1) {
|
||||
Matrix tmp = { c, -s, 0, s, c, 0, 0, 0, 1 };
|
||||
*matrix = mathMultiply(matrix, &tmp);
|
||||
@ -769,12 +877,12 @@ static Matrix* _parseTransformationMatrix(const char* value)
|
||||
*matrix = mathMultiply(matrix, &tmp);
|
||||
} else if (state == MatrixState::SkewX) {
|
||||
if (ptCount != 1) goto error;
|
||||
auto deg = tanf(points[0] * (MATH_PI / 180.0f));
|
||||
auto deg = tanf(mathDeg2Rad(points[0]));
|
||||
Matrix tmp = { 1, deg, 0, 0, 1, 0, 0, 0, 1 };
|
||||
*matrix = mathMultiply(matrix, &tmp);
|
||||
} else if (state == MatrixState::SkewY) {
|
||||
if (ptCount != 1) goto error;
|
||||
auto deg = tanf(points[0] * (MATH_PI / 180.0f));
|
||||
auto deg = tanf(mathDeg2Rad(points[0]));
|
||||
Matrix tmp = { 1, 0, 0, deg, 1, 0, 0, 0, 1 };
|
||||
*matrix = mathMultiply(matrix, &tmp);
|
||||
}
|
||||
@ -854,10 +962,10 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
|
||||
doc->viewFlag = (doc->viewFlag | SvgViewFlag::Height);
|
||||
}
|
||||
} else if (!strcmp(key, "viewBox")) {
|
||||
if (_parseNumber(&value, &doc->vx)) {
|
||||
if (_parseNumber(&value, &doc->vy)) {
|
||||
if (_parseNumber(&value, &doc->vw)) {
|
||||
if (_parseNumber(&value, &doc->vh)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vx)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vy)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vw)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vh)) {
|
||||
doc->viewFlag = (doc->viewFlag | SvgViewFlag::Viewbox);
|
||||
loader->svgParse->global.h = doc->vh;
|
||||
}
|
||||
@ -898,20 +1006,21 @@ static void _handlePaintAttr(SvgPaint* paint, const char* value)
|
||||
paint->none = true;
|
||||
return;
|
||||
}
|
||||
paint->none = false;
|
||||
if (!strcmp(value, "currentColor")) {
|
||||
paint->curColor = true;
|
||||
paint->none = false;
|
||||
return;
|
||||
}
|
||||
_toColor(value, &paint->color.r, &paint->color.g, &paint->color.b, &paint->url);
|
||||
if (_toColor(value, &paint->color.r, &paint->color.g, &paint->color.b, &paint->url)) paint->none = false;
|
||||
}
|
||||
|
||||
|
||||
static void _handleColorAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
|
||||
{
|
||||
SvgStyleProperty* style = node->style;
|
||||
style->curColorSet = true;
|
||||
_toColor(value, &style->color.r, &style->color.g, &style->color.b, nullptr);
|
||||
if (_toColor(value, &style->color.r, &style->color.g, &style->color.b, nullptr)) {
|
||||
style->curColorSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -995,6 +1104,7 @@ static void _handleFillRuleAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
|
||||
|
||||
static void _handleOpacityAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
|
||||
{
|
||||
node->style->flags = (node->style->flags | SvgStyleFlags::Opacity);
|
||||
node->style->opacity = _toOpacity(value);
|
||||
}
|
||||
|
||||
@ -1046,8 +1156,9 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
|
||||
// The default is "inline" which means visible and "none" means invisible.
|
||||
// Depending on the type of node, additional functionality may be required.
|
||||
// refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display
|
||||
if (!strcmp(value, "none")) node->display = false;
|
||||
else node->display = true;
|
||||
node->style->flags = (node->style->flags | SvgStyleFlags::Display);
|
||||
if (!strcmp(value, "none")) node->style->display = false;
|
||||
else node->style->display = true;
|
||||
}
|
||||
|
||||
|
||||
@ -1267,8 +1378,8 @@ static bool _attrParseSymbolNode(void* data, const char* key, const char* value)
|
||||
SvgSymbolNode* symbol = &(node->node.symbol);
|
||||
|
||||
if (!strcmp(key, "viewBox")) {
|
||||
if (!_parseNumber(&value, &symbol->vx) || !_parseNumber(&value, &symbol->vy)) return false;
|
||||
if (!_parseNumber(&value, &symbol->vw) || !_parseNumber(&value, &symbol->vh)) return false;
|
||||
if (!_parseNumber(&value, nullptr, &symbol->vx) || !_parseNumber(&value, nullptr, &symbol->vy)) return false;
|
||||
if (!_parseNumber(&value, nullptr, &symbol->vw) || !_parseNumber(&value, nullptr, &symbol->vh)) return false;
|
||||
symbol->hasViewBox = true;
|
||||
} else if (!strcmp(key, "width")) {
|
||||
symbol->w = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
|
||||
@ -1332,7 +1443,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type)
|
||||
node->style->paintOrder = _toPaintOrder("fill stroke");
|
||||
|
||||
//Default display is true("inline").
|
||||
node->display = true;
|
||||
node->style->display = true;
|
||||
|
||||
node->parent = parent;
|
||||
node->type = type;
|
||||
@ -1408,7 +1519,7 @@ static SvgNode* _createClipPathNode(SvgLoaderData* loader, SvgNode* parent, cons
|
||||
loader->svgParse->node = _createNode(parent, SvgNodeType::ClipPath);
|
||||
if (!loader->svgParse->node) return nullptr;
|
||||
|
||||
loader->svgParse->node->display = false;
|
||||
loader->svgParse->node->style->display = false;
|
||||
loader->svgParse->node->node.clip.userSpace = true;
|
||||
|
||||
func(buf, bufLength, _attrParseClipPathNode, loader);
|
||||
@ -1433,7 +1544,6 @@ static SvgNode* _createSymbolNode(SvgLoaderData* loader, SvgNode* parent, const
|
||||
loader->svgParse->node = _createNode(parent, SvgNodeType::Symbol);
|
||||
if (!loader->svgParse->node) return nullptr;
|
||||
|
||||
loader->svgParse->node->display = false;
|
||||
loader->svgParse->node->node.symbol.align = AspectRatioAlign::XMidYMid;
|
||||
loader->svgParse->node->node.symbol.meetOrSlice = AspectRatioMeetOrSlice::Meet;
|
||||
loader->svgParse->node->node.symbol.overflowVisible = false;
|
||||
@ -1615,8 +1725,11 @@ static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const
|
||||
|
||||
static bool _attrParsePolygonPoints(const char* str, SvgPolygonNode* polygon)
|
||||
{
|
||||
float num;
|
||||
while (_parseNumber(&str, &num)) polygon->pts.push(num);
|
||||
float num_x, num_y;
|
||||
while (_parseNumber(&str, nullptr, &num_x) && _parseNumber(&str, nullptr, &num_y)) {
|
||||
polygon->pts.push(num_x);
|
||||
polygon->pts.push(num_y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2378,8 +2491,9 @@ static bool _attrParseStopsStyle(void* data, const char* key, const char* value)
|
||||
stop->a = _toOpacity(value);
|
||||
loader->svgParse->flags = (loader->svgParse->flags | SvgStopStyleFlags::StopOpacity);
|
||||
} else if (!strcmp(key, "stop-color")) {
|
||||
_toColor(value, &stop->r, &stop->g, &stop->b, nullptr);
|
||||
loader->svgParse->flags = (loader->svgParse->flags | SvgStopStyleFlags::StopColor);
|
||||
if (_toColor(value, &stop->r, &stop->g, &stop->b, nullptr)) {
|
||||
loader->svgParse->flags = (loader->svgParse->flags | SvgStopStyleFlags::StopColor);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -2849,9 +2963,15 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from)
|
||||
to->color = from->color;
|
||||
to->curColorSet = true;
|
||||
}
|
||||
if (from->flags & SvgStyleFlags::Opacity) {
|
||||
to->opacity = from->opacity;
|
||||
}
|
||||
if (from->flags & SvgStyleFlags::PaintOrder) {
|
||||
to->paintOrder = from->paintOrder;
|
||||
}
|
||||
if (from->flags & SvgStyleFlags::Display) {
|
||||
to->display = from->display;
|
||||
}
|
||||
//Fill
|
||||
to->fill.flags = (to->fill.flags | from->fill.flags);
|
||||
if (from->fill.flags & SvgFillFlags::Paint) {
|
||||
@ -3080,6 +3200,14 @@ static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content)
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(graphicsTags) / sizeof(graphicsTags[0]); i++) {
|
||||
if (!strncmp(content, graphicsTags[i].tag, graphicsTags[i].sz - 1)) {
|
||||
loader->currentGraphicsNode = nullptr;
|
||||
loader->stack.pop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loader->level--;
|
||||
}
|
||||
|
||||
@ -3146,6 +3274,11 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
|
||||
if (loader->stack.count > 0) parent = loader->stack.last();
|
||||
else parent = loader->doc;
|
||||
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
|
||||
if (node && !empty) {
|
||||
auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr);
|
||||
loader->stack.push(defs);
|
||||
loader->currentGraphicsNode = node;
|
||||
}
|
||||
} else if ((gradientMethod = _findGradientFactory(tagName))) {
|
||||
SvgStyleGradient* gradient;
|
||||
gradient = gradientMethod(loader, attrs, attrsLength);
|
||||
@ -3257,7 +3390,7 @@ static void _inefficientNodeCheck(TVG_UNUSED SvgNode* node)
|
||||
#ifdef THORVG_LOG_ENABLED
|
||||
auto type = simpleXmlNodeTypeToString(node->type);
|
||||
|
||||
if (!node->display && node->type != SvgNodeType::ClipPath && node->type != SvgNodeType::Symbol) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type);
|
||||
if (!node->style->display && node->type != SvgNodeType::ClipPath) TVGLOG("SVG", "Inefficient elements used [Display is none][Node Type : %s]", type);
|
||||
if (node->style->opacity == 0) TVGLOG("SVG", "Inefficient elements used [Opacity is zero][Node Type : %s]", type);
|
||||
if (node->style->fill.opacity == 0 && node->style->stroke.opacity == 0) TVGLOG("SVG", "Inefficient elements used [Fill opacity and stroke opacity are zero][Node Type : %s]", type);
|
||||
|
||||
@ -3699,10 +3832,11 @@ bool SvgLoader::open(const char* data, uint32_t size, bool copy)
|
||||
clear();
|
||||
|
||||
if (copy) {
|
||||
content = (char*)malloc(size);
|
||||
content = (char*)malloc(size + 1);
|
||||
if (!content) return false;
|
||||
memcpy((char*)content, data, size);
|
||||
} else content = data;
|
||||
content[size] = '\0';
|
||||
} else content = (char*)data;
|
||||
|
||||
this->size = size;
|
||||
this->copy = copy;
|
||||
@ -3726,7 +3860,7 @@ bool SvgLoader::open(const string& path)
|
||||
|
||||
if (filePath.empty()) return false;
|
||||
|
||||
content = filePath.c_str();
|
||||
content = (char*)filePath.c_str();
|
||||
size = filePath.size();
|
||||
|
||||
return header();
|
||||
|
@ -31,7 +31,7 @@ class SvgLoader : public ImageLoader, public Task
|
||||
public:
|
||||
string filePath;
|
||||
string svgPath = "";
|
||||
const char* content = nullptr;
|
||||
char* content = nullptr;
|
||||
uint32_t size = 0;
|
||||
|
||||
SvgLoaderData loaderData;
|
||||
|
@ -485,11 +485,12 @@ struct SvgStyleProperty
|
||||
SvgComposite mask;
|
||||
int opacity;
|
||||
SvgColor color;
|
||||
bool curColorSet;
|
||||
char* cssClass;
|
||||
bool paintOrder; //true if default (fill, stroke), false otherwise
|
||||
SvgStyleFlags flags;
|
||||
SvgStyleFlags flagsImportance; //indicates the importance of the flag - if set, higher priority is applied (https://drafts.csswg.org/css-cascade-4/#importance)
|
||||
bool curColorSet;
|
||||
bool paintOrder; //true if default (fill, stroke), false otherwise
|
||||
bool display;
|
||||
};
|
||||
|
||||
struct SvgNode
|
||||
@ -518,7 +519,6 @@ struct SvgNode
|
||||
SvgCssStyleNode cssStyle;
|
||||
SvgSymbolNode symbol;
|
||||
} node;
|
||||
bool display;
|
||||
~SvgNode();
|
||||
};
|
||||
|
||||
@ -560,6 +560,7 @@ struct SvgLoaderData
|
||||
int level = 0;
|
||||
bool result = false;
|
||||
bool style = false;
|
||||
SvgNode* currentGraphicsNode = nullptr;
|
||||
};
|
||||
|
||||
struct Box
|
||||
|
16
thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
vendored
16
thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp
vendored
@ -126,7 +126,7 @@ void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, P
|
||||
rx = fabsf(rx);
|
||||
ry = fabsf(ry);
|
||||
|
||||
angle = angle * MATH_PI / 180.0f;
|
||||
angle = mathDeg2Rad(angle);
|
||||
cosPhi = cosf(angle);
|
||||
sinPhi = sinf(angle);
|
||||
dx2 = (sx - x) / 2.0f;
|
||||
@ -311,7 +311,7 @@ static int _numberCount(char cmd)
|
||||
}
|
||||
|
||||
|
||||
static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cmd, float* arr, int count, Point* cur, Point* curCtl, Point* startPoint, bool *isQuadratic)
|
||||
static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cmd, float* arr, int count, Point* cur, Point* curCtl, Point* startPoint, bool *isQuadratic, bool* closed)
|
||||
{
|
||||
switch (cmd) {
|
||||
case 'm':
|
||||
@ -464,6 +464,7 @@ static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cm
|
||||
case 'Z': {
|
||||
cmds->push(PathCommand::Close);
|
||||
*cur = *startPoint;
|
||||
*closed = true;
|
||||
break;
|
||||
}
|
||||
case 'a':
|
||||
@ -488,7 +489,7 @@ static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cm
|
||||
}
|
||||
|
||||
|
||||
static char* _nextCommand(char* path, char* cmd, float* arr, int* count)
|
||||
static char* _nextCommand(char* path, char* cmd, float* arr, int* count, bool* closed)
|
||||
{
|
||||
int large, sweep;
|
||||
|
||||
@ -500,6 +501,9 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count)
|
||||
} else {
|
||||
if (*cmd == 'm') *cmd = 'l';
|
||||
else if (*cmd == 'M') *cmd = 'L';
|
||||
else {
|
||||
if (*closed) return nullptr;
|
||||
}
|
||||
}
|
||||
if (*count == 7) {
|
||||
//Special case for arc command
|
||||
@ -548,6 +552,7 @@ bool svgPathToShape(const char* svgPath, Shape* shape)
|
||||
Point startPoint = { 0, 0 };
|
||||
char cmd = 0;
|
||||
bool isQuadratic = false;
|
||||
bool closed = false;
|
||||
char* path = (char*)svgPath;
|
||||
|
||||
auto& pts = P(shape)->rs.path.pts;
|
||||
@ -555,9 +560,10 @@ bool svgPathToShape(const char* svgPath, Shape* shape)
|
||||
auto lastCmds = cmds.count;
|
||||
|
||||
while ((path[0] != '\0')) {
|
||||
path = _nextCommand(path, &cmd, numberArray, &numberCount);
|
||||
path = _nextCommand(path, &cmd, numberArray, &numberCount, &closed);
|
||||
if (!path) break;
|
||||
if (!_processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &startPoint, &isQuadratic)) break;
|
||||
closed = false;
|
||||
if (!_processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &startPoint, &isQuadratic, &closed)) break;
|
||||
}
|
||||
|
||||
if (cmds.count > lastCmds && cmds[lastCmds] != PathCommand::MoveTo) return false;
|
||||
|
@ -310,7 +310,7 @@ static void _applyProperty(SvgLoaderData& loaderData, SvgNode* node, Shape* vg,
|
||||
|
||||
//Clip transformation is applied directly to the path in the _appendClipShape function
|
||||
if (node->transform && !clip) vg->transform(*node->transform);
|
||||
if (node->type == SvgNodeType::Doc || !node->display) return;
|
||||
if (node->type == SvgNodeType::Doc || !node->style->display) return;
|
||||
|
||||
//If fill property is nullptr then do nothing
|
||||
if (style->fill.paint.none) {
|
||||
@ -557,7 +557,7 @@ static bool _isValidImageMimeTypeAndEncoding(const char** href, const char** mim
|
||||
|
||||
static unique_ptr<Picture> _imageBuildHelper(SvgLoaderData& loaderData, SvgNode* node, const Box& vBox, const string& svgPath)
|
||||
{
|
||||
if (!node->node.image.href) return nullptr;
|
||||
if (!node->node.image.href || !strlen(node->node.image.href)) return nullptr;
|
||||
auto picture = Picture::gen();
|
||||
|
||||
TaskScheduler::async(false); //force to load a picture on the same thread
|
||||
@ -782,13 +782,13 @@ static unique_ptr<Scene> _sceneBuildHelper(SvgLoaderData& loaderData, const SvgN
|
||||
// For a Symbol node, the viewBox transformation has to be applied first - see _useBuildHelper()
|
||||
if (!mask && node->transform && node->type != SvgNodeType::Symbol) scene->transform(*node->transform);
|
||||
|
||||
if (node->display && node->style->opacity != 0) {
|
||||
if (node->style->display && node->style->opacity != 0) {
|
||||
auto child = node->child.data;
|
||||
for (uint32_t i = 0; i < node->child.count; ++i, ++child) {
|
||||
if (_isGroupType((*child)->type)) {
|
||||
if ((*child)->type == SvgNodeType::Use)
|
||||
scene->push(_useBuildHelper(loaderData, *child, vBox, svgPath, depth + 1, isMaskWhite));
|
||||
else
|
||||
else if (!((*child)->type == SvgNodeType::Symbol && node->type != SvgNodeType::Use))
|
||||
scene->push(_sceneBuildHelper(loaderData, *child, vBox, svgPath, false, depth + 1, isMaskWhite));
|
||||
} else if ((*child)->type == SvgNodeType::Image) {
|
||||
auto image = _imageBuildHelper(loaderData, *child, vBox, svgPath);
|
||||
|
@ -47,7 +47,6 @@ size_t svgUtilURLDecode(const char *src, char** dst)
|
||||
if (length == 0) return 0;
|
||||
|
||||
char* decoded = (char*)malloc(sizeof(char) * length + 1);
|
||||
decoded[length] = '\0';
|
||||
|
||||
char a, b;
|
||||
int idx =0;
|
||||
@ -64,7 +63,9 @@ size_t svgUtilURLDecode(const char *src, char** dst)
|
||||
decoded[idx++] = *src++;
|
||||
}
|
||||
}
|
||||
decoded[idx] = '\0';
|
||||
|
||||
*dst = decoded;
|
||||
return length + 1;
|
||||
return idx + 1;
|
||||
}
|
||||
|
||||
|
@ -314,7 +314,10 @@ bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttr
|
||||
if ((*keyEnd == '=') || (isspace((unsigned char)*keyEnd))) break;
|
||||
}
|
||||
if (keyEnd == itrEnd) goto error;
|
||||
if (keyEnd == key) continue;
|
||||
if (keyEnd == key) { // There is no key. This case is invalid, but explores the following syntax.
|
||||
itr = keyEnd + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*keyEnd == '=') value = keyEnd + 1;
|
||||
else {
|
||||
|
@ -1755,8 +1755,13 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c
|
||||
|
||||
void rasterGrayscale8(uint8_t *dst, uint8_t val, uint32_t offset, int32_t len)
|
||||
{
|
||||
//OPTIMIZE_ME: Support SIMD
|
||||
#if defined(THORVG_AVX_VECTOR_SUPPORT)
|
||||
avxRasterGrayscale8(dst, val, offset, len);
|
||||
#elif defined(THORVG_NEON_VECTOR_SUPPORT)
|
||||
neonRasterGrayscale8(dst, val, offset, len);
|
||||
#else
|
||||
cRasterPixels(dst, val, offset, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -62,6 +62,23 @@ static inline __m128i ALPHA_BLEND(__m128i c, __m128i a)
|
||||
}
|
||||
|
||||
|
||||
static void avxRasterGrayscale8(uint8_t* dst, uint8_t val, uint32_t offset, int32_t len)
|
||||
{
|
||||
dst += offset;
|
||||
|
||||
__m256i vecVal = _mm256_set1_epi8(val);
|
||||
|
||||
int32_t i = 0;
|
||||
for (; i <= len - 32; i += 32) {
|
||||
_mm256_storeu_si256((__m256i*)(dst + i), vecVal);
|
||||
}
|
||||
|
||||
for (; i < len; ++i) {
|
||||
dst[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void avxRasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
|
||||
{
|
||||
//1. calculate how many iterations we need to cover the length
|
||||
|
@ -24,6 +24,15 @@
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
//TODO : need to support windows ARM
|
||||
|
||||
#if defined(__ARM_64BIT_STATE) || defined(_M_ARM64)
|
||||
#define TVG_AARCH64 1
|
||||
#else
|
||||
#define TVG_AARCH64 0
|
||||
#endif
|
||||
|
||||
|
||||
static inline uint8x8_t ALPHA_BLEND(uint8x8_t c, uint8x8_t a)
|
||||
{
|
||||
uint16x8_t t = vmull_u8(c, a);
|
||||
@ -31,19 +40,50 @@ static inline uint8x8_t ALPHA_BLEND(uint8x8_t c, uint8x8_t a)
|
||||
}
|
||||
|
||||
|
||||
static void neonRasterGrayscale8(uint8_t* dst, uint8_t val, uint32_t offset, int32_t len)
|
||||
{
|
||||
dst += offset;
|
||||
|
||||
int32_t i = 0;
|
||||
const uint8x16_t valVec = vdupq_n_u8(val);
|
||||
#if TVG_AARCH64
|
||||
uint8x16x4_t valQuad = {valVec, valVec, valVec, valVec};
|
||||
for (; i <= len - 16 * 4; i += 16 * 4) {
|
||||
vst1q_u8_x4(dst + i, valQuad);
|
||||
}
|
||||
#else
|
||||
for (; i <= len - 16; i += 16) {
|
||||
vst1q_u8(dst + i, valVec);
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) {
|
||||
dst[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void neonRasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
|
||||
{
|
||||
dst += offset;
|
||||
|
||||
uint32x4_t vectorVal = vdupq_n_u32(val);
|
||||
|
||||
#if TVG_AARCH64
|
||||
uint32_t iterations = len / 16;
|
||||
uint32_t neonFilled = iterations * 16;
|
||||
uint32x4x4_t valQuad = {vectorVal, vectorVal, vectorVal, vectorVal};
|
||||
for (uint32_t i = 0; i < iterations; ++i) {
|
||||
vst4q_u32(dst, valQuad);
|
||||
dst += 16;
|
||||
}
|
||||
#else
|
||||
uint32_t iterations = len / 4;
|
||||
uint32_t neonFilled = iterations * 4;
|
||||
|
||||
dst += offset;
|
||||
uint32x4_t vectorVal = {val, val, val, val};
|
||||
|
||||
for (uint32_t i = 0; i < iterations; ++i) {
|
||||
vst1q_u32(dst, vectorVal);
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
int32_t leftovers = len - neonFilled;
|
||||
while (leftovers--) *dst++ = val;
|
||||
}
|
||||
@ -56,7 +96,7 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, u
|
||||
return false;
|
||||
}
|
||||
|
||||
auto color = surface->blender.join(r, g, b, a);
|
||||
auto color = surface->join(r, g, b, a);
|
||||
auto span = rle->spans;
|
||||
uint32_t src;
|
||||
uint8x8_t *vDst = nullptr;
|
||||
@ -67,9 +107,9 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, u
|
||||
else src = color;
|
||||
|
||||
auto dst = &surface->buf32[span->y * surface->stride + span->x];
|
||||
auto ialpha = IALPHA(src);
|
||||
auto ialpha = IA(src);
|
||||
|
||||
if ((((uint32_t) dst) & 0x7) != 0) {
|
||||
if ((((uintptr_t) dst) & 0x7) != 0) {
|
||||
//fill not aligned byte
|
||||
*dst = src + ALPHA_BLEND(*dst, ialpha);
|
||||
vDst = (uint8x8_t*)(dst + 1);
|
||||
@ -101,7 +141,7 @@ static bool neonRasterTranslucentRect(SwSurface* surface, const SwBBox& region,
|
||||
return false;
|
||||
}
|
||||
|
||||
auto color = surface->blender.join(r, g, b, a);
|
||||
auto color = surface->join(r, g, b, a);
|
||||
auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
|
||||
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||
@ -116,7 +156,7 @@ static bool neonRasterTranslucentRect(SwSurface* surface, const SwBBox& region,
|
||||
for (uint32_t y = 0; y < h; ++y) {
|
||||
auto dst = &buffer[y * surface->stride];
|
||||
|
||||
if ((((uint32_t) dst) & 0x7) != 0) {
|
||||
if ((((uintptr_t) dst) & 0x7) != 0) {
|
||||
//fill not aligned byte
|
||||
*dst = color + ALPHA_BLEND(*dst, ialpha);
|
||||
vDst = (uint8x8_t*) (dst + 1);
|
||||
|
@ -22,43 +22,26 @@
|
||||
|
||||
#include "tvgSwCommon.h"
|
||||
#include "tvgMath.h"
|
||||
#include "tvgBezier.h"
|
||||
#include "tvgLines.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
struct Line
|
||||
static bool _outlineBegin(SwOutline& outline)
|
||||
{
|
||||
Point pt1;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right)
|
||||
{
|
||||
auto len = _lineLength(cur.pt1, cur.pt2);
|
||||
auto dx = ((cur.pt2.x - cur.pt1.x) / len) * at;
|
||||
auto dy = ((cur.pt2.y - cur.pt1.y) / len) * at;
|
||||
left.pt1 = cur.pt1;
|
||||
left.pt2.x = left.pt1.x + dx;
|
||||
left.pt2.y = left.pt1.y + dy;
|
||||
right.pt1 = left.pt2;
|
||||
right.pt2 = cur.pt2;
|
||||
//Make a contour if lineTo/curveTo without calling close or moveTo beforehand.
|
||||
if (outline.pts.empty()) return false;
|
||||
outline.cntrs.push(outline.pts.count - 1);
|
||||
outline.closed.push(false);
|
||||
outline.pts.push(outline.pts[outline.cntrs.last()]);
|
||||
outline.types.push(SW_CURVE_TYPE_POINT);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool _outlineEnd(SwOutline& outline)
|
||||
{
|
||||
//Make a contour if lineTo/curveTo without calling close/moveTo beforehand.
|
||||
if (outline.pts.empty()) return false;
|
||||
outline.cntrs.push(outline.pts.count - 1);
|
||||
outline.closed.push(false);
|
||||
@ -119,10 +102,11 @@ static bool _outlineClose(SwOutline& outline)
|
||||
static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* transform)
|
||||
{
|
||||
Line cur = {dash.ptCur, *to};
|
||||
auto len = _lineLength(cur.pt1, cur.pt2);
|
||||
auto len = lineLength(cur.pt1, cur.pt2);
|
||||
|
||||
if (mathZero(len)) {
|
||||
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
||||
//draw the current line fully
|
||||
} else if (len < dash.curLen) {
|
||||
dash.curLen -= len;
|
||||
if (!dash.curOpGap) {
|
||||
@ -132,12 +116,13 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
|
||||
}
|
||||
_outlineLineTo(*dash.outline, to, transform);
|
||||
}
|
||||
//draw the current line partially
|
||||
} else {
|
||||
while (len - dash.curLen > 0.0001f) {
|
||||
Line left, right;
|
||||
if (dash.curLen > 0) {
|
||||
len -= dash.curLen;
|
||||
_lineSplitAt(cur, dash.curLen, left, right);
|
||||
lineSplitAt(cur, dash.curLen, left, right);
|
||||
if (!dash.curOpGap) {
|
||||
if (dash.move || dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) {
|
||||
_outlineMoveTo(*dash.outline, &left.pt1, transform);
|
||||
@ -180,6 +165,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
||||
Bezier cur = {dash.ptCur, *ctrl1, *ctrl2, *to};
|
||||
auto len = bezLength(cur);
|
||||
|
||||
//draw the current line fully
|
||||
if (mathZero(len)) {
|
||||
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
||||
} else if (len < dash.curLen) {
|
||||
@ -191,6 +177,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
||||
}
|
||||
_outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform);
|
||||
}
|
||||
//draw the current line partially
|
||||
} else {
|
||||
while ((len - dash.curLen) > 0.0001f) {
|
||||
Bezier left, right;
|
||||
@ -240,7 +227,15 @@ static void _dashClose(SwDashStroke& dash, const Matrix* transform)
|
||||
}
|
||||
|
||||
|
||||
static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const Point* pts, const Matrix* transform)
|
||||
static void _dashMoveTo(SwDashStroke& dash, const Point* pts)
|
||||
{
|
||||
dash.ptCur = *pts;
|
||||
dash.ptStart = *pts;
|
||||
dash.move = true;
|
||||
}
|
||||
|
||||
|
||||
static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const Point* pts)
|
||||
{
|
||||
dash.curIdx = offIdx % dash.cnt;
|
||||
dash.curLen = dash.pattern[dash.curIdx] - offset;
|
||||
@ -275,7 +270,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
||||
|
||||
//default
|
||||
if (end > begin) {
|
||||
if (begin > 0) dash.cnt += 4;
|
||||
if (begin > 0.0f) dash.cnt += 4;
|
||||
else dash.cnt += 2;
|
||||
//looping
|
||||
} else dash.cnt += 3;
|
||||
@ -293,7 +288,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
||||
dash.pattern[0] = 0; //zero dash to start with a space.
|
||||
dash.pattern[1] = begin;
|
||||
dash.pattern[2] = end - begin;
|
||||
dash.pattern[3] = length - (end - begin);
|
||||
dash.pattern[3] = length - end;
|
||||
}
|
||||
|
||||
trimmed = true;
|
||||
@ -322,14 +317,22 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
||||
|
||||
dash.outline = mpoolReqDashOutline(mpool, tid);
|
||||
|
||||
while (cmdCnt-- > 0) {
|
||||
//must begin with moveTo
|
||||
if (cmds[0] == PathCommand::MoveTo) {
|
||||
_dashMoveTo(dash, offIdx, offset, pts);
|
||||
cmds++;
|
||||
pts++;
|
||||
}
|
||||
|
||||
while (--cmdCnt > 0) {
|
||||
switch (*cmds) {
|
||||
case PathCommand::Close: {
|
||||
_dashClose(dash, transform);
|
||||
break;
|
||||
}
|
||||
case PathCommand::MoveTo: {
|
||||
_dashMoveTo(dash, offIdx, offset, pts, transform);
|
||||
if (rshape->stroke->trim.individual) _dashMoveTo(dash, pts);
|
||||
else _dashMoveTo(dash, offIdx, offset, pts);
|
||||
++pts;
|
||||
break;
|
||||
}
|
||||
@ -367,13 +370,19 @@ static float _outlineLength(const RenderShape* rshape)
|
||||
|
||||
const Point* close = nullptr;
|
||||
auto length = 0.0f;
|
||||
auto slength = -1.0f;
|
||||
auto simultaneous = !rshape->stroke->trim.individual;
|
||||
|
||||
//Compute the whole length
|
||||
while (cmdCnt-- > 0) {
|
||||
switch (*cmds) {
|
||||
case PathCommand::Close: {
|
||||
length += mathLength(pts - 1, close);
|
||||
++pts;
|
||||
//retrieve the max length of the shape if the simultaneous mode.
|
||||
if (simultaneous) {
|
||||
if (slength < length) slength = length;
|
||||
length = 0.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PathCommand::MoveTo: {
|
||||
@ -394,7 +403,8 @@ static float _outlineLength(const RenderShape* rshape)
|
||||
}
|
||||
++cmds;
|
||||
}
|
||||
return length;
|
||||
if (simultaneous && slength > length) return slength;
|
||||
else return length;
|
||||
}
|
||||
|
||||
|
||||
@ -429,7 +439,7 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix*
|
||||
|
||||
shape->outline = mpoolReqOutline(mpool, tid);
|
||||
auto outline = shape->outline;
|
||||
bool closed = false;
|
||||
auto closed = false;
|
||||
|
||||
//Generate Outlines
|
||||
while (cmdCnt-- > 0) {
|
||||
@ -444,13 +454,13 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix*
|
||||
break;
|
||||
}
|
||||
case PathCommand::LineTo: {
|
||||
if (closed) closed = _outlineEnd(*outline);
|
||||
if (closed) closed = _outlineBegin(*outline);
|
||||
_outlineLineTo(*outline, pts, transform);
|
||||
++pts;
|
||||
break;
|
||||
}
|
||||
case PathCommand::CubicTo: {
|
||||
if (closed) closed = _outlineEnd(*outline);
|
||||
if (closed) closed = _outlineBegin(*outline);
|
||||
_outlineCubicTo(*outline, pts, pts + 1, pts + 2, transform);
|
||||
pts += 3;
|
||||
break;
|
||||
|
27
thirdparty/thorvg/src/renderer/tvgAnimation.cpp
vendored
27
thirdparty/thorvg/src/renderer/tvgAnimation.cpp
vendored
@ -93,6 +93,33 @@ float Animation::duration() const noexcept
|
||||
}
|
||||
|
||||
|
||||
Result Animation::segment(float begin, float end) noexcept
|
||||
{
|
||||
if (begin < 0.0 || end > 1.0 || begin >= end) return Result::InvalidArguments;
|
||||
|
||||
auto loader = pImpl->picture->pImpl->loader;
|
||||
if (!loader) return Result::InsufficientCondition;
|
||||
if (!loader->animatable()) return Result::NonSupport;
|
||||
|
||||
static_cast<FrameModule*>(loader)->segment(begin, end);
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result Animation::segment(float *begin, float *end) noexcept
|
||||
{
|
||||
auto loader = pImpl->picture->pImpl->loader;
|
||||
if (!loader) return Result::InsufficientCondition;
|
||||
if (!loader->animatable()) return Result::NonSupport;
|
||||
if (!begin && !end) return Result::InvalidArguments;
|
||||
|
||||
static_cast<FrameModule*>(loader)->segment(begin, end);
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<Animation> Animation::gen() noexcept
|
||||
{
|
||||
return unique_ptr<Animation>(new Animation);
|
||||
|
15
thirdparty/thorvg/src/renderer/tvgCanvas.h
vendored
15
thirdparty/thorvg/src/renderer/tvgCanvas.h
vendored
@ -98,25 +98,14 @@ struct Canvas::Impl
|
||||
auto flag = RenderUpdateFlag::None;
|
||||
if (refresh || force) flag = RenderUpdateFlag::All;
|
||||
|
||||
//Update single paint node
|
||||
if (paint) {
|
||||
//Optimize Me: Can we skip the searching?
|
||||
for (auto paint2 : paints) {
|
||||
if (paint2 == paint) {
|
||||
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
||||
return Result::Success;
|
||||
}
|
||||
}
|
||||
return Result::InvalidArguments;
|
||||
//Update all retained paint nodes
|
||||
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
||||
} else {
|
||||
for (auto paint : paints) {
|
||||
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
||||
}
|
||||
refresh = false;
|
||||
}
|
||||
|
||||
refresh = false;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
15
thirdparty/thorvg/src/renderer/tvgFrameModule.h
vendored
15
thirdparty/thorvg/src/renderer/tvgFrameModule.h
vendored
@ -31,6 +31,9 @@ namespace tvg
|
||||
class FrameModule: public ImageLoader
|
||||
{
|
||||
public:
|
||||
float segmentBegin = 0.0f;
|
||||
float segmentEnd = 1.0f;
|
||||
|
||||
FrameModule(FileType type) : ImageLoader(type) {}
|
||||
virtual ~FrameModule() {}
|
||||
|
||||
@ -39,6 +42,18 @@ public:
|
||||
virtual float curFrame() = 0; //return the current frame number
|
||||
virtual float duration() = 0; //return the animation duration in seconds
|
||||
|
||||
void segment(float* begin, float* end)
|
||||
{
|
||||
if (begin) *begin = segmentBegin;
|
||||
if (end) *end = segmentEnd;
|
||||
}
|
||||
|
||||
void segment(float begin, float end)
|
||||
{
|
||||
segmentBegin = begin;
|
||||
segmentEnd = end;
|
||||
}
|
||||
|
||||
virtual bool animatable() override { return true; }
|
||||
};
|
||||
|
||||
|
@ -60,14 +60,14 @@ GlCanvas::~GlCanvas()
|
||||
}
|
||||
|
||||
|
||||
Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept
|
||||
Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h) noexcept
|
||||
{
|
||||
#ifdef THORVG_GL_RASTER_SUPPORT
|
||||
//We know renderer type, avoid dynamic_cast for performance.
|
||||
auto renderer = static_cast<GlRenderer*>(Canvas::pImpl->renderer);
|
||||
if (!renderer) return Result::MemoryCorruption;
|
||||
|
||||
if (!renderer->target(buffer, stride, w, h)) return Result::Unknown;
|
||||
if (!renderer->target(id, w, h)) return Result::Unknown;
|
||||
|
||||
//Paints must be updated again with this new target.
|
||||
Canvas::pImpl->needRefresh();
|
||||
|
50
thirdparty/thorvg/src/renderer/tvgLoader.cpp
vendored
50
thirdparty/thorvg/src/renderer/tvgLoader.cpp
vendored
@ -178,7 +178,6 @@ static LoadModule* _findByPath(const string& path)
|
||||
if (!ext.compare("tvg")) return _find(FileType::Tvg);
|
||||
if (!ext.compare("svg")) return _find(FileType::Svg);
|
||||
if (!ext.compare("json")) return _find(FileType::Lottie);
|
||||
if (!ext.compare("lottie")) return _find(FileType::Lottie);
|
||||
if (!ext.compare("png")) return _find(FileType::Png);
|
||||
if (!ext.compare("jpg")) return _find(FileType::Jpg);
|
||||
if (!ext.compare("webp")) return _find(FileType::Webp);
|
||||
@ -271,7 +270,7 @@ bool LoaderMgr::term()
|
||||
auto tmp = loader;
|
||||
loader = loader->next;
|
||||
_activeLoaders.remove(tmp);
|
||||
if (ret) delete(loader);
|
||||
if (ret) delete(tmp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -295,15 +294,24 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
|
||||
{
|
||||
*invalid = false;
|
||||
|
||||
if (auto loader = _findFromCache(path)) return loader;
|
||||
//TODO: lottie is not sharable.
|
||||
auto allowCache = true;
|
||||
auto ext = path.substr(path.find_last_of(".") + 1);
|
||||
if (!ext.compare("json")) allowCache = false;
|
||||
|
||||
if (allowCache) {
|
||||
if (auto loader = _findFromCache(path)) return loader;
|
||||
}
|
||||
|
||||
if (auto loader = _findByPath(path)) {
|
||||
if (loader->open(path)) {
|
||||
loader->hashpath = strdup(path.c_str());
|
||||
loader->pathcache = true;
|
||||
{
|
||||
ScopedLock lock(key);
|
||||
_activeLoaders.back(loader);
|
||||
if (allowCache) {
|
||||
loader->hashpath = strdup(path.c_str());
|
||||
loader->pathcache = true;
|
||||
{
|
||||
ScopedLock lock(key);
|
||||
_activeLoaders.back(loader);
|
||||
}
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
@ -313,11 +321,13 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
|
||||
for (int i = 0; i < static_cast<int>(FileType::Raw); i++) {
|
||||
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);
|
||||
if (allowCache) {
|
||||
loader->hashpath = strdup(path.c_str());
|
||||
loader->pathcache = true;
|
||||
{
|
||||
ScopedLock lock(key);
|
||||
_activeLoaders.back(loader);
|
||||
}
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
@ -354,7 +364,15 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
|
||||
{
|
||||
//Note that users could use the same data pointer with the different content.
|
||||
//Thus caching is only valid for shareable.
|
||||
if (!copy) {
|
||||
auto allowCache = !copy;
|
||||
|
||||
//TODO: lottie is not sharable.
|
||||
if (allowCache) {
|
||||
auto type = _convert(mimeType);
|
||||
if (type == FileType::Lottie) allowCache = false;
|
||||
}
|
||||
|
||||
if (allowCache) {
|
||||
if (auto loader = _findFromCache(data, size, mimeType)) return loader;
|
||||
}
|
||||
|
||||
@ -362,7 +380,7 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
|
||||
if (!mimeType.empty()) {
|
||||
if (auto loader = _findByType(mimeType)) {
|
||||
if (loader->open(data, size, copy)) {
|
||||
if (!copy) {
|
||||
if (allowCache) {
|
||||
loader->hashkey = HASH_KEY(data);
|
||||
ScopedLock lock(key);
|
||||
_activeLoaders.back(loader);
|
||||
@ -379,7 +397,7 @@ 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)) {
|
||||
if (!copy) {
|
||||
if (allowCache) {
|
||||
loader->hashkey = HASH_KEY(data);
|
||||
ScopedLock lock(key);
|
||||
_activeLoaders.back(loader);
|
||||
|
1
thirdparty/thorvg/src/renderer/tvgRender.h
vendored
1
thirdparty/thorvg/src/renderer/tvgRender.h
vendored
@ -163,6 +163,7 @@ struct RenderStroke
|
||||
struct {
|
||||
float begin = 0.0f;
|
||||
float end = 1.0f;
|
||||
bool individual = false;
|
||||
} trim;
|
||||
|
||||
~RenderStroke()
|
||||
|
11
thirdparty/thorvg/src/renderer/tvgSaver.cpp
vendored
11
thirdparty/thorvg/src/renderer/tvgSaver.cpp
vendored
@ -157,14 +157,17 @@ Result Saver::save(unique_ptr<Animation> animation, const string& path, uint32_t
|
||||
auto a = animation.release();
|
||||
if (!a) return Result::MemoryCorruption;
|
||||
|
||||
//animation holds the picture, it must be 1 at the bottom.
|
||||
auto remove = PP(a->picture())->refCnt <= 1 ? true : false;
|
||||
|
||||
if (mathZero(a->totalFrame())) {
|
||||
delete(a);
|
||||
if (remove) delete(a);
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
//Already on saving an other resource.
|
||||
if (pImpl->saveModule) {
|
||||
delete(a);
|
||||
if (remove) delete(a);
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
@ -173,12 +176,12 @@ Result Saver::save(unique_ptr<Animation> animation, const string& path, uint32_t
|
||||
pImpl->saveModule = saveModule;
|
||||
return Result::Success;
|
||||
} else {
|
||||
delete(a);
|
||||
if (remove) delete(a);
|
||||
delete(saveModule);
|
||||
return Result::Unknown;
|
||||
}
|
||||
}
|
||||
delete(a);
|
||||
if (remove) delete(a);
|
||||
return Result::NonSupport;
|
||||
}
|
||||
|
||||
|
10
thirdparty/thorvg/src/renderer/tvgShape.cpp
vendored
10
thirdparty/thorvg/src/renderer/tvgShape.cpp
vendored
@ -145,13 +145,15 @@ Result Shape::appendArc(float cx, float cy, float radius, float startAngle, floa
|
||||
//just circle
|
||||
if (sweep >= 360.0f || sweep <= -360.0f) return appendCircle(cx, cy, radius, radius);
|
||||
|
||||
startAngle = (startAngle * MATH_PI) / 180.0f;
|
||||
sweep = sweep * MATH_PI / 180.0f;
|
||||
const float arcPrecision = 1e-5f;
|
||||
startAngle = mathDeg2Rad(startAngle);
|
||||
sweep = mathDeg2Rad(sweep);
|
||||
|
||||
auto nCurves = ceil(fabsf(sweep / MATH_PI2));
|
||||
auto nCurves = static_cast<int>(fabsf(sweep / MATH_PI2));
|
||||
if (fabsf(sweep / MATH_PI2) - nCurves > arcPrecision) ++nCurves;
|
||||
auto sweepSign = (sweep < 0 ? -1 : 1);
|
||||
auto fract = fmodf(sweep, MATH_PI2);
|
||||
fract = (mathZero(fract)) ? MATH_PI2 * sweepSign : fract;
|
||||
fract = (fabsf(fract) < arcPrecision) ? MATH_PI2 * sweepSign : fract;
|
||||
|
||||
//Start from here
|
||||
Point start = {radius * cosf(startAngle), radius * sinf(startAngle)};
|
||||
|
20
thirdparty/thorvg/src/renderer/tvgShape.h
vendored
20
thirdparty/thorvg/src/renderer/tvgShape.h
vendored
@ -76,8 +76,21 @@ struct Shape::Impl
|
||||
//Composition test
|
||||
const Paint* target;
|
||||
auto method = shape->composite(&target);
|
||||
if (!target || method == tvg::CompositeMethod::ClipPath) return false;
|
||||
if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false;
|
||||
if (!target || method == CompositeMethod::ClipPath) return false;
|
||||
if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) {
|
||||
if (target->identifier() == TVG_CLASS_ID_SHAPE) {
|
||||
auto shape = static_cast<const Shape*>(target);
|
||||
if (!shape->fill()) {
|
||||
uint8_t r, g, b, a;
|
||||
shape->fillColor(&r, &g, &b, &a);
|
||||
if (a == 0 || a == 255) {
|
||||
if (method == CompositeMethod::LumaMask || method == CompositeMethod::InvLumaMask) {
|
||||
if ((r == 255 && g == 255 && b == 255) || (r == 0 && g == 0 && b == 0)) return false;
|
||||
} else return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -203,7 +216,7 @@ struct Shape::Impl
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strokeTrim(float begin, float end)
|
||||
bool strokeTrim(float begin, float end, bool individual)
|
||||
{
|
||||
if (!rs.stroke) {
|
||||
if (begin == 0.0f && end == 1.0f) return true;
|
||||
@ -214,6 +227,7 @@ struct Shape::Impl
|
||||
|
||||
rs.stroke->trim.begin = begin;
|
||||
rs.stroke->trim.end = end;
|
||||
rs.stroke->trim.individual = individual;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
|
||||
return true;
|
||||
|
11
thirdparty/thorvg/update-thorvg.sh
vendored
11
thirdparty/thorvg/update-thorvg.sh
vendored
@ -1,6 +1,6 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
VERSION=0.12.10
|
||||
VERSION=0.13.3
|
||||
|
||||
cd thirdparty/thorvg/ || true
|
||||
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
|
||||
@ -38,6 +38,7 @@ cat << EOF > ../inc/config.h
|
||||
#define THORVG_SVG_LOADER_SUPPORT
|
||||
#define THORVG_PNG_LOADER_SUPPORT
|
||||
#define THORVG_JPG_LOADER_SUPPORT
|
||||
#define THORVG_WEBP_LOADER_SUPPORT
|
||||
#define THORVG_THREAD_SUPPORT
|
||||
|
||||
// For internal debugging:
|
||||
@ -55,11 +56,13 @@ cp -rv src/renderer ../src/
|
||||
rm -rfv ../src/renderer/gl_engine
|
||||
rm -rfv ../src/renderer/wg_engine
|
||||
|
||||
# Enabled embedded loaders: raw, JPEG, PNG.
|
||||
# Enabled embedded loaders: raw, JPEG, PNG, WebP.
|
||||
mkdir ../src/loaders
|
||||
cp -rv src/loaders/svg src/loaders/raw ../src/loaders/
|
||||
cp -rv src/loaders/jpg ../src/loaders/
|
||||
cp -rv src/loaders/png src/loaders/external_png ../src/loaders/
|
||||
cp -rv src/loaders/external_png ../src/loaders/
|
||||
cp -rv src/loaders/external_webp ../src/loaders/
|
||||
# Not using external jpg as it's turbojpeg, which we don't have.
|
||||
cp -rv src/loaders/jpg ../src/loaders/
|
||||
|
||||
popd
|
||||
rm -rf tmp
|
||||
|
Loading…
Reference in New Issue
Block a user