Merge pull request #102851 from Chubercik/thorvg-0.15.10

thorvg: Update to 0.15.10
This commit is contained in:
Thaddeus Crews 2025-02-14 08:25:12 -06:00
commit bc648b4aa2
No known key found for this signature in database
GPG key ID: 62181B86FE9E5D84
19 changed files with 186 additions and 363 deletions

View file

@ -944,7 +944,7 @@ Patches:
## thorvg
- Upstream: https://github.com/thorvg/thorvg
- Version: 0.15.8 (bd8c2fca7663a22fba7a339937cb60f2f6247a2e, 2025)
- Version: 0.15.10 (bca94d244c67f573c6eddc27d783d9a6b1ef2f1b, 2025)
- License: MIT
Files extracted from upstream source:
@ -955,7 +955,6 @@ Files extracted from upstream source:
Patches:
- `0001-revert-tvglines-bezier-precision.patch` (GH-96658)
- `0002-gcc15-include-fix.patch` (GH-102022)
## tinyexr

View file

@ -38,3 +38,4 @@ Elliott Sales de Andrade <quantum.analyst@gmail.com>
Kelly Loh <kelly@lottiefiles.com>
Dragoș Tiselice <dragos@lottiefiles.com>
Marcin Baszczewski <marcin@baszczewski.pl>
Fabian Blatz <fabianblatz@gmail.com>

View file

@ -15,5 +15,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
#define THORVG_VERSION_STRING "0.15.8"
#define THORVG_VERSION_STRING "0.15.10"
#endif

View file

@ -1,12 +0,0 @@
diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h
index 8e3ab4e6ce..f515a03136 100644
--- a/thirdparty/thorvg/inc/thorvg.h
+++ b/thirdparty/thorvg/inc/thorvg.h
@@ -1,6 +1,7 @@
#ifndef _THORVG_H_
#define _THORVG_H_
+#include <cstdint>
#include <functional>
#include <memory>
#include <string>

View file

@ -183,7 +183,7 @@ float strToFloat(const char *nPtr, char **endPtr)
auto scale = 1.0f;
while (exponentPart >= 8U) {
scale *= 1E8;
scale *= 1E8f;
exponentPart -= 8U;
}
while (exponentPart > 0U) {

View file

@ -200,7 +200,7 @@ static float _gradientToFloat(const SvgParser* svgParse, const char* str, bool&
isPercentage = false;
if (strstr(str, "%")) {
parsedValue = parsedValue / 100.0;
parsedValue = parsedValue / 100.0f;
isPercentage = true;
}
else if (strstr(str, "cm")) parsedValue *= PX_PER_CM;
@ -225,7 +225,7 @@ static float _toOffset(const char* str)
auto ptr = strstr(str, "%");
if (ptr) {
parsedValue = parsedValue / 100.0;
parsedValue = parsedValue / 100.0f;
if (end != ptr || (end + 1) != strEnd) return 0;
} else if (end != strEnd) return 0;

View file

@ -402,10 +402,10 @@ static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cm
case 'q':
case 'Q': {
Point p[3];
float ctrl_x0 = (cur->x + 2 * arr[0]) * (1.0 / 3.0);
float ctrl_y0 = (cur->y + 2 * arr[1]) * (1.0 / 3.0);
float ctrl_x1 = (arr[2] + 2 * arr[0]) * (1.0 / 3.0);
float ctrl_y1 = (arr[3] + 2 * arr[1]) * (1.0 / 3.0);
float ctrl_x0 = (cur->x + 2 * arr[0]) * (1.0f / 3.0f);
float ctrl_y0 = (cur->y + 2 * arr[1]) * (1.0f / 3.0f);
float ctrl_x1 = (arr[2] + 2 * arr[0]) * (1.0f / 3.0f);
float ctrl_y1 = (arr[3] + 2 * arr[1]) * (1.0f / 3.0f);
cmds->push(PathCommand::CubicTo);
p[0] = {ctrl_x0, ctrl_y0};
p[1] = {ctrl_x1, ctrl_y1};
@ -428,10 +428,10 @@ static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cm
} else {
ctrl = *cur;
}
float ctrl_x0 = (cur->x + 2 * ctrl.x) * (1.0 / 3.0);
float ctrl_y0 = (cur->y + 2 * ctrl.y) * (1.0 / 3.0);
float ctrl_x1 = (arr[0] + 2 * ctrl.x) * (1.0 / 3.0);
float ctrl_y1 = (arr[1] + 2 * ctrl.y) * (1.0 / 3.0);
float ctrl_x0 = (cur->x + 2 * ctrl.x) * (1.0f / 3.0f);
float ctrl_y0 = (cur->y + 2 * ctrl.y) * (1.0f / 3.0f);
float ctrl_x1 = (arr[0] + 2 * ctrl.x) * (1.0f / 3.0f);
float ctrl_y1 = (arr[1] + 2 * ctrl.y) * (1.0f / 3.0f);
cmds->push(PathCommand::CubicTo);
p[0] = {ctrl_x0, ctrl_y0};
p[1] = {ctrl_x1, ctrl_y1};

View file

@ -26,7 +26,7 @@
#ifdef _WIN32
#include <malloc.h>
#elif defined(__linux__)
#elif defined(__linux__) || defined(__ZEPHYR__)
#include <alloca.h>
#else
#include <stdlib.h>

View file

@ -23,8 +23,8 @@
#ifndef _TVG_SW_COMMON_H_
#define _TVG_SW_COMMON_H_
#include <algorithm>
#include "tvgCommon.h"
#include "tvgMath.h"
#include "tvgRender.h"
#define SW_CURVE_TYPE_POINT 0
@ -379,10 +379,13 @@ static inline uint32_t opBlendDifference(uint32_t s, uint32_t d, TVG_UNUSED uint
static inline uint32_t opBlendExclusion(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
//A + B - 2AB
auto c1 = std::min(255, C1(s) + C1(d) - std::min(255, (C1(s) * C1(d)) << 1));
auto c2 = std::min(255, C2(s) + C2(d) - std::min(255, (C2(s) * C2(d)) << 1));
auto c3 = std::min(255, C3(s) + C3(d) - std::min(255, (C3(s) * C3(d)) << 1));
// (s + d) - (2 * s * d)
auto c1 = C1(s) + C1(d) - 2 * MULTIPLY(C1(s), C1(d));
tvg::clamp(c1, 0, 255);
auto c2 = C2(s) + C2(d) - 2 * MULTIPLY(C2(s), C2(d));
tvg::clamp(c2, 0, 255);
auto c3 = C3(s) + C3(d) - 2 * MULTIPLY(C3(s), C3(d));
tvg::clamp(c3, 0, 255);
return JOIN(255, c1, c2, c3);
}
@ -444,10 +447,10 @@ static inline uint32_t opBlendLighten(uint32_t s, uint32_t d, TVG_UNUSED uint8_t
static inline uint32_t opBlendColorDodge(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
// d / (1 - s)
auto is = 0xffffffff - s;
auto c1 = (C1(is) > 0) ? (C1(d) / C1(is)) : C1(d);
auto c2 = (C2(is) > 0) ? (C2(d) / C2(is)) : C2(d);
auto c3 = (C3(is) > 0) ? (C3(d) / C3(is)) : C3(d);
s = 0xffffffff - s;
auto c1 = (C1(s) == 0) ? C1(d) : std::min(C1(d) * 255 / C1(s), 255);
auto c2 = (C2(s) == 0) ? C2(d) : std::min(C2(d) * 255 / C2(s), 255);
auto c3 = (C3(s) == 0) ? C3(d) : std::min(C3(d) * 255 / C3(s), 255);
return JOIN(255, c1, c2, c3);
}
@ -455,14 +458,17 @@ static inline uint32_t opBlendColorBurn(uint32_t s, uint32_t d, TVG_UNUSED uint8
{
// 1 - (1 - d) / s
auto id = 0xffffffff - d;
auto c1 = 255 - ((C1(s) > 0) ? (C1(id) / C1(s)) : C1(id));
auto c2 = 255 - ((C2(s) > 0) ? (C2(id) / C2(s)) : C2(id));
auto c3 = 255 - ((C3(s) > 0) ? (C3(id) / C3(s)) : C3(id));
auto c1 = (C1(s) == 0) ? C1(d) : 255 - std::min(C1(id) * 255 / C1(s), 255);
auto c2 = (C2(s) == 0) ? C2(d) : 255 - std::min(C2(id) * 255 / C2(s), 255);
auto c3 = (C3(s) == 0) ? C3(d) : 255 - std::min(C3(id) * 255 / C3(s), 255);
return JOIN(255, c1, c2, c3);
}
static inline uint32_t opBlendHardLight(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
// if (s < sa), (2 * s * d)
// else (sa * da) - 2 * (da - s) * (sa - d)
auto c1 = (C1(s) < 128) ? std::min(255, 2 * MULTIPLY(C1(s), C1(d))) : (255 - std::min(255, 2 * MULTIPLY(255 - C1(s), 255 - C1(d))));
auto c2 = (C2(s) < 128) ? std::min(255, 2 * MULTIPLY(C2(s), C2(d))) : (255 - std::min(255, 2 * MULTIPLY(255 - C2(s), 255 - C2(d))));
auto c3 = (C3(s) < 128) ? std::min(255, 2 * MULTIPLY(C3(s), C3(d))) : (255 - std::min(255, 2 * MULTIPLY(255 - C3(s), 255 - C3(d))));
@ -472,9 +478,9 @@ static inline uint32_t opBlendHardLight(uint32_t s, uint32_t d, TVG_UNUSED uint8
static inline uint32_t opBlendSoftLight(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{
//(255 - 2 * s) * (d * d) + (2 * s * b)
auto c1 = std::min(255, MULTIPLY(255 - std::min(255, 2 * C1(s)), MULTIPLY(C1(d), C1(d))) + 2 * MULTIPLY(C1(s), C1(d)));
auto c2 = std::min(255, MULTIPLY(255 - std::min(255, 2 * C2(s)), MULTIPLY(C2(d), C2(d))) + 2 * MULTIPLY(C2(s), C2(d)));
auto c3 = std::min(255, MULTIPLY(255 - std::min(255, 2 * C3(s)), MULTIPLY(C3(d), C3(d))) + 2 * MULTIPLY(C3(s), C3(d)));
auto c1 = MULTIPLY(255 - std::min(255, 2 * C1(s)), MULTIPLY(C1(d), C1(d))) + MULTIPLY(std::min(255, 2 * C1(s)), C1(d));
auto c2 = MULTIPLY(255 - std::min(255, 2 * C2(s)), MULTIPLY(C2(d), C2(d))) + MULTIPLY(std::min(255, 2 * C2(s)), C2(d));
auto c3 = MULTIPLY(255 - std::min(255, 2 * C3(s)), MULTIPLY(C3(d), C3(d))) + MULTIPLY(std::min(255, 2 * C3(s)), C3(d));
return JOIN(255, c1, c2, c3);
}
@ -578,14 +584,16 @@ 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 effectGaussianBlurRegion(RenderEffectGaussianBlur* effect);
void effectGaussianBlurUpdate(RenderEffectGaussianBlur* effect, const Matrix& transform);
bool effectDropShadow(SwCompositor* cmp, SwSurface* surfaces[2], const RenderEffectDropShadow* params, bool direct);
bool effectDropShadowPrepare(RenderEffectDropShadow* effect);
bool effectFillPrepare(RenderEffectFill* effect);
bool effectDropShadowRegion(RenderEffectDropShadow* effect);
void effectDropShadowUpdate(RenderEffectDropShadow* effect, const Matrix& transform);
void effectFillUpdate(RenderEffectFill* effect);
bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct);
bool effectTintPrepare(RenderEffectTint* effect);
void effectTintUpdate(RenderEffectTint* effect);
bool effectTint(SwCompositor* cmp, const RenderEffectTint* params, bool direct);
bool effectTritonePrepare(RenderEffectTritone* effect);
void effectTritoneUpdate(RenderEffectTritone* effect);
bool effectTritone(SwCompositor* cmp, const RenderEffectTritone* params, bool direct);
#endif /* _TVG_SW_COMMON_H_ */

View file

@ -32,39 +32,27 @@ struct SwGaussianBlur
static constexpr int MAX_LEVEL = 3;
int level;
int kernel[MAX_LEVEL];
int extends;
};
static void _gaussianExtendRegion(RenderRegion& region, int extra, int8_t direction)
static inline int _gaussianEdgeWrap(int end, int idx)
{
//bbox region expansion for feathering
if (direction != 2) {
region.x = -extra;
region.w = extra * 2;
}
if (direction != 1) {
region.y = -extra;
region.h = extra * 2;
}
auto r = idx % (end + 1);
return (r < 0) ? (end + 1) + r : r;
}
static int _gaussianEdgeWrap(int end, int idx)
{
auto r = idx % end;
return (r < 0) ? end + r : r;
}
static int _gaussianEdgeExtend(int end, int idx)
static inline int _gaussianEdgeExtend(int end, int idx)
{
if (idx < 0) return 0;
else if (idx >= end) return end - 1;
else if (idx > end) return end;
return idx;
}
static int _gaussianRemap(int end, int idx, int border)
template<int border>
static inline int _gaussianRemap(int end, int idx)
{
if (border == 1) return _gaussianEdgeWrap(end, idx);
return _gaussianEdgeExtend(end, idx);
@ -72,7 +60,8 @@ static int _gaussianRemap(int end, int idx, int border)
//TODO: SIMD OPTIMIZATION?
static void _gaussianFilter(uint8_t* dst, uint8_t* src, int32_t stride, int32_t w, int32_t h, const SwBBox& bbox, int32_t dimension, int border, bool flipped)
template<int border = 0>
static void _gaussianFilter(uint8_t* dst, uint8_t* src, int32_t stride, int32_t w, int32_t h, const SwBBox& bbox, int32_t dimension, bool flipped)
{
if (flipped) {
src += (bbox.min.x * stride + bbox.min.y) << 2;
@ -83,6 +72,7 @@ static void _gaussianFilter(uint8_t* dst, uint8_t* src, int32_t stride, int32_t
}
auto iarr = 1.0f / (dimension + dimension + 1);
auto end = w - 1;
#pragma omp parallel for
for (int y = 0; y < h; ++y) {
@ -94,7 +84,7 @@ static void _gaussianFilter(uint8_t* dst, uint8_t* src, int32_t stride, int32_t
//initial accumulation
for (int x = l; x < r; ++x) {
auto id = (_gaussianRemap(w, x, border) + p) * 4;
auto id = (_gaussianRemap<border>(end, x) + p) * 4;
acc[0] += src[id++];
acc[1] += src[id++];
acc[2] += src[id++];
@ -102,16 +92,17 @@ static void _gaussianFilter(uint8_t* dst, uint8_t* src, int32_t stride, int32_t
}
//perform filtering
for (int x = 0; x < w; ++x, ++r, ++l) {
auto rid = (_gaussianRemap(w, r, border) + p) * 4;
auto lid = (_gaussianRemap(w, l, border) + p) * 4;
auto rid = (_gaussianRemap<border>(end, r) + p) * 4;
auto lid = (_gaussianRemap<border>(end, l) + p) * 4;
acc[0] += src[rid++] - src[lid++];
acc[1] += src[rid++] - src[lid++];
acc[2] += src[rid++] - src[lid++];
acc[3] += src[rid] - src[lid];
dst[i++] = static_cast<uint8_t>(acc[0] * iarr + 0.5f);
dst[i++] = static_cast<uint8_t>(acc[1] * iarr + 0.5f);
dst[i++] = static_cast<uint8_t>(acc[2] * iarr + 0.5f);
dst[i++] = static_cast<uint8_t>(acc[3] * iarr + 0.5f);
//ignored rounding for the performance. It should be originally: acc[idx] * iarr + 0.5f
dst[i++] = static_cast<uint8_t>(acc[0] * iarr);
dst[i++] = static_cast<uint8_t>(acc[1] * iarr);
dst[i++] = static_cast<uint8_t>(acc[2] * iarr);
dst[i++] = static_cast<uint8_t>(acc[3] * iarr);
}
}
}
@ -142,27 +133,44 @@ static int _gaussianInit(SwGaussianBlur* data, float sigma, int quality)
}
bool effectGaussianBlurPrepare(RenderEffectGaussianBlur* params)
bool effectGaussianBlurRegion(RenderEffectGaussianBlur* params)
{
auto rd = (SwGaussianBlur*)malloc(sizeof(SwGaussianBlur));
//bbox region expansion for feathering
auto& region = params->extend;
auto extra = static_cast<SwGaussianBlur*>(params->rd)->extends;
auto extends = _gaussianInit(rd, params->sigma * params->sigma, params->quality);
//invalid
if (extends == 0) {
free(rd);
return false;
if (params->direction != 2) {
region.x = -extra;
region.w = extra * 2;
}
if (params->direction != 1) {
region.y = -extra;
region.h = extra * 2;
}
_gaussianExtendRegion(params->extend, extends, params->direction);
params->rd = rd;
params->valid = true;
return true;
}
void effectGaussianBlurUpdate(RenderEffectGaussianBlur* params, const Matrix& transform)
{
if (!params->rd) params->rd = (SwGaussianBlur*)malloc(sizeof(SwGaussianBlur));
auto rd = static_cast<SwGaussianBlur*>(params->rd);
//compute box kernel sizes
auto scale = sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12);
rd->extends = _gaussianInit(rd, std::pow(params->sigma * scale, 2), params->quality);
//invalid
if (rd->extends == 0) {
params->valid = false;
return;
}
params->valid = true;
}
bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffectGaussianBlur* params)
{
auto& buffer = surface->compositor->image;
@ -184,7 +192,7 @@ bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffec
//horizontal
if (params->direction != 2) {
for (int i = 0; i < data->level; ++i) {
_gaussianFilter(reinterpret_cast<uint8_t*>(back), reinterpret_cast<uint8_t*>(front), stride, w, h, bbox, data->kernel[i], params->border, false);
_gaussianFilter(reinterpret_cast<uint8_t*>(back), reinterpret_cast<uint8_t*>(front), stride, w, h, bbox, data->kernel[i], false);
std::swap(front, back);
swapped = !swapped;
}
@ -196,7 +204,7 @@ bool effectGaussianBlur(SwCompositor* cmp, SwSurface* surface, const RenderEffec
std::swap(front, back);
for (int i = 0; i < data->level; ++i) {
_gaussianFilter(reinterpret_cast<uint8_t*>(back), reinterpret_cast<uint8_t*>(front), stride, h, w, bbox, data->kernel[i], params->border, true);
_gaussianFilter(reinterpret_cast<uint8_t*>(back), reinterpret_cast<uint8_t*>(front), stride, h, w, bbox, data->kernel[i], true);
std::swap(front, back);
swapped = !swapped;
}
@ -231,6 +239,7 @@ static void _dropShadowFilter(uint32_t* dst, uint32_t* src, int stride, int w, i
dst += (bbox.min.y * stride + bbox.min.x);
}
auto iarr = 1.0f / (dimension + dimension + 1);
auto end = w - 1;
#pragma omp parallel for
for (int y = 0; y < h; ++y) {
@ -242,15 +251,16 @@ static void _dropShadowFilter(uint32_t* dst, uint32_t* src, int stride, int w, i
//initial accumulation
for (int x = l; x < r; ++x) {
auto id = _gaussianEdgeExtend(w, x) + p;
auto id = _gaussianEdgeExtend(end, x) + p;
acc += A(src[id]);
}
//perform filtering
for (int x = 0; x < w; ++x, ++r, ++l) {
auto rid = _gaussianEdgeExtend(w, r) + p;
auto lid = _gaussianEdgeExtend(w, l) + p;
auto rid = _gaussianEdgeExtend(end, r) + p;
auto lid = _gaussianEdgeExtend(end, l) + p;
acc += A(src[rid]) - A(src[lid]);
dst[i++] = ALPHA_BLEND(color, static_cast<uint8_t>(acc * iarr + 0.5f));
//ignored rounding for the performance. It should be originally: acc * iarr
dst[i++] = ALPHA_BLEND(color, static_cast<uint8_t>(acc * iarr));
}
}
}
@ -281,9 +291,13 @@ static void _dropShadowShift(uint32_t* dst, uint32_t* src, int stride, SwBBox& r
}
static void _dropShadowExtendRegion(RenderRegion& region, int extra, SwPoint& offset)
bool effectDropShadowRegion(RenderEffectDropShadow* params)
{
//bbox region expansion for feathering
auto& region = params->extend;
auto& offset = static_cast<SwDropShadow*>(params->rd)->offset;
auto extra = static_cast<SwDropShadow*>(params->rd)->extends;
region.x = -extra;
region.w = extra * 2;
region.y = -extra;
@ -293,20 +307,24 @@ static void _dropShadowExtendRegion(RenderRegion& region, int extra, SwPoint& of
region.y = std::min(region.y + (int32_t)offset.y, region.y);
region.w += abs(offset.x);
region.h += abs(offset.y);
return true;
}
bool effectDropShadowPrepare(RenderEffectDropShadow* params)
void effectDropShadowUpdate(RenderEffectDropShadow* params, const Matrix& transform)
{
auto rd = (SwDropShadow*)malloc(sizeof(SwDropShadow));
if (!params->rd) params->rd = (SwDropShadow*)malloc(sizeof(SwDropShadow));
auto rd = static_cast<SwDropShadow*>(params->rd);
//compute box kernel sizes
auto extends = _gaussianInit(rd, params->sigma * params->sigma, params->quality);
auto scale = sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12);
rd->extends = _gaussianInit(rd, std::pow(params->sigma * scale, 2), params->quality);
//invalid
if (extends == 0 || params->color[3] == 0) {
free(rd);
return false;
if (rd->extends == 0 || params->color[3] == 0) {
params->valid = false;
return;
}
//offset
@ -317,13 +335,7 @@ bool effectDropShadowPrepare(RenderEffectDropShadow* params)
rd->offset = {0, 0};
}
//bbox region expansion for feathering
_dropShadowExtendRegion(params->extend, extends, rd->offset);
params->rd = rd;
params->valid = true;
return true;
}
@ -405,10 +417,9 @@ bool effectDropShadow(SwCompositor* cmp, SwSurface* surface[2], const RenderEffe
/* Fill Implementation */
/************************************************************************/
bool effectFillPrepare(RenderEffectFill* params)
void effectFillUpdate(RenderEffectFill* params)
{
params->valid = true;
return true;
}
@ -456,10 +467,9 @@ bool effectFill(SwCompositor* cmp, const RenderEffectFill* params, bool direct)
/* Tint Implementation */
/************************************************************************/
bool effectTintPrepare(RenderEffectTint* params)
void effectTintUpdate(RenderEffectTint* params)
{
params->valid = true;
return true;
}
@ -529,10 +539,10 @@ static uint32_t _trintone(uint32_t s, uint32_t m, uint32_t h, int l)
}
}
bool effectTritonePrepare(RenderEffectTritone* params)
void effectTritoneUpdate(RenderEffectTritone* params)
{
params->valid = true;
return true;
}

View file

@ -22,7 +22,7 @@
#ifdef _WIN32
#include <malloc.h>
#elif defined(__linux__)
#elif defined(__linux__) || defined(__ZEPHYR__)
#include <alloca.h>
#else
#include <stdlib.h>

View file

@ -75,197 +75,8 @@ static bool _arrange(const SwImage* image, const SwBBox* region, int& yStart, in
static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag = 0)
{
TVGERR("SW_ENGINE", "TODO: _rasterMaskedPolygonImageSegment()");
return false;
#if 0 //Enable it when GRAYSCALE image is supported
auto maskOp = _getMaskOp(surface->compositor->method);
auto direct = _direct(surface->compositor->method);
float _dudx = dudx, _dvdx = dvdx;
float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya;
float _xa = xa, _xb = xb, _ua = ua, _va = va;
auto sbuf = image->buf8;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = 0;
float dx, u, v, iptr;
SwSpan* span = nullptr; //used only when rle based.
if (!_arrange(image, region, yStart, yEnd)) return false;
//Loop through all lines in the segment
uint32_t spanIdx = 0;
if (region) {
minx = region->min.x;
maxx = region->max.x;
} else {
span = image->rle->spans;
while (span->y < yStart) {
++span;
++spanIdx;
}
}
y = yStart;
while (y < yEnd) {
x1 = (int32_t)_xa;
x2 = (int32_t)_xb;
if (!region) {
minx = INT32_MAX;
maxx = 0;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
++spanIdx;
}
}
if (x1 < minx) x1 = minx;
if (x2 > maxx) x2 = maxx;
//Anti-Aliasing frames
ay = y - aaSpans->yStart;
if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1;
if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2;
//Range allowed
if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) {
//Perform subtexel pre-stepping on UV
dx = 1 - (_xa - x1);
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
x = x1;
auto cmp = &surface->compositor->image.buf8[y * surface->compositor->image.stride + x1];
auto dst = &surface->buf8[y * surface->stride + x1];
if (opacity == 255) {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
if (uu >= sw) continue;
vv = (int) v;
if (vv >= sh) continue;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
if (direct) {
auto tmp = maskOp(px, *cmp, 0); //not use alpha
*dst = tmp + MULTIPLY(*dst, ~tmp);
++dst;
} else {
*cmp = maskOp(px, *cmp, ~px);
}
++cmp;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
} else {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
if (uu >= sw) continue;
vv = (int) v;
if (vv >= sh) continue;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
}
if (direct) {
auto tmp = maskOp(MULTIPLY(px, opacity), *cmp, 0);
*dst = tmp + MULTIPLY(*dst, ~tmp);
++dst;
} else {
auto tmp = MULTIPLY(px, opacity);
*cmp = maskOp(tmp, *cmp, ~px);
}
++cmp;
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
}
}
//Step along both edges
_xa += _dxdya;
_xb += _dxdyb;
_ua += _dudya;
_va += _dvdya;
if (!region && spanIdx >= image->rle->size) break;
++y;
}
xa = _xa;
xb = _xb;
ua = _ua;
va = _va;
return true;
#endif
}
@ -276,9 +87,8 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
float _xa = xa, _xb = xb, _ua = ua, _va = va;
auto sbuf = image->buf32;
auto dbuf = surface->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t dw = surface->stride;
int32_t sw = static_cast<int32_t>(image->w);
int32_t sh = static_cast<int32_t>(image->h);
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = 0;
@ -335,7 +145,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
buf = dbuf + ((y * dw) + x1);
buf = dbuf + ((y * surface->stride) + x1);
x = x1;
@ -343,32 +153,32 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
if (uu >= sw) continue;
vv = (int) v;
if (vv >= sh) continue;
if ((uint32_t) uu >= image->w || (uint32_t) vv >= image->h) continue;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
px = *(sbuf + (vv * sw) + uu);
px = *(sbuf + (vv * image->stride) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
int px2 = *(sbuf + (vv * image->stride) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
int px2 = *(sbuf + (irv * image->stride) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
int px3 = *(sbuf + (irv * image->stride) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
@ -379,39 +189,37 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
} else {
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
if (uu >= sw) continue;
vv = (int) v;
if (vv >= sh) continue;
if ((uint32_t) uu >= image->w || (uint32_t) vv >= image->h) continue;
ar = (int)(255 * (1 - modff(u, &iptr)));
ab = (int)(255 * (1 - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
px = *(sbuf + (vv * sw) + uu);
px = *(sbuf + (vv * image->stride) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
int px2 = *(sbuf + (vv * image->stride) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
int px2 = *(sbuf + (irv * image->stride) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
int px3 = *(sbuf + (irv * image->stride) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
@ -423,8 +231,6 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
}
}
@ -453,9 +259,8 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
float _xa = xa, _xb = xb, _ua = ua, _va = va;
auto sbuf = image->buf32;
auto dbuf = surface->buf32;
int32_t sw = static_cast<int32_t>(image->stride);
int32_t sh = image->h;
int32_t dw = surface->stride;
int32_t sw = static_cast<int32_t>(image->w);
int32_t sh = static_cast<int32_t>(image->h);
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
int32_t minx = INT32_MAX, maxx = 0;
@ -517,7 +322,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
u = _ua + dx * _dudx;
v = _va + dx * _dvdx;
buf = dbuf + ((y * dw) + x1);
buf = dbuf + ((y * surface->stride) + x1);
x = x1;
@ -527,32 +332,32 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
//Draw horizontal line
while (x++ < x2) {
uu = (int) u;
if (uu >= sw) continue;
vv = (int) v;
if (vv >= sh) continue;
if ((uint32_t) uu >= image->w || (uint32_t) vv >= image->h) continue;
ar = (int)(255.0f * (1.0f - modff(u, &iptr)));
ab = (int)(255.0f * (1.0f - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
px = *(sbuf + (vv * sw) + uu);
px = *(sbuf + (vv * image->stride) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
int px2 = *(sbuf + (vv * image->stride) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
int px2 = *(sbuf + (irv * image->stride) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
int px3 = *(sbuf + (irv * image->stride) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
@ -570,8 +375,6 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
} else {
//Draw horizontal line
@ -579,30 +382,30 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
uu = (int) u;
vv = (int) v;
if ((uint32_t) uu >= image->w || (uint32_t) vv >= image->h) continue;
ar = (int)(255.0f * (1.0f - modff(u, &iptr)));
ab = (int)(255.0f * (1.0f - modff(v, &iptr)));
iru = uu + 1;
irv = vv + 1;
if (vv >= sh) continue;
px = *(sbuf + (vv * sw) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* right pixel */
int px2 = *(sbuf + (vv * sw) + iru);
int px2 = *(sbuf + (vv * image->stride) + iru);
px = INTERPOLATE(px, px2, ar);
}
/* vertical interpolate */
if (irv < sh) {
/* bottom pixel */
int px2 = *(sbuf + (irv * sw) + uu);
int px2 = *(sbuf + (irv * image->stride) + uu);
/* horizontal interpolate */
if (iru < sw) {
/* bottom right pixel */
int px3 = *(sbuf + (irv * sw) + iru);
int px3 = *(sbuf + (irv * image->stride) + iru);
px2 = INTERPOLATE(px2, px3, ar);
}
px = INTERPOLATE(px, px2, ab);
@ -620,8 +423,6 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
//Step UV horizontally
u += _dudx;
v += _dvdx;
//range over?
if ((uint32_t)v >= image->h) break;
}
}
}

View file

@ -574,7 +574,7 @@ SwSurface* SwRenderer::request(int channelSize, bool square)
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->stride = cmp->compositor->image.stride = w;
cmp->compositor->image.direct = true;
cmp->compositor->valid = true;
cmp->channelSize = cmp->compositor->image.channelSize = channelSize;
@ -655,23 +655,31 @@ bool SwRenderer::endComposite(RenderCompositor* cmp)
}
bool SwRenderer::prepare(RenderEffect* effect)
void SwRenderer::prepare(RenderEffect* effect, const Matrix& transform)
{
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));
case SceneEffect::GaussianBlur: effectGaussianBlurUpdate(static_cast<RenderEffectGaussianBlur*>(effect), transform); break;
case SceneEffect::DropShadow: effectDropShadowUpdate(static_cast<RenderEffectDropShadow*>(effect), transform); break;
case SceneEffect::Fill: effectFillUpdate(static_cast<RenderEffectFill*>(effect)); break;
case SceneEffect::Tint: effectTintUpdate(static_cast<RenderEffectTint*>(effect)); break;
case SceneEffect::Tritone: effectTritoneUpdate(static_cast<RenderEffectTritone*>(effect)); break;
default: break;
}
}
bool SwRenderer::region(RenderEffect* effect)
{
switch (effect->type) {
case SceneEffect::GaussianBlur: return effectGaussianBlurRegion(static_cast<RenderEffectGaussianBlur*>(effect));
case SceneEffect::DropShadow: return effectDropShadowRegion(static_cast<RenderEffectDropShadow*>(effect));
default: return false;
}
}
bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct)
bool SwRenderer::render(RenderCompositor* cmp, const RenderEffect* effect, bool direct)
{
if (!effect->valid) return false;
auto p = static_cast<SwCompositor*>(cmp);
if (p->image.channelSize != sizeof(uint32_t)) {

View file

@ -60,8 +60,9 @@ public:
bool endComposite(RenderCompositor* cmp) override;
void clearCompositors();
bool prepare(RenderEffect* effect) override;
bool effect(RenderCompositor* cmp, const RenderEffect* effect, bool direct) override;
void prepare(RenderEffect* effect, const Matrix& transform) override;
bool region(RenderEffect* effect) override;
bool render(RenderCompositor* cmp, const RenderEffect* effect, bool direct) override;
static SwRenderer* gen();
static bool init(uint32_t threads);

View file

@ -95,7 +95,7 @@ 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;
if (begin < 0.0f || end > 1.0f || begin > end) return Result::InvalidArguments;
auto loader = pImpl->picture->pImpl->loader;
if (!loader) return Result::InsufficientCondition;

View file

@ -76,7 +76,7 @@ struct Fill::Impl
ret->pImpl->cnt = cnt;
ret->pImpl->spread = spread;
ret->pImpl->colorStops = static_cast<ColorStop*>(malloc(sizeof(ColorStop) * cnt));
memcpy(ret->pImpl->colorStops, colorStops, sizeof(ColorStop) * cnt);
if (cnt > 0) memcpy(ret->pImpl->colorStops, colorStops, sizeof(ColorStop) * cnt);
if (transform) {
ret->pImpl->transform = static_cast<Matrix*>(malloc(sizeof(Matrix)));
*ret->pImpl->transform = *transform;

View file

@ -352,7 +352,7 @@ struct RenderEffectTint : RenderEffect
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->intensity = (uint8_t)(va_arg(args, double) * 2.55);
inst->type = SceneEffect::Tint;
return inst;
}
@ -413,8 +413,9 @@ public:
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, bool direct) = 0;
virtual void prepare(RenderEffect* effect, const Matrix& transform) = 0;
virtual bool region(RenderEffect* effect) = 0;
virtual bool render(RenderCompositor* cmp, const RenderEffect* effect, bool direct) = 0;
};
static inline bool MASK_REGION_MERGING(CompositeMethod method)

View file

@ -121,6 +121,12 @@ struct Scene::Impl
paint->pImpl->update(renderer, transform, clips, opacity, flag, false);
}
if (effects) {
for (auto e = effects->begin(); e < effects->end(); ++e) {
renderer->prepare(*e, transform);
}
}
return nullptr;
}
@ -146,7 +152,7 @@ struct Scene::Impl
//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, direct);
if ((*e)->valid) renderer->render(cmp, *e, direct);
}
}
renderer->endComposite(cmp);
@ -179,7 +185,7 @@ struct Scene::Impl
if (effects) {
for (auto e = effects->begin(); e < effects->end(); ++e) {
auto effect = *e;
if (effect->valid || renderer->prepare(effect)) {
if (effect->valid && renderer->region(effect)) {
ex = std::min(ex, effect->extend.x);
ey = std::min(ey, effect->extend.y);
ew = std::max(ew, effect->extend.w);

View file

@ -1,6 +1,6 @@
#!/bin/bash -e
VERSION=0.15.8
VERSION=0.15.10
# Uncomment and set a git hash to use specific commit instead of tag.
#GIT_COMMIT=