mirror of
https://github.com/godotengine/godot.git
synced 2025-04-07 00:44:24 +08:00
Merge pull request #101347 from akien-mga/thorvg-0.15.8
thorvg: Update to 0.15.8
This commit is contained in:
commit
df7572f8bc
2
thirdparty/README.md
vendored
2
thirdparty/README.md
vendored
@ -935,7 +935,7 @@ instead of `miniz.h` as an external dependency.
|
||||
## thorvg
|
||||
|
||||
- Upstream: https://github.com/thorvg/thorvg
|
||||
- Version: 0.15.5 (89ab573acb253567975b2494069c7ee9abc9267c, 2024)
|
||||
- Version: 0.15.8 (bd8c2fca7663a22fba7a339937cb60f2f6247a2e, 2025)
|
||||
- License: MIT
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
5
thirdparty/thorvg/AUTHORS
vendored
5
thirdparty/thorvg/AUTHORS
vendored
@ -22,7 +22,7 @@ Rafał Mikrut <mikrutrafal@protonmail.com>
|
||||
Martin Capitanio <capnm@capitanio.org>
|
||||
RuiwenTang <tangruiwen1989@gmail.com>
|
||||
YouJin Lee <ol-of@naver.com>
|
||||
SergeyLebedkin <sergii@lottiefiles.com>
|
||||
Sergii Liebodkin <sergii@lottiefiles.com>
|
||||
Jinny You <jinny@lottiefiles.com>
|
||||
Nattu Adnan <nattu@reallynattu.com>
|
||||
Gabor Kiss-Vamosi <kisvegabor@gmail.com>
|
||||
@ -35,3 +35,6 @@ Thaddeus Crews <repiteo@outlook.com>
|
||||
Josh Soref <jsoref@gmail.com>
|
||||
Elliott Sales de Andrade <quantum.analyst@gmail.com>
|
||||
Łukasz Pomietło <oficjalnyadreslukasza@gmail.com>
|
||||
Kelly Loh <kelly@lottiefiles.com>
|
||||
Dragoș Tiselice <dragos@lottiefiles.com>
|
||||
Marcin Baszczewski <marcin@baszczewski.pl>
|
||||
|
2
thirdparty/thorvg/inc/config.h
vendored
2
thirdparty/thorvg/inc/config.h
vendored
@ -15,5 +15,5 @@
|
||||
// For internal debugging:
|
||||
//#define THORVG_LOG_ENABLED
|
||||
|
||||
#define THORVG_VERSION_STRING "0.15.5"
|
||||
#define THORVG_VERSION_STRING "0.15.8"
|
||||
#endif
|
||||
|
9
thirdparty/thorvg/inc/thorvg.h
vendored
9
thirdparty/thorvg/inc/thorvg.h
vendored
@ -217,7 +217,10 @@ enum class SceneEffect : uint8_t
|
||||
{
|
||||
ClearAll = 0, ///< Reset all previously applied scene effects, restoring the scene to its original state.
|
||||
GaussianBlur, ///< Apply a blur effect with a Gaussian filter. Param(3) = {sigma(float)[> 0], direction(int)[both: 0 / horizontal: 1 / vertical: 2], border(int)[duplicate: 0 / wrap: 1], quality(int)[0 - 100]}
|
||||
DropShadow ///< Apply a drop shadow effect with a Gaussian Blur filter. Param(8) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255], angle(float)[0 - 360], distance(float), blur_sigma(float)[> 0], quality(int)[0 - 100]}
|
||||
DropShadow, ///< Apply a drop shadow effect with a Gaussian Blur filter. Param(8) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255], angle(float)[0 - 360], distance(float), blur_sigma(float)[> 0], quality(int)[0 - 100]}
|
||||
Fill, ///< Override the scene content color with a given fill information (Experimental API). Param(5) = {color_R(int)[0 - 255], color_G(int)[0 - 255], color_B(int)[0 - 255], opacity(int)[0 - 255]}
|
||||
Tint, ///< Tinting the current scene color with a given black, white color paramters (Experimental API). Param(7) = {black_R(int)[0 - 255], black_G(int)[0 - 255], black_B(int)[0 - 255], white_R(int)[0 - 255], white_G(int)[0 - 255], white_B(int)[0 - 255], intensity(float)[0 - 100]}
|
||||
Tritone ///< Apply a tritone color effect to the scene using three color parameters for shadows, midtones, and highlights (Experimental API). Param(9) = {Shadow_R(int)[0 - 255], Shadow_G(int)[0 - 255], Shadow_B(int)[0 - 255], Midtone_R(int)[0 - 255], Midtone_G(int)[0 - 255], Midtone_B(int)[0 - 255], Highlight_R(int)[0 - 255], Highlight_G(int)[0 - 255], Highlight_B(int)[0 - 255]}
|
||||
};
|
||||
|
||||
|
||||
@ -2110,7 +2113,7 @@ public:
|
||||
/**
|
||||
* @brief Set the access function for traversing the Picture scene tree nodes.
|
||||
*
|
||||
* @param[in] picture The picture node to traverse the internal scene-tree.
|
||||
* @param[in] paint The paint node to traverse the internal scene-tree.
|
||||
* @param[in] func The callback function calling for every paint nodes of the Picture.
|
||||
* @param[in] data Data passed to the @p func as its argument.
|
||||
*
|
||||
@ -2118,7 +2121,7 @@ public:
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result set(const Picture* picture, std::function<bool(const Paint* paint, void* data)> func, void* data) noexcept;
|
||||
Result set(Paint* paint, std::function<bool(const Paint* paint, void* data)> func, void* data) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Generate a unique ID (hash key) from a given name.
|
||||
|
@ -67,6 +67,7 @@ bool PngLoader::open(const string& path)
|
||||
|
||||
bool PngLoader::open(const char* data, uint32_t size, bool copy)
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
image->opaque = NULL;
|
||||
|
||||
if (!png_image_begin_read_from_memory(image, data, size)) return false;
|
||||
@ -75,6 +76,9 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy)
|
||||
h = (float)image->height;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,6 +68,7 @@ WebpLoader::~WebpLoader()
|
||||
|
||||
bool WebpLoader::open(const string& path)
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
auto webpFile = fopen(path.c_str(), "rb");
|
||||
if (!webpFile) return false;
|
||||
|
||||
@ -96,6 +97,9 @@ bool WebpLoader::open(const string& path)
|
||||
finalize:
|
||||
fclose(webpFile);
|
||||
return ret;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,6 +70,7 @@ JpgLoader::~JpgLoader()
|
||||
|
||||
bool JpgLoader::open(const string& path)
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
int width, height;
|
||||
decoder = jpgdHeader(path.c_str(), &width, &height);
|
||||
if (!decoder) return false;
|
||||
@ -78,6 +79,9 @@ bool JpgLoader::open(const string& path)
|
||||
h = static_cast<float>(height);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -3973,6 +3973,7 @@ bool SvgLoader::open(const char* data, uint32_t size, bool copy)
|
||||
|
||||
bool SvgLoader::open(const string& path)
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
clear();
|
||||
|
||||
ifstream f;
|
||||
@ -3990,6 +3991,9 @@ bool SvgLoader::open(const string& path)
|
||||
size = filePath.size();
|
||||
|
||||
return header();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -213,7 +213,7 @@ static bool _appendClipUseNode(SvgLoaderData& loaderData, SvgNode* node, Shape*
|
||||
Matrix m = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1};
|
||||
finalTransform *= m;
|
||||
}
|
||||
if (child->transform) finalTransform = *child->transform * finalTransform;
|
||||
if (child->transform) finalTransform *= *child->transform;
|
||||
|
||||
return _appendClipShape(loaderData, child, shape, vBox, svgPath, identity((const Matrix*)(&finalTransform)) ? nullptr : &finalTransform);
|
||||
}
|
||||
|
@ -547,8 +547,8 @@ SwRle* rleRender(const SwBBox* bbox);
|
||||
void rleFree(SwRle* rle);
|
||||
void rleReset(SwRle* rle);
|
||||
void rleMerge(SwRle* rle, SwRle* clip1, SwRle* clip2);
|
||||
void rleClip(SwRle* rle, const SwRle* clip);
|
||||
void rleClip(SwRle* rle, const SwBBox* clip);
|
||||
bool rleClip(SwRle* rle, const SwRle* clip);
|
||||
bool rleClip(SwRle* rle, const SwBBox* clip);
|
||||
|
||||
SwMpool* mpoolInit(uint32_t threads);
|
||||
bool mpoolTerm(SwMpool* mpool);
|
||||
@ -575,10 +575,17 @@ void rasterXYFlip(uint32_t* src, uint32_t* dst, int32_t stride, int32_t w, int32
|
||||
void rasterUnpremultiply(RenderSurface* surface);
|
||||
void rasterPremultiply(RenderSurface* surface);
|
||||
bool rasterConvertCS(RenderSurface* surface, ColorSpace to);
|
||||
uint32_t rasterUnpremultiply(uint32_t data);
|
||||
|
||||
bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params);
|
||||
bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* effect);
|
||||
bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params, uint8_t opacity, bool direct);
|
||||
bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params, bool direct);
|
||||
bool effectDropShadowPrepare(RenderEffectDropShadow* effect);
|
||||
bool effectFillPrepare(RenderEffectFill* effect);
|
||||
bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct);
|
||||
bool effectTintPrepare(RenderEffectTint* effect);
|
||||
bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct);
|
||||
bool effectTritonePrepare(RenderEffectTritone* effect);
|
||||
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct);
|
||||
|
||||
#endif /* _TVG_SW_COMMON_H_ */
|
||||
|
@ -487,6 +487,7 @@ void fillRadial(const SwFill* fill, uint8_t* dst, uint32_t y, uint32_t x, uint32
|
||||
auto src = MULTIPLY(A(_pixel(fill, sqrtf(det))), a);
|
||||
auto tmp = maskOp(src, *cmp, 0);
|
||||
*dst = tmp + MULTIPLY(*dst, ~tmp);
|
||||
det += deltaDet;
|
||||
deltaDet += deltaDeltaDet;
|
||||
b += deltaB;
|
||||
}
|
||||
|
@ -150,7 +150,6 @@ bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params)
|
||||
|
||||
//invalid
|
||||
if (extends == 0) {
|
||||
params->invalid = true;
|
||||
free(rd);
|
||||
return false;
|
||||
}
|
||||
@ -158,6 +157,7 @@ bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params)
|
||||
_gaussianExtendRegion(params->extend, extends, params->direction);
|
||||
|
||||
params->rd = rd;
|
||||
params->valid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -165,11 +165,6 @@ bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params)
|
||||
|
||||
bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params)
|
||||
{
|
||||
if (cmp->image.channelSize != sizeof(uint32_t)) {
|
||||
TVGERR("SW_ENGINE", "Not supported grayscale Gaussian Blur!");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& buffer = surface->compositor->image;
|
||||
auto data = static_cast<SwGaussianBlur*>(params->rd);
|
||||
auto& bbox = cmp->bbox;
|
||||
@ -310,7 +305,6 @@ bool effectDropShadowPrepare(RenderEffectDropShadow* params)
|
||||
|
||||
//invalid
|
||||
if (extends == 0 || params->color[3] == 0) {
|
||||
params->invalid = true;
|
||||
free(rd);
|
||||
return false;
|
||||
}
|
||||
@ -327,6 +321,7 @@ bool effectDropShadowPrepare(RenderEffectDropShadow* params)
|
||||
_dropShadowExtendRegion(params->extend, extends, rd->offset);
|
||||
|
||||
params->rd = rd;
|
||||
params->valid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -335,13 +330,8 @@ bool effectDropShadowPrepare(RenderEffectDropShadow* params)
|
||||
//A quite same integration with effectGaussianBlur(). See it for detailed comments.
|
||||
//surface[0]: the original image, to overlay it into the filtered image.
|
||||
//surface[1]: temporary buffer for generating the filtered image.
|
||||
bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffectDropShadow* params, uint8_t opacity, bool direct)
|
||||
bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffectDropShadow* params, bool direct)
|
||||
{
|
||||
if (cmp->image.channelSize != sizeof(uint32_t)) {
|
||||
TVGERR("SW_ENGINE", "Not supported grayscale Drop Shadow!");
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME: if the body is partially visible due to clipping, the shadow also becomes partially visible.
|
||||
|
||||
auto data = static_cast<SwDropShadow*>(params->rd);
|
||||
@ -357,7 +347,8 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe
|
||||
auto stride = cmp->image.stride;
|
||||
auto front = cmp->image.buf32;
|
||||
auto back = buffer[1]->buf32;
|
||||
opacity = MULTIPLY(params->color[3], opacity);
|
||||
|
||||
auto opacity = direct ? MULTIPLY(params->color[3], cmp->opacity) : params->color[3];
|
||||
|
||||
TVGLOG("SW_ENGINE", "DropShadow region(%ld, %ld, %ld, %ld) params(%f %f %f), level(%d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->angle, params->distance, params->sigma, data->level);
|
||||
|
||||
@ -408,3 +399,181 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Fill Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool effectFillPrepare(RenderEffectFill* params)
|
||||
{
|
||||
params->valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct)
|
||||
{
|
||||
auto opacity = direct ? MULTIPLY(params->color[3], cmp->opacity) : params->color[3];
|
||||
|
||||
auto& bbox = cmp->bbox;
|
||||
auto w = size_t(bbox.max.x - bbox.min.x);
|
||||
auto h = size_t(bbox.max.y - bbox.min.y);
|
||||
auto color = cmp->recoverSfc->join(params->color[0], params->color[1], params->color[2], 255);
|
||||
|
||||
TVGLOG("SW_ENGINE", "Fill region(%ld, %ld, %ld, %ld), param(%d %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->color[0], params->color[1], params->color[2], params->color[3]);
|
||||
|
||||
if (direct) {
|
||||
auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x);
|
||||
auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
auto dst = dbuffer;
|
||||
auto src = sbuffer;
|
||||
for (size_t x = 0; x < w; ++x, ++dst, ++src) {
|
||||
auto a = MULTIPLY(opacity, A(*src));
|
||||
auto tmp = ALPHA_BLEND(color, a);
|
||||
*dst = tmp + ALPHA_BLEND(*dst, 255 - a);
|
||||
}
|
||||
dbuffer += cmp->image.stride;
|
||||
sbuffer += cmp->recoverSfc->stride;
|
||||
}
|
||||
cmp->valid = true; //no need the subsequent composition
|
||||
} else {
|
||||
auto dbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
auto dst = dbuffer;
|
||||
for (size_t x = 0; x < w; ++x, ++dst) {
|
||||
*dst = ALPHA_BLEND(color, MULTIPLY(opacity, A(*dst)));
|
||||
}
|
||||
dbuffer += cmp->image.stride;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Tint Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool effectTintPrepare(RenderEffectTint* params)
|
||||
{
|
||||
params->valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct)
|
||||
{
|
||||
auto& bbox = cmp->bbox;
|
||||
auto w = size_t(bbox.max.x - bbox.min.x);
|
||||
auto h = size_t(bbox.max.y - bbox.min.y);
|
||||
auto black = cmp->recoverSfc->join(params->black[0], params->black[1], params->black[2], 255);
|
||||
auto white = cmp->recoverSfc->join(params->white[0], params->white[1], params->white[2], 255);
|
||||
auto opacity = cmp->opacity;
|
||||
auto luma = cmp->recoverSfc->alphas[2]; //luma function
|
||||
|
||||
TVGLOG("SW_ENGINE", "Tint region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->black[0], params->black[1], params->black[2], params->white[0], params->white[1], params->white[2], params->intensity);
|
||||
|
||||
/* Tint Formula: (1 - L) * Black + L * White, where the L is Luminance. */
|
||||
|
||||
if (direct) {
|
||||
auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x);
|
||||
auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
auto dst = dbuffer;
|
||||
auto src = sbuffer;
|
||||
for (size_t x = 0; x < w; ++x, ++dst, ++src) {
|
||||
auto tmp = rasterUnpremultiply(*src);
|
||||
auto val = INTERPOLATE(INTERPOLATE(black, white, luma((uint8_t*)&tmp)), tmp, params->intensity);
|
||||
*dst = INTERPOLATE(val, *dst, MULTIPLY(opacity, A(tmp)));
|
||||
}
|
||||
dbuffer += cmp->image.stride;
|
||||
sbuffer += cmp->recoverSfc->stride;
|
||||
}
|
||||
cmp->valid = true; //no need the subsequent composition
|
||||
} else {
|
||||
auto dbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
auto dst = dbuffer;
|
||||
for (size_t x = 0; x < w; ++x, ++dst) {
|
||||
auto tmp = rasterUnpremultiply(*dst);
|
||||
auto val = INTERPOLATE(INTERPOLATE(black, white, luma((uint8_t*)&tmp)), tmp, params->intensity);
|
||||
*dst = ALPHA_BLEND(val, A(tmp));
|
||||
}
|
||||
dbuffer += cmp->image.stride;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Tritone Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
static uint32_t _trintone(uint32_t s, uint32_t m, uint32_t h, int l)
|
||||
{
|
||||
/* Tritone Formula:
|
||||
if (L < 0.5) { (1 - 2L) * Shadow + 2L * Midtone }
|
||||
else { (1 - 2(L - 0.5)) * Midtone + (2(L - 0.5)) * Highlight }
|
||||
Where the L is Luminance. */
|
||||
|
||||
if (l < 128) {
|
||||
auto a = std::min(l * 2, 255);
|
||||
return ALPHA_BLEND(s, 255 - a) + ALPHA_BLEND(m, a);
|
||||
} else {
|
||||
auto a = 2 * std::max(0, l - 128);
|
||||
return ALPHA_BLEND(m, 255 - a) + ALPHA_BLEND(h, a);
|
||||
}
|
||||
}
|
||||
|
||||
bool effectTritonePrepare(RenderEffectTritone* params)
|
||||
{
|
||||
params->valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct)
|
||||
{
|
||||
auto& bbox = cmp->bbox;
|
||||
auto w = size_t(bbox.max.x - bbox.min.x);
|
||||
auto h = size_t(bbox.max.y - bbox.min.y);
|
||||
auto shadow = cmp->recoverSfc->join(params->shadow[0], params->shadow[1], params->shadow[2], 255);
|
||||
auto midtone = cmp->recoverSfc->join(params->midtone[0], params->midtone[1], params->midtone[2], 255);
|
||||
auto highlight = cmp->recoverSfc->join(params->highlight[0], params->highlight[1], params->highlight[2], 255);
|
||||
auto opacity = cmp->opacity;
|
||||
auto luma = cmp->recoverSfc->alphas[2]; //luma function
|
||||
|
||||
TVGLOG("SW_ENGINE", "Tritone region(%ld, %ld, %ld, %ld), param(%d %d %d, %d %d %d, %d %d %d)", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y, params->shadow[0], params->shadow[1], params->shadow[2], params->midtone[0], params->midtone[1], params->midtone[2], params->highlight[0], params->highlight[1], params->highlight[2]);
|
||||
|
||||
if (direct) {
|
||||
auto dbuffer = cmp->recoverSfc->buf32 + (bbox.min.y * cmp->recoverSfc->stride + bbox.min.x);
|
||||
auto sbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
auto dst = dbuffer;
|
||||
auto src = sbuffer;
|
||||
for (size_t x = 0; x < w; ++x, ++dst, ++src) {
|
||||
auto tmp = rasterUnpremultiply(*src);
|
||||
*dst = INTERPOLATE(_trintone(shadow, midtone, highlight, luma((uint8_t*)&tmp)), *dst, MULTIPLY(opacity, A(tmp)));
|
||||
}
|
||||
dbuffer += cmp->image.stride;
|
||||
sbuffer += cmp->recoverSfc->stride;
|
||||
}
|
||||
cmp->valid = true; //no need the subsequent composition
|
||||
} else {
|
||||
auto dbuffer = cmp->image.buf32 + (bbox.min.y * cmp->image.stride + bbox.min.x);
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
auto dst = dbuffer;
|
||||
for (size_t x = 0; x < w; ++x, ++dst) {
|
||||
auto tmp = rasterUnpremultiply(*dst);
|
||||
*dst = ALPHA_BLEND(_trintone(shadow, midtone, highlight, luma((uint8_t*)&tmp)), A(tmp));
|
||||
}
|
||||
dbuffer += cmp->image.stride;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1667,6 +1667,20 @@ bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_
|
||||
}
|
||||
|
||||
|
||||
uint32_t rasterUnpremultiply(uint32_t data)
|
||||
{
|
||||
uint8_t a = data >> 24;
|
||||
if (a == 255 || a == 0) return data;
|
||||
uint16_t r = ((data >> 8) & 0xff00) / a;
|
||||
uint16_t g = ((data) & 0xff00) / a;
|
||||
uint16_t b = ((data << 8) & 0xff00) / a;
|
||||
if (r > 0xff) r = 0xff;
|
||||
if (g > 0xff) g = 0xff;
|
||||
if (b > 0xff) b = 0xff;
|
||||
return (a << 24) | (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
|
||||
|
||||
void rasterUnpremultiply(RenderSurface* surface)
|
||||
{
|
||||
if (surface->channelSize != sizeof(uint32_t)) return;
|
||||
@ -1677,20 +1691,7 @@ void rasterUnpremultiply(RenderSurface* surface)
|
||||
for (uint32_t y = 0; y < surface->h; y++) {
|
||||
auto buffer = surface->buf32 + surface->stride * y;
|
||||
for (uint32_t x = 0; x < surface->w; ++x) {
|
||||
uint8_t a = buffer[x] >> 24;
|
||||
if (a == 255) {
|
||||
continue;
|
||||
} else if (a == 0) {
|
||||
buffer[x] = 0x00ffffff;
|
||||
} else {
|
||||
uint16_t r = ((buffer[x] >> 8) & 0xff00) / a;
|
||||
uint16_t g = ((buffer[x]) & 0xff00) / a;
|
||||
uint16_t b = ((buffer[x] << 8) & 0xff00) / a;
|
||||
if (r > 0xff) r = 0xff;
|
||||
if (g > 0xff) g = 0xff;
|
||||
if (b > 0xff) b = 0xff;
|
||||
buffer[x] = (a << 24) | (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
buffer[x] = rasterUnpremultiply(buffer[x]);
|
||||
}
|
||||
}
|
||||
surface->premultiplied = false;
|
||||
|
@ -103,11 +103,9 @@ struct SwShapeTask : SwTask
|
||||
|
||||
bool clip(SwRle* target) override
|
||||
{
|
||||
if (shape.fastTrack) rleClip(target, &bbox);
|
||||
else if (shape.rle) rleClip(target, shape.rle);
|
||||
else return false;
|
||||
|
||||
return true;
|
||||
if (shape.fastTrack) return rleClip(target, &bbox);
|
||||
else if (shape.rle) return rleClip(target, shape.rle);
|
||||
return false;
|
||||
}
|
||||
|
||||
void run(unsigned tid) override
|
||||
@ -177,10 +175,8 @@ struct SwShapeTask : SwTask
|
||||
//Clip Path
|
||||
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;
|
||||
//Clip stroke rle
|
||||
if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err;
|
||||
if (shape.rle && !clipper->clip(shape.rle)) goto err; //Clip shape rle
|
||||
if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err; //Clip stroke rle
|
||||
}
|
||||
|
||||
bbox = renderRegion; //sync
|
||||
@ -546,15 +542,27 @@ const RenderSurface* SwRenderer::mainSurface()
|
||||
}
|
||||
|
||||
|
||||
SwSurface* SwRenderer::request(int channelSize)
|
||||
SwSurface* SwRenderer::request(int channelSize, bool square)
|
||||
{
|
||||
SwSurface* cmp = nullptr;
|
||||
uint32_t w, h;
|
||||
|
||||
if (square) {
|
||||
//Same Dimensional Size is demanded for the Post Processing Fast Flipping
|
||||
w = h = std::max(surface->w, surface->h);
|
||||
} else {
|
||||
w = surface->w;
|
||||
h = surface->h;
|
||||
}
|
||||
|
||||
//Use cached data
|
||||
for (auto p = compositors.begin(); p < compositors.end(); ++p) {
|
||||
if ((*p)->compositor->valid && (*p)->compositor->image.channelSize == channelSize) {
|
||||
cmp = *p;
|
||||
break;
|
||||
auto cur = *p;
|
||||
if (cur->compositor->valid && cur->compositor->image.channelSize == channelSize) {
|
||||
if (w == cur->w && h == cur->h) {
|
||||
cmp = *p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,15 +571,13 @@ SwSurface* SwRenderer::request(int channelSize)
|
||||
//Inherits attributes from main surface
|
||||
cmp = new SwSurface(surface);
|
||||
cmp->compositor = new SwCompositor;
|
||||
cmp->compositor->image.data = (pixel_t*)malloc(channelSize * surface->stride * surface->h);
|
||||
cmp->compositor->image.w = surface->w;
|
||||
cmp->compositor->image.h = surface->h;
|
||||
cmp->compositor->image.stride = surface->stride;
|
||||
cmp->compositor->image.data = (pixel_t*)malloc(channelSize * w * h);
|
||||
cmp->w = cmp->compositor->image.w = w;
|
||||
cmp->h = cmp->compositor->image.h = h;
|
||||
cmp->compositor->image.stride = w;
|
||||
cmp->compositor->image.direct = true;
|
||||
cmp->compositor->valid = true;
|
||||
cmp->channelSize = cmp->compositor->image.channelSize = channelSize;
|
||||
cmp->w = cmp->compositor->image.w;
|
||||
cmp->h = cmp->compositor->image.h;
|
||||
|
||||
compositors.push(cmp);
|
||||
}
|
||||
@ -583,7 +589,7 @@ SwSurface* SwRenderer::request(int channelSize)
|
||||
}
|
||||
|
||||
|
||||
RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs)
|
||||
RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags)
|
||||
{
|
||||
auto x = region.x;
|
||||
auto y = region.y;
|
||||
@ -595,7 +601,7 @@ RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs)
|
||||
//Out of boundary
|
||||
if (x >= sw || y >= sh || x + w < 0 || y + h < 0) return nullptr;
|
||||
|
||||
auto cmp = request(CHANNEL_SIZE(cs));
|
||||
auto cmp = request(CHANNEL_SIZE(cs), (flags & CompositionFlag::PostProcessing));
|
||||
|
||||
//Boundary Check
|
||||
if (x < 0) x = 0;
|
||||
@ -630,12 +636,15 @@ bool SwRenderer::endComposite(RenderCompositor* cmp)
|
||||
if (!cmp) return false;
|
||||
|
||||
auto p = static_cast<SwCompositor*>(cmp);
|
||||
p->valid = true;
|
||||
|
||||
//Recover Context
|
||||
surface = p->recoverSfc;
|
||||
surface->compositor = p->recoverCmp;
|
||||
|
||||
//only invalid (currently used) surface can be composited
|
||||
if (p->valid) return true;
|
||||
p->valid = true;
|
||||
|
||||
//Default is alpha blending
|
||||
if (p->method == CompositeMethod::None) {
|
||||
Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
@ -651,30 +660,47 @@ bool SwRenderer::prepare(RenderEffect* effect)
|
||||
switch (effect->type) {
|
||||
case SceneEffect::GaussianBlur: return effectGaussianBlurPrepare(static_cast<RenderEffectGaussianBlur*>(effect));
|
||||
case SceneEffect::DropShadow: return effectDropShadowPrepare(static_cast<RenderEffectDropShadow*>(effect));
|
||||
case SceneEffect::Fill: return effectFillPrepare(static_cast<RenderEffectFill*>(effect));
|
||||
case SceneEffect::Tint: return effectTintPrepare(static_cast<RenderEffectTint*>(effect));
|
||||
case SceneEffect::Tritone: return effectTritonePrepare(static_cast<RenderEffectTritone*>(effect));
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct)
|
||||
bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct)
|
||||
{
|
||||
if (effect->invalid) return false;
|
||||
if (!effect->valid) return false;
|
||||
|
||||
auto p = static_cast<SwCompositor*>(cmp);
|
||||
|
||||
if (p->image.channelSize != sizeof(uint32_t)) {
|
||||
TVGERR("SW_ENGINE", "Not supported grayscale Gaussian Blur!");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (effect->type) {
|
||||
case SceneEffect::GaussianBlur: {
|
||||
return effectGaussianBlur(p, request(surface->channelSize), static_cast<const RenderEffectGaussianBlur*>(effect));
|
||||
return effectGaussianBlur(p, request(surface->channelSize, true), static_cast<const RenderEffectGaussianBlur*>(effect));
|
||||
}
|
||||
case SceneEffect::DropShadow: {
|
||||
auto cmp1 = request(surface->channelSize);
|
||||
auto cmp1 = request(surface->channelSize, true);
|
||||
cmp1->compositor->valid = false;
|
||||
auto cmp2 = request(surface->channelSize);
|
||||
auto cmp2 = request(surface->channelSize, true);
|
||||
SwSurface* surfaces[] = {cmp1, cmp2};
|
||||
auto ret = effectDropShadow(p, surfaces, static_cast<const RenderEffectDropShadow*>(effect), opacity, direct);
|
||||
auto ret = effectDropShadow(p, surfaces, static_cast<const RenderEffectDropShadow*>(effect), direct);
|
||||
cmp1->compositor->valid = true;
|
||||
return ret;
|
||||
}
|
||||
case SceneEffect::Fill: {
|
||||
return effectFill(p, static_cast<const RenderEffectFill*>(effect), direct);
|
||||
}
|
||||
case SceneEffect::Tint: {
|
||||
return effectTint(p, static_cast<const RenderEffectTint*>(effect), direct);
|
||||
}
|
||||
case SceneEffect::Tritone: {
|
||||
return effectTritone(p, static_cast<const RenderEffectTritone*>(effect), direct);
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
@ -55,13 +55,13 @@ public:
|
||||
bool target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, ColorSpace cs);
|
||||
bool mempool(bool shared);
|
||||
|
||||
RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override;
|
||||
RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) override;
|
||||
bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override;
|
||||
bool endComposite(RenderCompositor* cmp) override;
|
||||
void clearCompositors();
|
||||
|
||||
bool prepare(RenderEffect* effect) override;
|
||||
bool effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) override;
|
||||
bool effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct) override;
|
||||
|
||||
static SwRenderer* gen();
|
||||
static bool init(uint32_t threads);
|
||||
@ -79,7 +79,7 @@ private:
|
||||
SwRenderer();
|
||||
~SwRenderer();
|
||||
|
||||
SwSurface* request(int channelSize);
|
||||
SwSurface* request(int channelSize, bool square);
|
||||
RenderData prepareCommon(SwTask* task, const Matrix& transform, const Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags);
|
||||
};
|
||||
|
||||
|
@ -188,7 +188,6 @@
|
||||
* http://www.freetype.org
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <limits.h>
|
||||
#include <memory.h>
|
||||
#include "tvgSwCommon.h"
|
||||
@ -243,8 +242,6 @@ struct RleWorker
|
||||
int bandSize;
|
||||
int bandShoot;
|
||||
|
||||
jmp_buf jmpBuf;
|
||||
|
||||
void* buffer;
|
||||
long bufferSize;
|
||||
|
||||
@ -359,7 +356,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
|
||||
rle->spans = static_cast<SwSpan*>(realloc(rle->spans, rle->alloc * sizeof(SwSpan)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Clip x range
|
||||
SwCoord xOver = 0;
|
||||
if (x + aCount >= rw.cellMax.x) xOver -= (x + aCount - rw.cellMax.x);
|
||||
@ -418,7 +415,7 @@ static Cell* _findCell(RleWorker& rw)
|
||||
pcell = &cell->next;
|
||||
}
|
||||
|
||||
if (rw.cellsCnt >= rw.maxCells) longjmp(rw.jmpBuf, 1);
|
||||
if (rw.cellsCnt >= rw.maxCells) return nullptr;
|
||||
|
||||
auto cell = rw.cells + rw.cellsCnt++;
|
||||
cell->x = x;
|
||||
@ -431,17 +428,22 @@ static Cell* _findCell(RleWorker& rw)
|
||||
}
|
||||
|
||||
|
||||
static void _recordCell(RleWorker& rw)
|
||||
static bool _recordCell(RleWorker& rw)
|
||||
{
|
||||
if (rw.area | rw.cover) {
|
||||
auto cell = _findCell(rw);
|
||||
|
||||
if (cell == nullptr) return false;
|
||||
|
||||
cell->area += rw.area;
|
||||
cell->cover += rw.cover;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void _setCell(RleWorker& rw, SwPoint pos)
|
||||
static bool _setCell(RleWorker& rw, SwPoint pos)
|
||||
{
|
||||
/* Move the cell pointer to a new position. We set the `invalid' */
|
||||
/* flag to indicate that the cell isn't part of those we're interested */
|
||||
@ -458,22 +460,26 @@ static void _setCell(RleWorker& rw, SwPoint pos)
|
||||
pos.x -= rw.cellMin.x;
|
||||
pos.y -= rw.cellMin.y;
|
||||
|
||||
if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
|
||||
//exceptions
|
||||
if (pos.x < 0) pos.x = -1;
|
||||
else if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
|
||||
|
||||
//Are we moving to a different cell?
|
||||
if (pos != rw.cellPos) {
|
||||
//Record the current one if it is valid
|
||||
if (!rw.invalid) _recordCell(rw);
|
||||
if (!rw.invalid) {
|
||||
if (!_recordCell(rw)) return false;
|
||||
}
|
||||
rw.area = rw.cover = 0;
|
||||
rw.cellPos = pos;
|
||||
}
|
||||
|
||||
rw.area = 0;
|
||||
rw.cover = 0;
|
||||
rw.cellPos = pos;
|
||||
rw.invalid = ((unsigned)pos.y >= (unsigned)rw.cellYCnt || pos.x >= rw.cellXCnt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void _startCell(RleWorker& rw, SwPoint pos)
|
||||
static bool _startCell(RleWorker& rw, SwPoint pos)
|
||||
{
|
||||
if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
|
||||
if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x;
|
||||
@ -483,23 +489,27 @@ static void _startCell(RleWorker& rw, SwPoint pos)
|
||||
rw.cellPos = pos - rw.cellMin;
|
||||
rw.invalid = false;
|
||||
|
||||
_setCell(rw, pos);
|
||||
return _setCell(rw, pos);
|
||||
}
|
||||
|
||||
|
||||
static void _moveTo(RleWorker& rw, const SwPoint& to)
|
||||
static bool _moveTo(RleWorker& rw, const SwPoint& to)
|
||||
{
|
||||
//record current cell, if any */
|
||||
if (!rw.invalid) _recordCell(rw);
|
||||
if (!rw.invalid) {
|
||||
if (!_recordCell(rw)) return false;
|
||||
}
|
||||
|
||||
//start to a new position
|
||||
_startCell(rw, TRUNC(to));
|
||||
if (!_startCell(rw, TRUNC(to))) return false;
|
||||
|
||||
rw.pos = to;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
static bool _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
{
|
||||
#define SW_UDIV(a, b) \
|
||||
static_cast<SwCoord>(((unsigned long)(a) * (unsigned long)(b)) >> \
|
||||
@ -511,7 +521,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
//vertical clipping
|
||||
if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) || (e1.y < rw.cellMin.y && e2.y < rw.cellMin.y)) {
|
||||
rw.pos = to;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto line = rw.lineStack;
|
||||
@ -539,7 +549,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
//any horizontal line
|
||||
} else if (diff.y == 0) {
|
||||
e1.x = e2.x;
|
||||
_setCell(rw, e1);
|
||||
if (!_setCell(rw, e1)) return false;
|
||||
} else if (diff.x == 0) {
|
||||
//vertical line up
|
||||
if (diff.y > 0) {
|
||||
@ -549,7 +559,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||
f1.y = 0;
|
||||
++e1.y;
|
||||
_setCell(rw, e1);
|
||||
if (!_setCell(rw, e1)) return false;
|
||||
} while(e1.y != e2.y);
|
||||
//vertical line down
|
||||
} else {
|
||||
@ -559,7 +569,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
rw.area += (f2.y - f1.y) * f1.x * 2;
|
||||
f1.y = ONE_PIXEL;
|
||||
--e1.y;
|
||||
_setCell(rw, e1);
|
||||
if (!_setCell(rw, e1)) return false;
|
||||
} while(e1.y != e2.y);
|
||||
}
|
||||
//any other line
|
||||
@ -612,7 +622,7 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
--e1.y;
|
||||
}
|
||||
|
||||
_setCell(rw, e1);
|
||||
if (!_setCell(rw, e1)) return false;
|
||||
|
||||
} while(e1 != e2);
|
||||
}
|
||||
@ -622,12 +632,12 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
|
||||
rw.area += (f2.y - f1.y) * (f1.x + f2.x);
|
||||
rw.pos = line[0];
|
||||
|
||||
if (line-- == rw.lineStack) return;
|
||||
if (line-- == rw.lineStack) return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to)
|
||||
static bool _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to)
|
||||
{
|
||||
auto arc = rw.bezStack;
|
||||
arc[0] = to;
|
||||
@ -691,14 +701,14 @@ static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2,
|
||||
continue;
|
||||
|
||||
draw:
|
||||
_lineTo(rw, arc[0]);
|
||||
if (arc == rw.bezStack) return;
|
||||
if (!_lineTo(rw, arc[0])) return false;
|
||||
if (arc == rw.bezStack) return true;
|
||||
arc -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _decomposeOutline(RleWorker& rw)
|
||||
static bool _decomposeOutline(RleWorker& rw)
|
||||
{
|
||||
auto outline = rw.outline;
|
||||
auto first = 0; //index of first point in contour
|
||||
@ -711,38 +721,43 @@ static void _decomposeOutline(RleWorker& rw)
|
||||
auto types = outline->types.data + first;
|
||||
++types;
|
||||
|
||||
_moveTo(rw, UPSCALE(outline->pts[first]));
|
||||
if (!_moveTo(rw, UPSCALE(outline->pts[first]))) return false;
|
||||
|
||||
while (pt < limit) {
|
||||
//emit a single line_to
|
||||
if (types[0] == SW_CURVE_TYPE_POINT) {
|
||||
++pt;
|
||||
++types;
|
||||
_lineTo(rw, UPSCALE(*pt));
|
||||
if (!_lineTo(rw, UPSCALE(*pt))) return false;
|
||||
//types cubic
|
||||
} else {
|
||||
pt += 3;
|
||||
types += 3;
|
||||
if (pt <= limit) _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0]));
|
||||
else if (pt - 1 == limit) _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), start);
|
||||
if (pt <= limit) {
|
||||
if (!_cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0]))) return false;
|
||||
}
|
||||
else if (pt - 1 == limit) {
|
||||
if (!_cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), start)) return false;
|
||||
}
|
||||
else goto close;
|
||||
}
|
||||
}
|
||||
close:
|
||||
_lineTo(rw, start);
|
||||
if (!_lineTo(rw, start)) return false;
|
||||
first = last + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int _genRle(RleWorker& rw)
|
||||
{
|
||||
if (setjmp(rw.jmpBuf) == 0) {
|
||||
_decomposeOutline(rw);
|
||||
if (!rw.invalid) _recordCell(rw);
|
||||
return 0;
|
||||
if (!_decomposeOutline(rw)) return -1;
|
||||
if (!rw.invalid) {
|
||||
if (!_recordCell(rw)) return -1;
|
||||
}
|
||||
return -1; //lack of cell memory
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1005,9 +1020,9 @@ void rleFree(SwRle* rle)
|
||||
}
|
||||
|
||||
|
||||
void rleClip(SwRle *rle, const SwRle *clip)
|
||||
bool rleClip(SwRle *rle, const SwRle *clip)
|
||||
{
|
||||
if (rle->size == 0 || clip->size == 0) return;
|
||||
if (rle->size == 0 || clip->size == 0) return false;
|
||||
auto spanCnt = rle->size > clip->size ? rle->size : clip->size;
|
||||
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt)));
|
||||
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt);
|
||||
@ -1015,16 +1030,21 @@ void rleClip(SwRle *rle, const SwRle *clip)
|
||||
_replaceClipSpan(rle, spans, spansEnd - spans);
|
||||
|
||||
TVGLOG("SW_ENGINE", "Using Path Clipping!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void rleClip(SwRle *rle, const SwBBox* clip)
|
||||
bool rleClip(SwRle *rle, const SwBBox* clip)
|
||||
{
|
||||
if (rle->size == 0) return;
|
||||
if (rle->size == 0) return false;
|
||||
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (rle->size)));
|
||||
auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size);
|
||||
|
||||
_replaceClipSpan(rle, spans, spansEnd - spans);
|
||||
|
||||
TVGLOG("SW_ENGINE", "Using Box Clipping!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -374,8 +374,12 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to)
|
||||
{
|
||||
auto delta = to - stroke.center;
|
||||
|
||||
//a zero-length lineto is a no-op; avoid creating a spurious corner
|
||||
if (delta.zero()) return;
|
||||
//a zero-length lineto is a no-op
|
||||
if (delta.zero()) {
|
||||
//round and square caps are expected to be drawn as a dot even for zero-length lines
|
||||
if (stroke.firstPt && stroke.cap != StrokeCap::Butt) _firstSubPath(stroke, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@ -454,6 +458,9 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl
|
||||
//ignoreable size
|
||||
if (valid < 0 && arc == bezStack) {
|
||||
stroke.center = to;
|
||||
|
||||
//round and square caps are expected to be drawn as a dot even for zero-length lines
|
||||
if (stroke.firstPt && stroke.cap != StrokeCap::Butt) _firstSubPath(stroke, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
10
thirdparty/thorvg/src/renderer/tvgAccessor.cpp
vendored
10
thirdparty/thorvg/src/renderer/tvgAccessor.cpp
vendored
@ -64,17 +64,17 @@ TVG_DEPRECATED unique_ptr<Picture> Accessor::set(unique_ptr<Picture> picture, fu
|
||||
}
|
||||
|
||||
|
||||
Result Accessor::set(const Picture* picture, function<bool(const Paint* paint, void* data)> func, void* data) noexcept
|
||||
Result Accessor::set(Paint* paint, function<bool(const Paint* paint, void* data)> func, void* data) noexcept
|
||||
{
|
||||
if (!picture || !func) return Result::InvalidArguments;
|
||||
if (!paint || !func) return Result::InvalidArguments;
|
||||
|
||||
//Use the Preorder Tree-Search
|
||||
//Use the Preorder Tree-Searc
|
||||
|
||||
//Root
|
||||
if (!func(picture, data)) return Result::Success;
|
||||
if (!func(paint, data)) return Result::Success;
|
||||
|
||||
//Children
|
||||
if (auto it = IteratorAccessor::iterator(picture)) {
|
||||
if (auto it = IteratorAccessor::iterator(paint)) {
|
||||
accessChildren(it, func, data);
|
||||
delete(it);
|
||||
}
|
||||
|
4
thirdparty/thorvg/src/renderer/tvgLoader.cpp
vendored
4
thirdparty/thorvg/src/renderer/tvgLoader.cpp
vendored
@ -172,6 +172,7 @@ static LoadModule* _find(FileType type)
|
||||
}
|
||||
|
||||
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
static LoadModule* _findByPath(const string& path)
|
||||
{
|
||||
auto ext = path.substr(path.find_last_of(".") + 1);
|
||||
@ -185,6 +186,7 @@ static LoadModule* _findByPath(const string& path)
|
||||
if (!ext.compare("otf") || !ext.compare("otc")) return _find(FileType::Ttf);
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static FileType _convert(const string& mimeType)
|
||||
@ -292,6 +294,7 @@ bool LoaderMgr::retrieve(LoadModule* loader)
|
||||
|
||||
LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
*invalid = false;
|
||||
|
||||
//TODO: svg & lottie is not sharable.
|
||||
@ -335,6 +338,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
|
||||
}
|
||||
}
|
||||
*invalid = true;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
4
thirdparty/thorvg/src/renderer/tvgPaint.cpp
vendored
4
thirdparty/thorvg/src/renderer/tvgPaint.cpp
vendored
@ -216,7 +216,7 @@ bool Paint::Impl::render(RenderMethod* renderer)
|
||||
|
||||
if (MASK_REGION_MERGING(compData->method)) region.add(P(compData->target)->bounds(renderer));
|
||||
if (region.w == 0 || region.h == 0) return true;
|
||||
cmp = renderer->target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method));
|
||||
cmp = renderer->target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method), CompositionFlag::Masking);
|
||||
if (renderer->beginComposite(cmp, CompositeMethod::None, 255)) {
|
||||
compData->target->pImpl->render(renderer);
|
||||
}
|
||||
@ -374,7 +374,7 @@ void Paint::Impl::reset()
|
||||
|
||||
blendMethod = BlendMethod::Normal;
|
||||
renderFlag = RenderUpdateFlag::None;
|
||||
ctxFlag = ContextFlag::Invalid;
|
||||
ctxFlag = ContextFlag::Default;
|
||||
opacity = 255;
|
||||
paint->id = 0;
|
||||
}
|
||||
|
2
thirdparty/thorvg/src/renderer/tvgPaint.h
vendored
2
thirdparty/thorvg/src/renderer/tvgPaint.h
vendored
@ -28,7 +28,7 @@
|
||||
|
||||
namespace tvg
|
||||
{
|
||||
enum ContextFlag : uint8_t {Invalid = 0, FastTrack = 1};
|
||||
enum ContextFlag : uint8_t {Default = 0, FastTrack = 1};
|
||||
|
||||
struct Iterator
|
||||
{
|
||||
|
21
thirdparty/thorvg/src/renderer/tvgPicture.cpp
vendored
21
thirdparty/thorvg/src/renderer/tvgPicture.cpp
vendored
@ -56,18 +56,20 @@ RenderUpdateFlag Picture::Impl::load()
|
||||
}
|
||||
|
||||
|
||||
bool Picture::Impl::needComposition(uint8_t opacity)
|
||||
void Picture::Impl::queryComposition(uint8_t opacity)
|
||||
{
|
||||
cFlag = CompositionFlag::Invalid;
|
||||
|
||||
//In this case, paint(scene) would try composition itself.
|
||||
if (opacity < 255) return false;
|
||||
if (opacity < 255) return;
|
||||
|
||||
//Composition test
|
||||
const Paint* target;
|
||||
auto method = picture->composite(&target);
|
||||
if (!target || method == tvg::CompositeMethod::ClipPath) return false;
|
||||
if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false;
|
||||
if (!target || method == tvg::CompositeMethod::ClipPath) return;
|
||||
if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return;
|
||||
|
||||
return true;
|
||||
cFlag = CompositionFlag::Opacity;
|
||||
}
|
||||
|
||||
|
||||
@ -79,8 +81,8 @@ bool Picture::Impl::render(RenderMethod* renderer)
|
||||
if (surface) return renderer->renderImage(rd);
|
||||
else if (paint) {
|
||||
RenderCompositor* cmp = nullptr;
|
||||
if (needComp) {
|
||||
cmp = renderer->target(bounds(renderer), renderer->colorSpace());
|
||||
if (cFlag) {
|
||||
cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast<CompositionFlag>(cFlag));
|
||||
renderer->beginComposite(cmp, CompositeMethod::None, 255);
|
||||
}
|
||||
ret = paint->pImpl->render(renderer);
|
||||
@ -164,9 +166,14 @@ Type Picture::type() const noexcept
|
||||
|
||||
Result Picture::load(const std::string& path) noexcept
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
if (path.empty()) return Result::InvalidArguments;
|
||||
|
||||
return pImpl->load(path);
|
||||
#else
|
||||
TVGLOG("RENDERER", "FILE IO is disabled!");
|
||||
return Result::NonSupport;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
6
thirdparty/thorvg/src/renderer/tvgPicture.h
vendored
6
thirdparty/thorvg/src/renderer/tvgPicture.h
vendored
@ -64,10 +64,10 @@ struct Picture::Impl
|
||||
RenderData rd = nullptr; //engine data
|
||||
float w = 0, h = 0;
|
||||
Picture* picture = nullptr;
|
||||
uint8_t cFlag = CompositionFlag::Invalid;
|
||||
bool resizing = false;
|
||||
bool needComp = false; //need composition
|
||||
|
||||
bool needComposition(uint8_t opacity);
|
||||
void queryComposition(uint8_t opacity);
|
||||
bool render(RenderMethod* renderer);
|
||||
bool size(float w, float h);
|
||||
RenderRegion bounds(RenderMethod* renderer);
|
||||
@ -107,7 +107,7 @@ struct Picture::Impl
|
||||
loader->resize(paint, w, h);
|
||||
resizing = false;
|
||||
}
|
||||
needComp = needComposition(opacity) ? true : false;
|
||||
queryComposition(opacity);
|
||||
rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false);
|
||||
}
|
||||
return rd;
|
||||
|
70
thirdparty/thorvg/src/renderer/tvgRender.h
vendored
70
thirdparty/thorvg/src/renderer/tvgRender.h
vendored
@ -36,6 +36,7 @@ using RenderData = void*;
|
||||
using pixel_t = uint32_t;
|
||||
|
||||
enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255};
|
||||
enum CompositionFlag : uint8_t {Invalid = 0, Opacity = 1, Blending = 2, Masking = 4, PostProcessing = 8}; //Composition Purpose
|
||||
|
||||
//TODO: Move this in public header unifying with SwCanvas::Colorspace
|
||||
enum ColorSpace : uint8_t
|
||||
@ -137,6 +138,7 @@ struct RenderStroke
|
||||
dashPattern = nullptr;
|
||||
}
|
||||
dashCnt = rhs.dashCnt;
|
||||
dashOffset = rhs.dashOffset;
|
||||
miterlimit = rhs.miterlimit;
|
||||
cap = rhs.cap;
|
||||
join = rhs.join;
|
||||
@ -268,7 +270,7 @@ struct RenderEffect
|
||||
RenderData rd = nullptr;
|
||||
RenderRegion extend = {0, 0, 0, 0};
|
||||
SceneEffect type;
|
||||
bool invalid = false;
|
||||
bool valid = false;
|
||||
|
||||
virtual ~RenderEffect()
|
||||
{
|
||||
@ -309,7 +311,7 @@ struct RenderEffectDropShadow : RenderEffect
|
||||
inst->color[0] = va_arg(args, int);
|
||||
inst->color[1] = va_arg(args, int);
|
||||
inst->color[2] = va_arg(args, int);
|
||||
inst->color[3] = std::min(va_arg(args, int), 255);
|
||||
inst->color[3] = va_arg(args, int);
|
||||
inst->angle = (float) va_arg(args, double);
|
||||
inst->distance = (float) va_arg(args, double);
|
||||
inst->sigma = std::max((float) va_arg(args, double), 0.0f);
|
||||
@ -319,6 +321,66 @@ struct RenderEffectDropShadow : RenderEffect
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderEffectFill : RenderEffect
|
||||
{
|
||||
uint8_t color[4]; //rgba
|
||||
|
||||
static RenderEffectFill* gen(va_list& args)
|
||||
{
|
||||
auto inst = new RenderEffectFill;
|
||||
inst->color[0] = va_arg(args, int);
|
||||
inst->color[1] = va_arg(args, int);
|
||||
inst->color[2] = va_arg(args, int);
|
||||
inst->color[3] = va_arg(args, int);
|
||||
inst->type = SceneEffect::Fill;
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderEffectTint : RenderEffect
|
||||
{
|
||||
uint8_t black[3]; //rgb
|
||||
uint8_t white[3]; //rgb
|
||||
uint8_t intensity; //0 - 255
|
||||
|
||||
static RenderEffectTint* gen(va_list& args)
|
||||
{
|
||||
auto inst = new RenderEffectTint;
|
||||
inst->black[0] = va_arg(args, int);
|
||||
inst->black[1] = va_arg(args, int);
|
||||
inst->black[2] = va_arg(args, int);
|
||||
inst->white[0] = va_arg(args, int);
|
||||
inst->white[1] = va_arg(args, int);
|
||||
inst->white[2] = va_arg(args, int);
|
||||
inst->intensity = (uint8_t)(va_arg(args, double) * 2.55f);
|
||||
inst->type = SceneEffect::Tint;
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderEffectTritone : RenderEffect
|
||||
{
|
||||
uint8_t shadow[3]; //rgb
|
||||
uint8_t midtone[3]; //rgb
|
||||
uint8_t highlight[3]; //rgb
|
||||
|
||||
static RenderEffectTritone* gen(va_list& args)
|
||||
{
|
||||
auto inst = new RenderEffectTritone;
|
||||
inst->shadow[0] = va_arg(args, int);
|
||||
inst->shadow[1] = va_arg(args, int);
|
||||
inst->shadow[2] = va_arg(args, int);
|
||||
inst->midtone[0] = va_arg(args, int);
|
||||
inst->midtone[1] = va_arg(args, int);
|
||||
inst->midtone[2] = va_arg(args, int);
|
||||
inst->highlight[0] = va_arg(args, int);
|
||||
inst->highlight[1] = va_arg(args, int);
|
||||
inst->highlight[2] = va_arg(args, int);
|
||||
inst->type = SceneEffect::Tritone;
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
class RenderMethod
|
||||
{
|
||||
private:
|
||||
@ -347,12 +409,12 @@ public:
|
||||
virtual bool clear() = 0;
|
||||
virtual bool sync() = 0;
|
||||
|
||||
virtual RenderCompositor* target(const RenderRegion& region, ColorSpace cs) = 0;
|
||||
virtual RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) = 0;
|
||||
virtual bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) = 0;
|
||||
virtual bool endComposite(RenderCompositor* cmp) = 0;
|
||||
|
||||
virtual bool prepare(RenderEffect* effect) = 0;
|
||||
virtual bool effect(RenderCompositor* cmp, const RenderEffect* effect, uint8_t opacity, bool direct) = 0;
|
||||
virtual bool effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct) = 0;
|
||||
};
|
||||
|
||||
static inline bool MASK_REGION_MERGING(CompositeMethod method)
|
||||
|
12
thirdparty/thorvg/src/renderer/tvgScene.cpp
vendored
12
thirdparty/thorvg/src/renderer/tvgScene.cpp
vendored
@ -128,6 +128,18 @@ Result Scene::push(SceneEffect effect, ...) noexcept
|
||||
re = RenderEffectDropShadow::gen(args);
|
||||
break;
|
||||
}
|
||||
case SceneEffect::Fill: {
|
||||
re = RenderEffectFill::gen(args);
|
||||
break;
|
||||
}
|
||||
case SceneEffect::Tint: {
|
||||
re = RenderEffectTint::gen(args);
|
||||
break;
|
||||
}
|
||||
case SceneEffect::Tritone: {
|
||||
re = RenderEffectTritone::gen(args);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
39
thirdparty/thorvg/src/renderer/tvgScene.h
vendored
39
thirdparty/thorvg/src/renderer/tvgScene.h
vendored
@ -62,8 +62,8 @@ struct Scene::Impl
|
||||
Scene* scene = nullptr;
|
||||
RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX};
|
||||
Array<RenderEffect*>* effects = nullptr;
|
||||
uint8_t compFlag = CompositionFlag::Invalid;
|
||||
uint8_t opacity; //for composition
|
||||
bool needComp = false; //composite or not
|
||||
|
||||
Impl(Scene* s) : scene(s)
|
||||
{
|
||||
@ -82,36 +82,36 @@ struct Scene::Impl
|
||||
}
|
||||
}
|
||||
|
||||
bool needComposition(uint8_t opacity)
|
||||
uint8_t needComposition(uint8_t opacity)
|
||||
{
|
||||
if (opacity == 0 || paints.empty()) return false;
|
||||
compFlag = CompositionFlag::Invalid;
|
||||
|
||||
//post effects requires composition
|
||||
if (effects) return true;
|
||||
if (opacity == 0 || paints.empty()) return 0;
|
||||
|
||||
//Masking may require composition (even if opacity == 255)
|
||||
//post effects, masking, blending may require composition
|
||||
if (effects) compFlag |= CompositionFlag::PostProcessing;
|
||||
auto compMethod = scene->composite(nullptr);
|
||||
if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) return true;
|
||||
|
||||
//Blending may require composition (even if opacity == 255)
|
||||
if (PP(scene)->blendMethod != BlendMethod::Normal) return true;
|
||||
if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) compFlag |= CompositionFlag::Masking;
|
||||
if (PP(scene)->blendMethod != BlendMethod::Normal) compFlag |= CompositionFlag::Blending;
|
||||
|
||||
//Half translucent requires intermediate composition.
|
||||
if (opacity == 255) return false;
|
||||
if (opacity == 255) return compFlag;
|
||||
|
||||
//If scene has several children or only scene, it may require composition.
|
||||
//OPTIMIZE: the bitmap type of the picture would not need the composition.
|
||||
//OPTIMIZE: a single paint of a scene would not need the composition.
|
||||
if (paints.size() == 1 && paints.front()->type() == Type::Shape) return false;
|
||||
if (paints.size() == 1 && paints.front()->type() == Type::Shape) return compFlag;
|
||||
|
||||
return true;
|
||||
compFlag |= CompositionFlag::Opacity;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flag, TVG_UNUSED bool clipper)
|
||||
{
|
||||
this->vport = renderer->viewport();
|
||||
|
||||
if ((needComp = needComposition(opacity))) {
|
||||
if (needComposition(opacity)) {
|
||||
/* Overriding opacity value. If this scene is half-translucent,
|
||||
It must do intermediate composition with that opacity value. */
|
||||
this->opacity = opacity;
|
||||
@ -131,8 +131,8 @@ struct Scene::Impl
|
||||
|
||||
renderer->blend(PP(scene)->blendMethod);
|
||||
|
||||
if (needComp) {
|
||||
cmp = renderer->target(bounds(renderer), renderer->colorSpace());
|
||||
if (compFlag) {
|
||||
cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast<CompositionFlag>(compFlag));
|
||||
renderer->beginComposite(cmp, CompositeMethod::None, opacity);
|
||||
}
|
||||
|
||||
@ -143,9 +143,10 @@ struct Scene::Impl
|
||||
if (cmp) {
|
||||
//Apply post effects if any.
|
||||
if (effects) {
|
||||
auto direct = effects->count == 1 ? true : false;
|
||||
//Notify the possiblity of the direct composition of the effect result to the origin surface.
|
||||
auto direct = (effects->count == 1) & (compFlag == CompositionFlag::PostProcessing);
|
||||
for (auto e = effects->begin(); e < effects->end(); ++e) {
|
||||
renderer->effect(cmp, *e, opacity, direct);
|
||||
renderer->effect(cmp, *e, direct);
|
||||
}
|
||||
}
|
||||
renderer->endComposite(cmp);
|
||||
@ -178,7 +179,7 @@ struct Scene::Impl
|
||||
if (effects) {
|
||||
for (auto e = effects->begin(); e < effects->end(); ++e) {
|
||||
auto effect = *e;
|
||||
if (effect->rd || renderer->prepare(effect)) {
|
||||
if (effect->valid || renderer->prepare(effect)) {
|
||||
ex = std::min(ex, effect->extend.x);
|
||||
ey = std::min(ey, effect->extend.y);
|
||||
ew = std::max(ew, effect->extend.w);
|
||||
|
22
thirdparty/thorvg/src/renderer/tvgShape.cpp
vendored
22
thirdparty/thorvg/src/renderer/tvgShape.cpp
vendored
@ -66,7 +66,7 @@ Result Shape::reset() noexcept
|
||||
pImpl->rs.path.cmds.clear();
|
||||
pImpl->rs.path.pts.clear();
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -93,7 +93,7 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point*
|
||||
pImpl->grow(cmdCnt, ptsCnt);
|
||||
pImpl->append(cmds, cmdCnt, pts, ptsCnt);
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -111,7 +111,7 @@ Result Shape::lineTo(float x, float y) noexcept
|
||||
{
|
||||
pImpl->lineTo(x, y);
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -121,7 +121,7 @@ Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float
|
||||
{
|
||||
pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y);
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -131,7 +131,7 @@ Result Shape::close() noexcept
|
||||
{
|
||||
pImpl->close();
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -150,7 +150,7 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
|
||||
pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
|
||||
pImpl->close();
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -212,7 +212,7 @@ TVG_DEPRECATED Result Shape::appendArc(float cx, float cy, float radius, float s
|
||||
|
||||
if (pie) pImpl->close();
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -252,7 +252,7 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry)
|
||||
pImpl->close();
|
||||
}
|
||||
|
||||
pImpl->flag |= RenderUpdateFlag::Path;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Path;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -263,7 +263,7 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
|
||||
if (pImpl->rs.fill) {
|
||||
delete(pImpl->rs.fill);
|
||||
pImpl->rs.fill = nullptr;
|
||||
pImpl->flag |= RenderUpdateFlag::Gradient;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Gradient;
|
||||
}
|
||||
|
||||
if (r == pImpl->rs.color[0] && g == pImpl->rs.color[1] && b == pImpl->rs.color[2] && a == pImpl->rs.color[3]) return Result::Success;
|
||||
@ -272,7 +272,7 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
|
||||
pImpl->rs.color[1] = g;
|
||||
pImpl->rs.color[2] = b;
|
||||
pImpl->rs.color[3] = a;
|
||||
pImpl->flag |= RenderUpdateFlag::Color;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Color;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -285,7 +285,7 @@ Result Shape::fill(unique_ptr<Fill> f) noexcept
|
||||
|
||||
if (pImpl->rs.fill && pImpl->rs.fill != p) delete(pImpl->rs.fill);
|
||||
pImpl->rs.fill = p;
|
||||
pImpl->flag |= RenderUpdateFlag::Gradient;
|
||||
pImpl->rFlag |= RenderUpdateFlag::Gradient;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
51
thirdparty/thorvg/src/renderer/tvgShape.h
vendored
51
thirdparty/thorvg/src/renderer/tvgShape.h
vendored
@ -33,10 +33,9 @@ struct Shape::Impl
|
||||
RenderShape rs; //shape data
|
||||
RenderData rd = nullptr; //engine data
|
||||
Shape* shape;
|
||||
uint8_t flag = RenderUpdateFlag::None;
|
||||
|
||||
uint8_t rFlag = RenderUpdateFlag::None;
|
||||
uint8_t cFlag = CompositionFlag::Invalid;
|
||||
uint8_t opacity; //for composition
|
||||
bool needComp = false; //composite or not
|
||||
|
||||
Impl(Shape* s) : shape(s)
|
||||
{
|
||||
@ -57,8 +56,8 @@ struct Shape::Impl
|
||||
|
||||
renderer->blend(PP(shape)->blendMethod);
|
||||
|
||||
if (needComp) {
|
||||
cmp = renderer->target(bounds(renderer), renderer->colorSpace());
|
||||
if (cFlag) {
|
||||
cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast<CompositionFlag>(cFlag));
|
||||
renderer->beginComposite(cmp, CompositeMethod::None, opacity);
|
||||
}
|
||||
|
||||
@ -69,6 +68,8 @@ struct Shape::Impl
|
||||
|
||||
bool needComposition(uint8_t opacity)
|
||||
{
|
||||
cFlag = CompositionFlag::Invalid;
|
||||
|
||||
if (opacity == 0) return false;
|
||||
|
||||
//Shape composition is only necessary when stroking & fill are valid.
|
||||
@ -76,7 +77,10 @@ struct Shape::Impl
|
||||
if (!rs.fill && rs.color[3] == 0) return false;
|
||||
|
||||
//translucent fill & stroke
|
||||
if (opacity < 255) return true;
|
||||
if (opacity < 255) {
|
||||
cFlag = CompositionFlag::Opacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Composition test
|
||||
const Paint* target;
|
||||
@ -97,22 +101,23 @@ struct Shape::Impl
|
||||
}
|
||||
}
|
||||
|
||||
cFlag = CompositionFlag::Masking;
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
{
|
||||
if (static_cast<RenderUpdateFlag>(pFlag | flag) == RenderUpdateFlag::None) return rd;
|
||||
if (static_cast<RenderUpdateFlag>(pFlag | rFlag) == RenderUpdateFlag::None) return rd;
|
||||
|
||||
if ((needComp = needComposition(opacity))) {
|
||||
if (needComposition(opacity)) {
|
||||
/* Overriding opacity value. If this scene is half-translucent,
|
||||
It must do intermediate composition with that opacity value. */
|
||||
this->opacity = opacity;
|
||||
opacity = 255;
|
||||
}
|
||||
|
||||
rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
|
||||
flag = RenderUpdateFlag::None;
|
||||
rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | rFlag), clipper);
|
||||
rFlag = RenderUpdateFlag::None;
|
||||
return rd;
|
||||
}
|
||||
|
||||
@ -209,7 +214,7 @@ struct Shape::Impl
|
||||
{
|
||||
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||
rs.stroke->width = width;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
}
|
||||
|
||||
void strokeTrim(float begin, float end, bool simultaneous)
|
||||
@ -225,7 +230,7 @@ struct Shape::Impl
|
||||
rs.stroke->trim.begin = begin;
|
||||
rs.stroke->trim.end = end;
|
||||
rs.stroke->trim.simultaneous = simultaneous;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
}
|
||||
|
||||
bool strokeTrim(float* begin, float* end)
|
||||
@ -245,21 +250,21 @@ struct Shape::Impl
|
||||
{
|
||||
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||
rs.stroke->cap = cap;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
}
|
||||
|
||||
void strokeJoin(StrokeJoin join)
|
||||
{
|
||||
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||
rs.stroke->join = join;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
}
|
||||
|
||||
void strokeMiterlimit(float miterlimit)
|
||||
{
|
||||
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||
rs.stroke->miterlimit = miterlimit;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
}
|
||||
|
||||
void strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||
@ -268,7 +273,7 @@ struct Shape::Impl
|
||||
if (rs.stroke->fill) {
|
||||
delete(rs.stroke->fill);
|
||||
rs.stroke->fill = nullptr;
|
||||
flag |= RenderUpdateFlag::GradientStroke;
|
||||
rFlag |= RenderUpdateFlag::GradientStroke;
|
||||
}
|
||||
|
||||
rs.stroke->color[0] = r;
|
||||
@ -276,7 +281,7 @@ struct Shape::Impl
|
||||
rs.stroke->color[2] = b;
|
||||
rs.stroke->color[3] = a;
|
||||
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
}
|
||||
|
||||
Result strokeFill(unique_ptr<Fill> f)
|
||||
@ -289,8 +294,8 @@ struct Shape::Impl
|
||||
rs.stroke->fill = p;
|
||||
rs.stroke->color[3] = 0;
|
||||
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
flag |= RenderUpdateFlag::GradientStroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::GradientStroke;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -325,7 +330,7 @@ struct Shape::Impl
|
||||
}
|
||||
rs.stroke->dashCnt = cnt;
|
||||
rs.stroke->dashOffset = offset;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
@ -340,12 +345,12 @@ struct Shape::Impl
|
||||
{
|
||||
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||
rs.stroke->strokeFirst = strokeFirst;
|
||||
flag |= RenderUpdateFlag::Stroke;
|
||||
rFlag |= RenderUpdateFlag::Stroke;
|
||||
}
|
||||
|
||||
void update(RenderUpdateFlag flag)
|
||||
{
|
||||
this->flag |= flag;
|
||||
rFlag |= flag;
|
||||
}
|
||||
|
||||
Paint* duplicate(Paint* ret)
|
||||
@ -358,7 +363,7 @@ struct Shape::Impl
|
||||
delete(dup->rs.fill);
|
||||
|
||||
//Default Properties
|
||||
dup->flag = RenderUpdateFlag::All;
|
||||
dup->rFlag = RenderUpdateFlag::All;
|
||||
dup->rs.rule = rs.rule;
|
||||
|
||||
//Color
|
||||
|
11
thirdparty/thorvg/src/renderer/tvgText.cpp
vendored
11
thirdparty/thorvg/src/renderer/tvgText.cpp
vendored
@ -60,13 +60,17 @@ Result Text::font(const char* name, float size, const char* style) noexcept
|
||||
|
||||
Result Text::load(const std::string& path) noexcept
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
bool invalid; //invalid path
|
||||
if (!LoaderMgr::loader(path, &invalid)) {
|
||||
if (invalid) return Result::InvalidArguments;
|
||||
else return Result::NonSupport;
|
||||
}
|
||||
|
||||
return Result::Success;
|
||||
#else
|
||||
TVGLOG("RENDERER", "FILE IO is disabled!");
|
||||
return Result::NonSupport;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -87,8 +91,13 @@ Result Text::load(const char* name, const char* data, uint32_t size, const strin
|
||||
|
||||
Result Text::unload(const std::string& path) noexcept
|
||||
{
|
||||
#ifdef THORVG_FILE_IO_SUPPORT
|
||||
if (LoaderMgr::retrieve(path)) return Result::Success;
|
||||
return Result::InsufficientCondition;
|
||||
#else
|
||||
TVGLOG("RENDERER", "FILE IO is disabled!");
|
||||
return Result::NonSupport;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
2
thirdparty/thorvg/src/renderer/tvgText.h
vendored
2
thirdparty/thorvg/src/renderer/tvgText.h
vendored
@ -113,7 +113,7 @@ struct Text::Impl
|
||||
|
||||
//transform the gradient coordinates based on the final scaled font.
|
||||
auto fill = P(shape)->rs.fill;
|
||||
if (fill && P(shape)->flag & RenderUpdateFlag::Gradient) {
|
||||
if (fill && P(shape)->rFlag & RenderUpdateFlag::Gradient) {
|
||||
auto scale = 1.0f / loader->scale;
|
||||
if (fill->type() == Type::LinearGradient) {
|
||||
P(static_cast<LinearGradient*>(fill))->x1 *= scale;
|
||||
|
2
thirdparty/thorvg/update-thorvg.sh
vendored
2
thirdparty/thorvg/update-thorvg.sh
vendored
@ -1,6 +1,6 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
VERSION=0.15.5
|
||||
VERSION=0.15.8
|
||||
# Uncomment and set a git hash to use specific commit instead of tag.
|
||||
#GIT_COMMIT=
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user