From f16d4af3422ba167e211bcffa9186d6d88a4f228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 27 Aug 2024 15:54:05 +0200 Subject: [PATCH] thorvg: Update to 0.14.7 Fixes #95861. --- thirdparty/README.md | 2 +- thirdparty/thorvg/inc/config.h | 2 +- thirdparty/thorvg/inc/thorvg.h | 150 +++++++++--------- thirdparty/thorvg/src/common/tvgArray.h | 2 +- .../thorvg/src/common/tvgCompressor.cpp | 2 + thirdparty/thorvg/src/common/tvgInlist.h | 2 +- thirdparty/thorvg/src/common/tvgLines.cpp | 2 +- thirdparty/thorvg/src/common/tvgLock.h | 2 - thirdparty/thorvg/src/common/tvgMath.h | 19 ++- .../thorvg/src/loaders/svg/tvgSvgLoader.cpp | 7 +- .../src/renderer/sw_engine/tvgSwCommon.h | 31 ++-- .../src/renderer/sw_engine/tvgSwFill.cpp | 70 ++++---- .../src/renderer/sw_engine/tvgSwImage.cpp | 68 ++------ .../src/renderer/sw_engine/tvgSwMath.cpp | 8 +- .../src/renderer/sw_engine/tvgSwRaster.cpp | 106 ++++++++----- .../renderer/sw_engine/tvgSwRasterTexmap.h | 112 ++++--------- .../src/renderer/sw_engine/tvgSwRenderer.cpp | 122 ++------------ .../src/renderer/sw_engine/tvgSwRenderer.h | 7 +- .../src/renderer/sw_engine/tvgSwRle.cpp | 81 +--------- .../src/renderer/sw_engine/tvgSwShape.cpp | 38 ++--- .../src/renderer/sw_engine/tvgSwStroke.cpp | 11 +- .../thorvg/src/renderer/tvgAccessor.cpp | 41 +++-- .../thorvg/src/renderer/tvgAnimation.cpp | 2 +- thirdparty/thorvg/src/renderer/tvgCanvas.h | 6 +- .../thorvg/src/renderer/tvgInitializer.cpp | 42 ++--- thirdparty/thorvg/src/renderer/tvgPaint.cpp | 142 +++++++++-------- thirdparty/thorvg/src/renderer/tvgPaint.h | 63 +++++--- thirdparty/thorvg/src/renderer/tvgPicture.cpp | 43 ++--- thirdparty/thorvg/src/renderer/tvgPicture.h | 80 +++------- thirdparty/thorvg/src/renderer/tvgRender.cpp | 35 ---- thirdparty/thorvg/src/renderer/tvgRender.h | 95 +++++++---- thirdparty/thorvg/src/renderer/tvgScene.h | 28 ++-- thirdparty/thorvg/src/renderer/tvgShape.h | 79 +++++---- .../thorvg/src/renderer/tvgTaskScheduler.h | 2 - thirdparty/thorvg/src/renderer/tvgText.cpp | 13 +- thirdparty/thorvg/src/renderer/tvgText.h | 59 +++---- thirdparty/thorvg/update-thorvg.sh | 2 +- 37 files changed, 665 insertions(+), 911 deletions(-) diff --git a/thirdparty/README.md b/thirdparty/README.md index a71c189fca66..799eb97cd27f 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -909,7 +909,7 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.14.2 (f6c4d8a94e0b2194fe911d6e19a550683055dd50, 2024) +- Version: 0.14.7 (e3a6bf5229a9671c385ee78bc33e6e6b611a9729, 2024) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 8c185ccbcabc..67ebc9381ede 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -15,5 +15,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.14.2" +#define THORVG_VERSION_STRING "0.14.7" #endif diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index 47414d851a2e..4303092a5ea7 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/thirdparty/thorvg/inc/thorvg.h @@ -157,7 +157,7 @@ enum class FillRule enum class CompositeMethod { None = 0, ///< No composition is applied. - ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered. + ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered. Note that ClipPath only supports the Shape type. AlphaMask, ///< Alpha Masking using the compositing target's pixels as an alpha value. InvAlphaMask, ///< Alpha Masking using the complement to the compositing target's pixels as an alpha value. LumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the compositing target's pixels. @since 0.9 @@ -165,7 +165,9 @@ enum class CompositeMethod AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) (Experimental API) SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) (Experimental API) IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) (Experimental API) - DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) (Experimental API) + DifferenceMask, ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) (Experimental API) + LightenMask, ///< Where multiple masks intersect, the highest transparency value is used. (Experimental API) + DarkenMask ///< Where multiple masks intersect, the lowest transparency value is used. (Experimental API) }; @@ -232,34 +234,6 @@ struct Matrix }; -/** - * @brief A data structure representing a texture mesh vertex - * - * @param pt The vertex coordinate - * @param uv The normalized texture coordinate in the range (0.0..1.0, 0.0..1.0) - * - * @note Experimental API - */ -struct Vertex -{ - Point pt; - Point uv; -}; - - -/** - * @brief A data structure representing a triange in a texture mesh - * - * @param vertex The three vertices that make up the polygon - * - * @note Experimental API - */ -struct Polygon -{ - Vertex vertex[3]; -}; - - /** * @class Paint * @@ -361,7 +335,7 @@ class TVG_API Paint * * @note Experimental API */ - Result blend(BlendMethod method) const noexcept; + Result blend(BlendMethod method) noexcept; /** * @deprecated Use bounds(float* x, float* y, float* w, float* h, bool transformed) instead @@ -371,15 +345,16 @@ class TVG_API Paint /** * @brief Gets the axis-aligned bounding box of the paint object. * - * In case @p transform is @c true, all object's transformations are applied first, and then the bounding box is established. Otherwise, the bounding box is determined before any transformations. - * - * @param[out] x The x coordinate of the upper left corner of the object. - * @param[out] y The y coordinate of the upper left corner of the object. + * @param[out] x The x-coordinate of the upper-left corner of the object. + * @param[out] y The y-coordinate of the upper-left corner of the object. * @param[out] w The width of the object. * @param[out] h The height of the object. - * @param[in] transformed If @c true, the paint's transformations are taken into account, otherwise they aren't. + * @param[in] transformed If @c true, the paint's transformations are taken into account in the scene it belongs to. Otherwise they aren't. * + * @note This is useful when you need to figure out the bounding box of the paint in the canvas space. * @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object. + * @note If @p transformed is @c true, the paint needs to be pushed into a canvas and updated before this api is called. + * @see Canvas::update() */ Result bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept; @@ -411,9 +386,9 @@ class TVG_API Paint CompositeMethod composite(const Paint** target) const noexcept; /** - * @brief Gets the blending method of the object. + * @brief Retrieves the current blending method applied to the paint object. * - * @return The blending method + * @return The currently set blending method. * * @note Experimental API */ @@ -428,6 +403,15 @@ class TVG_API Paint */ uint32_t identifier() const noexcept; + /** + * @brief Unique ID of this instance. + * + * This is reserved to specify an paint instance in a scene. + * + * @since Experimental API + */ + uint32_t id = 0; + _TVG_DECLARE_PRIVATE(Paint); }; @@ -675,7 +659,8 @@ class TVG_API LinearGradient final : public Fill * @param[in] x2 The horizontal coordinate of the second point used to determine the gradient bounds. * @param[in] y2 The vertical coordinate of the second point used to determine the gradient bounds. * - * @note In case the first and the second points are equal, an object filled with such a gradient fill is not rendered. + * @note In case the first and the second points are equal, an object is filled with a single color using the last color specified in the colorStops(). + * @see Fill::colorStops() */ Result linear(float x1, float y1, float x2, float y2) noexcept; @@ -734,6 +719,8 @@ class TVG_API RadialGradient final : public Fill * @param[in] radius The radius of the bounding circle. * * @retval Result::InvalidArguments in case the @p radius value is zero or less. + * + * @note In case the @p radius is zero, an object is filled with a single color using the last color specified in the colorStops(). */ Result radial(float cx, float cy, float radius) noexcept; @@ -990,7 +977,7 @@ class TVG_API Shape final : public Paint /** * @brief Sets the trim of the stroke along the defined path segment, allowing control over which part of the stroke is visible. * - * The values of the arguments @p begin, @p end, and @p offset are in the range of 0.0 to 1.0, representing the beginning of the path and the end, respectively. + * If the values of the arguments @p begin and @p end exceed the 0-1 range, they are wrapped around in a manner similar to angle wrapping, effectively treating the range as circular. * * @param[in] begin Specifies the start of the segment to display along the path. * @param[in] end Specifies the end of the segment to display along the path. @@ -1076,7 +1063,6 @@ class TVG_API Shape final : public Paint * @param[out] b The blue color channel value in the range [0 ~ 255]. * @param[out] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. * - * @return Result::Success when succeed. */ Result fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a = nullptr) const noexcept; @@ -1219,7 +1205,7 @@ class TVG_API Picture final : public Paint * when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations * for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data. * - * @param[in] data A pointer to a memory location where the content of the picture file is stored. + * @param[in] data A pointer to a memory location where the content of the picture file is stored. A null-terminated string is expected for non-binary data if @p copy is @c false. * @param[in] size The size in bytes of the memory occupied by the @p data. * @param[in] mimeType Mimetype or extension of data such as "jpg", "jpeg", "lottie", "svg", "svg+xml", "png", etc. In case an empty string or an unknown type is provided, the loaders will be tried one by one. * @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not. @@ -1256,7 +1242,7 @@ class TVG_API Picture final : public Paint Result size(float* w, float* h) const noexcept; /** - * @brief Loads a raw data from a memory block with a given size. + * @brief Loads raw data in ARGB8888 format from a memory block of the given size. * * ThorVG efficiently caches the loaded data using the specified @p data address as a key * when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations @@ -1265,47 +1251,27 @@ class TVG_API Picture final : public Paint * @param[in] data A pointer to a memory location where the content of the picture raw data is stored. * @param[in] w The width of the image @p data in pixels. * @param[in] h The height of the image @p data in pixels. - * @param[in] premultiplied If @c true, the given image data is alpha-premultiplied. * @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not. * + * @note It expects premultiplied alpha data. * @since 0.9 */ Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy) noexcept; /** - * @brief Sets or removes the triangle mesh to deform the image. - * - * If a mesh is provided, the transform property of the Picture will apply to the triangle mesh, and the - * image data will be used as the texture. - * - * If @p triangles is @c nullptr, or @p triangleCnt is 0, the mesh will be removed. - * - * Only raster image types are supported at this time (png, jpg). Vector types like svg and tvg do not support. - * mesh deformation. However, if required you should be able to render a vector image to a raster image and then apply a mesh. + * @brief Retrieve a paint object from the Picture scene by its Unique ID. * - * @param[in] triangles An array of Polygons(triangles) that make up the mesh, or null to remove the mesh. - * @param[in] triangleCnt The number of Polygons(triangles) provided, or 0 to remove the mesh. + * This function searches for a paint object within the Picture scene that matches the provided @p id. * - * @note The Polygons are copied internally, so modifying them after calling Mesh::mesh has no affect. - * @warning Please do not use it, this API is not official one. It could be modified in the next version. + * @param[in] id The Unique ID of the paint object. * - * @note Experimental API - */ - Result mesh(const Polygon* triangles, uint32_t triangleCnt) noexcept; - - /** - * @brief Return the number of triangles in the mesh, and optionally get a pointer to the array of triangles in the mesh. + * @return A pointer to the paint object that matches the given identifier, or @c nullptr if no matching paint object is found. * - * @param[out] triangles Optional. A pointer to the array of Polygons used by this mesh. - * - * @return The number of polygons in the array. - * - * @note Modifying the triangles returned by this method will modify them directly within the mesh. - * @warning Please do not use it, this API is not official one. It could be modified in the next version. + * @see Accessor::id() * * @note Experimental API */ - uint32_t mesh(const Polygon** triangles) const noexcept; + const Paint* paint(uint32_t id) noexcept; /** * @brief Creates a new Picture object. @@ -1454,8 +1420,6 @@ class TVG_API Text final : public Paint * @param[in] g The green color channel value in the range [0 ~ 255]. The default value is 0. * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0. * - * @retval Result::InsufficientCondition when the font has not been set up prior to this operation. - * * @see Text::font() * * @note Experimental API @@ -1469,8 +1433,6 @@ class TVG_API Text final : public Paint * * @param[in] f The unique pointer to the gradient fill. * - * @retval Result::InsufficientCondition when the font has not been set up prior to this operation. - * * @note Either a solid color or a gradient fill is applied, depending on what was set as last. * @note Experimental API * @@ -1781,6 +1743,19 @@ class TVG_API Initializer final */ static Result term(CanvasEngine engine) noexcept; + /** + * @brief Retrieves the version of the TVG engine. + * + * @param[out] major A major version number. + * @param[out] minor A minor version number. + * @param[out] micro A micro version number. + * + * @return The version of the engine in the format major.minor.micro, or a @p nullptr in case of an internal error. + * + * @note Experimental API + */ + static const char* version(uint32_t* major, uint32_t* minor, uint32_t* micro) noexcept; + _TVG_DISABLE_CTOR(Initializer); }; @@ -1879,7 +1854,7 @@ class TVG_API Animation * @retval Result::InsufficientCondition In case the animation is not loaded. * @retval Result::NonSupport When it's not animatable. * - * @note Range from 0.0~1.0 + * @note Animation allows a range from 0.0 to 1.0. @p end should not be higher than @p begin. * @note If a marker has been specified, its range will be disregarded. * @see LottieAnimation::segment(const char* marker) * @note Experimental API @@ -2030,17 +2005,36 @@ class TVG_API Accessor final public: ~Accessor(); + TVG_DEPRECATED std::unique_ptr set(std::unique_ptr picture, std::function func) noexcept; + /** * @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] func The callback function calling for every paint nodes of the Picture. - * - * @return Return the given @p picture instance. + * @param[in] data Data passed to the @p func as its argument. * * @note The bitmap based picture might not have the scene-tree. + * + * @note Experimental API + */ + Result set(const Picture* picture, std::function func, void* data) noexcept; + + /** + * @brief Generate a unique ID (hash key) from a given name. + * + * This function computes a unique identifier value based on the provided string. + * You can use this to assign a unique ID to the Paint object. + * + * @param[in] name The input string to generate the unique identifier from. + * + * @return The generated unique identifier value. + * + * @see Paint::id + * + * @note Experimental API */ - std::unique_ptr set(std::unique_ptr picture, std::function func) noexcept; + static uint32_t id(const char* name) noexcept; /** * @brief Creates a new Accessor object. diff --git a/thirdparty/thorvg/src/common/tvgArray.h b/thirdparty/thorvg/src/common/tvgArray.h index 8178bd0e420c..19c8f6972600 100644 --- a/thirdparty/thorvg/src/common/tvgArray.h +++ b/thirdparty/thorvg/src/common/tvgArray.h @@ -59,7 +59,7 @@ struct Array data[count++] = element; } - void push(Array& rhs) + void push(const Array& rhs) { if (rhs.count == 0) return; grow(rhs.count); diff --git a/thirdparty/thorvg/src/common/tvgCompressor.cpp b/thirdparty/thorvg/src/common/tvgCompressor.cpp index b61718f9a7b8..aebe9a4ef164 100644 --- a/thirdparty/thorvg/src/common/tvgCompressor.cpp +++ b/thirdparty/thorvg/src/common/tvgCompressor.cpp @@ -478,6 +478,8 @@ size_t b64Decode(const char* encoded, const size_t len, char** decoded) unsigned long djb2Encode(const char* str) { + if (!str) return 0; + unsigned long hash = 5381; int c; diff --git a/thirdparty/thorvg/src/common/tvgInlist.h b/thirdparty/thorvg/src/common/tvgInlist.h index ff28cfd48ea4..fc99ae3d14fb 100644 --- a/thirdparty/thorvg/src/common/tvgInlist.h +++ b/thirdparty/thorvg/src/common/tvgInlist.h @@ -100,7 +100,7 @@ struct Inlist if (element == tail) tail = element->prev; } - bool empty() + bool empty() const { return head ? false : true; } diff --git a/thirdparty/thorvg/src/common/tvgLines.cpp b/thirdparty/thorvg/src/common/tvgLines.cpp index 9d704900a50e..49d992f127db 100644 --- a/thirdparty/thorvg/src/common/tvgLines.cpp +++ b/thirdparty/thorvg/src/common/tvgLines.cpp @@ -79,7 +79,7 @@ float _bezAt(const Bezier& bz, float at, float length, LengthFunc lineLengthFunc Bezier left; bezSplitLeft(right, t, left); length = _bezLength(left, lineLengthFunc); - if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) { + if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < 1e-3f) { break; } if (length < at) { diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h index 59f68d0d44ba..d3a4e41c5cfd 100644 --- a/thirdparty/thorvg/src/common/tvgLock.h +++ b/thirdparty/thorvg/src/common/tvgLock.h @@ -25,8 +25,6 @@ #ifdef THORVG_THREAD_SUPPORT -#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR - #include #include "tvgTaskScheduler.h" diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h index 668260c6896d..556ed410fff4 100644 --- a/thirdparty/thorvg/src/common/tvgMath.h +++ b/thirdparty/thorvg/src/common/tvgMath.h @@ -78,17 +78,17 @@ bool mathIdentity(const Matrix* m); Matrix operator*(const Matrix& lhs, const Matrix& rhs); bool operator==(const Matrix& lhs, const Matrix& rhs); -static inline bool mathRightAngle(const Matrix* m) +static inline bool mathRightAngle(const Matrix& m) { - auto radian = fabsf(mathAtan2(m->e21, m->e11)); + auto radian = fabsf(mathAtan2(m.e21, m.e11)); if (radian < FLOAT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true; return false; } -static inline bool mathSkewed(const Matrix* m) +static inline bool mathSkewed(const Matrix& m) { - return !mathZero(m->e21 + m->e12); + return !mathZero(m.e21 + m.e12); } @@ -233,6 +233,17 @@ static inline Point operator/(const Point& lhs, const float rhs) } +static inline Point mathNormal(const Point& p1, const Point& p2) +{ + auto dir = p2 - p1; + auto len = mathLength(dir); + if (mathZero(len)) return {}; + + auto unitDir = dir / len; + return {-unitDir.y, unitDir.x}; +} + + static inline void mathLog(const Point& pt) { TVGLOG("COMMON", "Point: [%f %f]", pt.x, pt.y); diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index 8fbf3816ea84..197d3cc13a58 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -710,15 +710,16 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** return true; } else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') { float th, ts, tb; - const char *content, *hue, *saturation, *brightness; - content = str + 4; - content = _skipSpace(content, nullptr); + const char* content = _skipSpace(str + 4, nullptr); + const char* hue = nullptr; if (_parseNumber(&content, &hue, &th) && hue) { + const char* saturation = nullptr; th = float(uint32_t(th) % 360); hue = _skipSpace(hue, nullptr); hue = (char*)_skipComma(hue); hue = _skipSpace(hue, nullptr); if (_parseNumber(&hue, &saturation, &ts) && saturation && *saturation == '%') { + const char* brightness = nullptr; ts /= 100.0f; saturation = _skipSpace(saturation + 1, nullptr); saturation = (char*)_skipComma(saturation); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h index 05cbdc7f3a09..3229eb39ba38 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h @@ -134,7 +134,6 @@ struct SwFill { struct SwLinear { float dx, dy; - float len; float offset; }; @@ -154,6 +153,7 @@ struct SwFill uint32_t* ctable; FillSpread spread; + bool solid = false; //solid color fill with the last color from colorStops bool translucent; }; @@ -301,8 +301,8 @@ static inline uint32_t JOIN(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) static inline uint32_t ALPHA_BLEND(uint32_t c, uint32_t a) { - return (((((c >> 8) & 0x00ff00ff) * a + 0x00ff00ff) & 0xff00ff00) + - ((((c & 0x00ff00ff) * a + 0x00ff00ff) >> 8) & 0x00ff00ff)); + ++a; + return (((((c >> 8) & 0x00ff00ff) * a) & 0xff00ff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff)); } static inline uint32_t INTERPOLATE(uint32_t s, uint32_t d, uint8_t a) @@ -494,38 +494,39 @@ SwFixed mathDiff(SwFixed angle1, SwFixed angle2); SwFixed mathLength(const SwPoint& pt); bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); SwFixed mathMean(SwFixed angle1, SwFixed angle2); -SwPoint mathTransform(const Point* to, const Matrix* transform); +SwPoint mathTransform(const Point* to, const Matrix& transform); bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack); bool mathClipBBox(const SwBBox& clipper, SwBBox& clipee); void shapeReset(SwShape* shape); -bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite); +bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite); bool shapePrepared(const SwShape* shape); bool shapeGenRle(SwShape* shape, const RenderShape* rshape, bool antiAlias); void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid); -void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform); -bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid); +void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix& transform); +bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape* shape); -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable); -bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable); +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable); +bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable); void shapeResetFill(SwShape* shape); void shapeResetStrokeFill(SwShape* shape); void shapeDelFill(SwShape* shape); void shapeDelStrokeFill(SwShape* shape); -void strokeReset(SwStroke* stroke, const RenderShape* shape, const Matrix* transform); +void strokeReset(SwStroke* stroke, const RenderShape* shape, const Matrix& transform); bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid); void strokeFree(SwStroke* stroke); -bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid); +bool imagePrepare(SwImage* image, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid); bool imageGenRle(SwImage* image, const SwBBox& renderRegion, bool antiAlias); void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid); void imageReset(SwImage* image); void imageFree(SwImage* image); -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable); +const Fill::ColorStop* fillFetchSolid(const SwFill* fill, const Fill* fdata); void fillReset(SwFill* fill); void fillFree(SwFill* fill); @@ -561,11 +562,11 @@ SwOutline* mpoolReqDashOutline(SwMpool* mpool, unsigned idx); void mpoolRetDashOutline(SwMpool* mpool, unsigned idx); bool rasterCompositor(SwSurface* surface); -bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id); +bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity); bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& bbox, uint8_t opacity); +bool rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& bbox, uint8_t opacity); bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id); +bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity); bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h); void rasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len); void rasterGrayscale8(uint8_t *dst, uint8_t val, uint32_t offset, int32_t len); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp index bd0b5ffdcbbf..631294ad40be 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp @@ -58,7 +58,7 @@ static void _calculateCoefficients(const SwFill* fill, uint32_t x, uint32_t y, f auto deltaDeltaRr = 2.0f * (radial->a11 * radial->a11 + radial->a21 * radial->a21) * radial->invA; det = b * b + (rr - radial->fr * radial->fr) * radial->invA; - deltaDet = 2.0f * b * deltaB + deltaB * deltaB + deltaRr + deltaDeltaRr; + deltaDet = 2.0f * b * deltaB + deltaB * deltaB + deltaRr + deltaDeltaRr * 0.5f; deltaDeltaDet = 2.0f * deltaB * deltaB + deltaDeltaRr; } @@ -125,6 +125,8 @@ static void _applyAA(const SwFill* fill, uint32_t begin, uint32_t end) static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* surface, uint8_t opacity) { + if (fill->solid) return true; + if (!fill->ctable) { fill->ctable = static_cast(malloc(GRADIENT_STOP_SIZE * sizeof(uint32_t))); if (!fill->ctable) return false; @@ -205,28 +207,33 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* } -bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* transform) +bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix& transform) { float x1, x2, y1, y2; if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; fill->linear.dx = x2 - x1; fill->linear.dy = y2 - y1; - fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; + auto len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; - if (fill->linear.len < FLOAT_EPSILON) return true; + if (len < FLOAT_EPSILON) { + if (mathZero(fill->linear.dx) && mathZero(fill->linear.dy)) { + fill->solid = true; + } + return true; + } - fill->linear.dx /= fill->linear.len; - fill->linear.dy /= fill->linear.len; + fill->linear.dx /= len; + fill->linear.dy /= len; fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; auto gradTransform = linear->transform(); bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform)); if (isTransformation) { - if (transform) gradTransform = *transform * gradTransform; - } else if (transform) { - gradTransform = *transform; + gradTransform = transform * gradTransform; + } else { + gradTransform = transform; isTransformation = true; } @@ -239,15 +246,13 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr auto dx = fill->linear.dx; fill->linear.dx = dx * invTransform.e11 + fill->linear.dy * invTransform.e21; fill->linear.dy = dx * invTransform.e12 + fill->linear.dy * invTransform.e22; - - fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; } return true; } -bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* transform) +bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix& transform) { auto cx = P(radial)->cx; auto cy = P(radial)->cy; @@ -256,7 +261,10 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr auto fy = P(radial)->fy; auto fr = P(radial)->fr; - if (r < FLOAT_EPSILON) return true; + if (mathZero(r)) { + fill->solid = true; + return true; + } fill->radial.dr = r - fr; fill->radial.dx = cx - fx; @@ -289,12 +297,10 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr auto gradTransform = radial->transform(); bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform)); - if (transform) { - if (isTransformation) gradTransform = *transform * gradTransform; - else { - gradTransform = *transform; - isTransformation = true; - } + if (isTransformation) gradTransform = transform * gradTransform; + else { + gradTransform = transform; + isTransformation = true; } if (isTransformation) { @@ -816,25 +822,32 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 } -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable) { if (!fill) return false; fill->spread = fdata->spread(); - if (ctable) { - if (!_updateColorTable(fill, fdata, surface, opacity)) return false; - } - if (fdata->identifier() == TVG_CLASS_ID_LINEAR) { - return _prepareLinear(fill, static_cast(fdata), transform); + if (!_prepareLinear(fill, static_cast(fdata), transform)) return false; } else if (fdata->identifier() == TVG_CLASS_ID_RADIAL) { - return _prepareRadial(fill, static_cast(fdata), transform); + if (!_prepareRadial(fill, static_cast(fdata), transform)) return false; } - //LOG: What type of gradient?! + if (ctable) return _updateColorTable(fill, fdata, surface, opacity); + return true; +} + + +const Fill::ColorStop* fillFetchSolid(const SwFill* fill, const Fill* fdata) +{ + if (!fill->solid) return nullptr; + + const Fill::ColorStop* colors; + auto cnt = fdata->colorStops(&colors); + if (cnt == 0 || !colors) return nullptr; - return false; + return colors + cnt - 1; } @@ -845,6 +858,7 @@ void fillReset(SwFill* fill) fill->ctable = nullptr; } fill->translucent = false; + fill->solid = false; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp index e1d41a0d5289..3fc64ce036a9 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp @@ -27,14 +27,14 @@ /* Internal Class Implementation */ /************************************************************************/ -static inline bool _onlyShifted(const Matrix* m) +static inline bool _onlyShifted(const Matrix& m) { - if (mathEqual(m->e11, 1.0f) && mathEqual(m->e22, 1.0f) && mathZero(m->e12) && mathZero(m->e21)) return true; + if (mathEqual(m.e11, 1.0f) && mathEqual(m.e22, 1.0f) && mathZero(m.e12) && mathZero(m.e21)) return true; return false; } -static bool _genOutline(SwImage* image, const RenderMesh* mesh, const Matrix* transform, SwMpool* mpool, unsigned tid) +static bool _genOutline(SwImage* image, const Matrix& transform, SwMpool* mpool, unsigned tid) { image->outline = mpoolReqOutline(mpool, tid); auto outline = image->outline; @@ -45,48 +45,12 @@ static bool _genOutline(SwImage* image, const RenderMesh* mesh, const Matrix* tr outline->closed.reserve(1); Point to[4]; - if (mesh->triangleCnt > 0) { - // TODO: Optimise me. We appear to calculate this exact min/max bounding area in multiple - // places. We should be able to re-use one we have already done? Also see: - // tvgPicture.h --> bounds - // tvgSwRasterTexmap.h --> _rasterTexmapPolygonMesh - // - // TODO: Should we calculate the exact path(s) of the triangle mesh instead? - // i.e. copy tvgSwShape.capp -> _genOutline? - // - // TODO: Cntrs? - auto triangles = mesh->triangles; - auto min = triangles[0].vertex[0].pt; - auto max = triangles[0].vertex[0].pt; - - for (uint32_t i = 0; i < mesh->triangleCnt; ++i) { - if (triangles[i].vertex[0].pt.x < min.x) min.x = triangles[i].vertex[0].pt.x; - else if (triangles[i].vertex[0].pt.x > max.x) max.x = triangles[i].vertex[0].pt.x; - if (triangles[i].vertex[0].pt.y < min.y) min.y = triangles[i].vertex[0].pt.y; - else if (triangles[i].vertex[0].pt.y > max.y) max.y = triangles[i].vertex[0].pt.y; - - if (triangles[i].vertex[1].pt.x < min.x) min.x = triangles[i].vertex[1].pt.x; - else if (triangles[i].vertex[1].pt.x > max.x) max.x = triangles[i].vertex[1].pt.x; - if (triangles[i].vertex[1].pt.y < min.y) min.y = triangles[i].vertex[1].pt.y; - else if (triangles[i].vertex[1].pt.y > max.y) max.y = triangles[i].vertex[1].pt.y; - - if (triangles[i].vertex[2].pt.x < min.x) min.x = triangles[i].vertex[2].pt.x; - else if (triangles[i].vertex[2].pt.x > max.x) max.x = triangles[i].vertex[2].pt.x; - if (triangles[i].vertex[2].pt.y < min.y) min.y = triangles[i].vertex[2].pt.y; - else if (triangles[i].vertex[2].pt.y > max.y) max.y = triangles[i].vertex[2].pt.y; - } - to[0] = {min.x, min.y}; - to[1] = {max.x, min.y}; - to[2] = {max.x, max.y}; - to[3] = {min.x, max.y}; - } else { - auto w = static_cast(image->w); - auto h = static_cast(image->h); - to[0] = {0, 0}; - to[1] = {w, 0}; - to[2] = {w, h}; - to[3] = {0, h}; - } + auto w = static_cast(image->w); + auto h = static_cast(image->h); + to[0] = {0, 0}; + to[1] = {w, 0}; + to[2] = {w, h}; + to[3] = {0, h}; for (int i = 0; i < 4; i++) { outline->pts.push(mathTransform(&to[i], transform)); @@ -108,25 +72,25 @@ static bool _genOutline(SwImage* image, const RenderMesh* mesh, const Matrix* tr /* External Class Implementation */ /************************************************************************/ -bool imagePrepare(SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid) +bool imagePrepare(SwImage* image, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid) { image->direct = _onlyShifted(transform); //Fast track: Non-transformed image but just shifted. if (image->direct) { - image->ox = -static_cast(nearbyint(transform->e13)); - image->oy = -static_cast(nearbyint(transform->e23)); + image->ox = -static_cast(nearbyint(transform.e13)); + image->oy = -static_cast(nearbyint(transform.e23)); //Figure out the scale factor by transform matrix } else { - auto scaleX = sqrtf((transform->e11 * transform->e11) + (transform->e21 * transform->e21)); - auto scaleY = sqrtf((transform->e22 * transform->e22) + (transform->e12 * transform->e12)); + auto scaleX = sqrtf((transform.e11 * transform.e11) + (transform.e21 * transform.e21)); + auto scaleY = sqrtf((transform.e22 * transform.e22) + (transform.e12 * transform.e12)); image->scale = (fabsf(scaleX - scaleY) > 0.01f) ? 1.0f : scaleX; - if (mathZero(transform->e12) && mathZero(transform->e21)) image->scaled = true; + if (mathZero(transform.e12) && mathZero(transform.e21)) image->scaled = true; else image->scaled = false; } - if (!_genOutline(image, mesh, transform, mpool, tid)) return false; + if (!_genOutline(image, transform, mpool, tid)) return false; return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion, image->direct); } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp index ae158c836af9..fb809c4f7e91 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp @@ -254,12 +254,10 @@ SwFixed mathDiff(SwFixed angle1, SwFixed angle2) } -SwPoint mathTransform(const Point* to, const Matrix* transform) +SwPoint mathTransform(const Point* to, const Matrix& transform) { - if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)}; - - auto tx = to->x * transform->e11 + to->y * transform->e12 + transform->e13; - auto ty = to->x * transform->e21 + to->y * transform->e22 + transform->e23; + auto tx = to->x * transform.e11 + to->y * transform.e12 + transform.e13; + auto ty = to->x * transform.e21 + to->y * transform.e22 + transform.e23; return {TO_SWCOORD(tx), TO_SWCOORD(ty)}; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp index 042d1e2b44de..a6f9d8745a22 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp @@ -194,10 +194,21 @@ static inline uint8_t _opMaskDifference(uint8_t s, uint8_t d, uint8_t a) } +static inline uint8_t _opMaskLighten(uint8_t s, uint8_t d, uint8_t a) +{ + return (s > d) ? s : d; +} + + +static inline uint8_t _opMaskDarken(uint8_t s, uint8_t d, uint8_t a) +{ + return (s < d) ? s : d; +} + + static inline bool _direct(CompositeMethod method) { - //subtract & Intersect allows the direct composition - if (method == CompositeMethod::SubtractMask || method == CompositeMethod::IntersectMask) return true; + if (method == CompositeMethod::SubtractMask || method == CompositeMethod::IntersectMask || method == CompositeMethod::DarkenMask) return true; return false; } @@ -209,6 +220,8 @@ static inline SwMask _getMaskOp(CompositeMethod method) case CompositeMethod::SubtractMask: return _opMaskSubtract; case CompositeMethod::DifferenceMask: return _opMaskDifference; case CompositeMethod::IntersectMask: return _opMaskIntersect; + case CompositeMethod::LightenMask: return _opMaskLighten; + case CompositeMethod::DarkenMask: return _opMaskDarken; default: return nullptr; } } @@ -832,7 +845,7 @@ static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, cons } -static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity) +static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity) { if (surface->channelSize == sizeof(uint8_t)) { TVGERR("SW_ENGINE", "Not supported scaled rle image!"); @@ -841,9 +854,7 @@ static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matr Matrix itransform; - if (transform) { - if (!mathInverse(transform, &itransform)) return false; - } else mathIdentity(&itransform); + if (!mathInverse(&transform, &itransform)) return true; if (_compositing(surface)) { if (_matting(surface)) return _rasterScaledMattedRleImage(surface, image, &itransform, region, opacity); @@ -1197,13 +1208,11 @@ static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const M } -static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity) +static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity) { Matrix itransform; - if (transform) { - if (!mathInverse(transform, &itransform)) return false; - } else mathIdentity(&itransform); + if (!mathInverse(&transform, &itransform)) return true; if (_compositing(surface)) { if (_matting(surface)) return _rasterScaledMattedImage(surface, image, &itransform, region, opacity); @@ -1389,29 +1398,45 @@ static bool _rasterDirectBlendingImage(SwSurface* surface, const SwImage* image, static bool _rasterDirectImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity) { - if (surface->channelSize == sizeof(uint8_t)) { - TVGERR("SW_ENGINE", "Not supported grayscale image!"); - return false; - } - - auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x]; auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox); - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto src = sbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) { - *dst = *src + ALPHA_BLEND(*dst, IA(*src)); + //32bits channels + if (surface->channelSize == sizeof(uint32_t)) { + auto dbuffer = &surface->buf32[region.min.y * surface->stride + region.min.x]; + + for (auto y = region.min.y; y < region.max.y; ++y) { + auto dst = dbuffer; + auto src = sbuffer; + if (opacity == 255) { + for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) { + *dst = *src + ALPHA_BLEND(*dst, IA(*src)); + } + } else { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { + auto tmp = ALPHA_BLEND(*src, opacity); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + } } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { - auto tmp = ALPHA_BLEND(*src, opacity); - *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + dbuffer += surface->stride; + sbuffer += image->stride; + } + //8bits grayscale + } else if (surface->channelSize == sizeof(uint8_t)) { + auto dbuffer = &surface->buf8[region.min.y * surface->stride + region.min.x]; + + for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride, sbuffer += image->stride) { + auto dst = dbuffer; + auto src = sbuffer; + if (opacity == 255) { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { + *dst = *src + MULTIPLY(*dst, ~*src); + } + } else { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { + *dst = INTERPOLATE8(*src, *dst, opacity); + } } } - dbuffer += surface->stride; - sbuffer += image->stride; } return true; } @@ -1433,7 +1458,7 @@ static bool _directImage(SwSurface* surface, const SwImage* image, const SwBBox& //Blenders for the following scenarios: [RLE / Whole] * [Direct / Scaled / Transformed] -static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity) +static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& region, uint8_t opacity) { //RLE Image if (image->rle) { @@ -1574,8 +1599,6 @@ static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, c static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { - if (fill->linear.len < FLOAT_EPSILON) return false; - if (_compositing(surface)) { if (_matting(surface)) return _rasterGradientMattedRect(surface, region, fill); else return _rasterGradientMaskedRect(surface, region, fill); @@ -1902,10 +1925,16 @@ void rasterPremultiply(Surface* surface) } -bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) +bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity) { if (!shape->fill) return false; + if (auto color = fillFetchSolid(shape->fill, fdata)) { + auto a = MULTIPLY(color->a, opacity); + return a > 0 ? rasterShape(surface, shape, color->r, color->g, color->b, a) : true; + } + + auto id = fdata->identifier(); if (shape->fastTrack) { if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill); else if (id == TVG_CLASS_ID_RADIAL)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill); @@ -1917,10 +1946,16 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) } -bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) +bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity) { if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false; + if (auto color = fillFetchSolid(shape->stroke->fill, fdata)) { + auto a = MULTIPLY(color->a, opacity); + return a > 0 ? rasterStroke(surface, shape, color->r, color->g, color->b, a) : true; + } + + auto id = fdata->identifier(); if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); @@ -1952,13 +1987,12 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint } -bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox& bbox, uint8_t opacity) +bool rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const SwBBox& bbox, uint8_t opacity) { //Outside of the viewport, skip the rendering if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= static_cast(surface->w) || bbox.min.y >= static_cast(surface->h)) return true; - if (mesh && mesh->triangleCnt > 0) return _rasterTexmapPolygonMesh(surface, image, mesh, transform, &bbox, opacity); - else return _rasterImage(surface, image, transform, bbox, opacity); + return _rasterImage(surface, image, transform, bbox, opacity); } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h index cfce7785c752..88ef2118f278 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h @@ -53,12 +53,10 @@ static bool _arrange(const SwImage* image, const SwBBox* region, int& yStart, in regionBottom = image->rle->spans[image->rle->size - 1].y; } - if (yStart >= regionBottom) return false; - if (yStart < regionTop) yStart = regionTop; if (yEnd > regionBottom) yEnd = regionBottom; - return true; + return yEnd > yStart; } @@ -868,10 +866,8 @@ static void _calcVertCoverage(AALine *lines, int32_t eidx, int32_t y, int32_t re static void _calcHorizCoverage(AALine *lines, int32_t eidx, int32_t y, int32_t x, int32_t x2) { - if (lines[y].length[eidx] < abs(x - x2)) { - lines[y].length[eidx] = abs(x - x2); - lines[y].coverage[eidx] = (255 / (lines[y].length[eidx] + 1)); - } + lines[y].length[eidx] = abs(x - x2); + lines[y].coverage[eidx] = (255 / (lines[y].length[eidx] + 1)); } @@ -897,9 +893,14 @@ static void _calcAAEdge(AASpans *aaSpans, int32_t eidx) ptx[1] = tx[1]; \ } while (0) + struct Point + { + int32_t x, y; + }; + int32_t y = 0; - SwPoint pEdge = {-1, -1}; //previous edge point - SwPoint edgeDiff = {0, 0}; //temporary used for point distance + Point pEdge = {-1, -1}; //previous edge point + Point edgeDiff = {0, 0}; //temporary used for point distance /* store bigger to tx[0] between prev and current edge's x positions. */ int32_t tx[2] = {0, 0}; @@ -1024,6 +1025,7 @@ static void _calcAAEdge(AASpans *aaSpans, int32_t eidx) static bool _apply(SwSurface* surface, AASpans* aaSpans) { + auto end = surface->buf32 + surface->h * surface->stride; auto y = aaSpans->yStart; uint32_t pixel; uint32_t* dst; @@ -1044,8 +1046,13 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans) dst = surface->buf32 + (offset + line->x[0]); if (line->x[0] > 1) pixel = *(dst - 1); else pixel = *dst; - pos = 1; + + //exceptional handling. out of memory bound. + if (dst + line->length[0] >= end) { + pos += (dst + line->length[0] - end); + } + while (pos <= line->length[0]) { *dst = INTERPOLATE(*dst, pixel, line->coverage[0] * pos); ++dst; @@ -1053,17 +1060,21 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans) } //Right edge - dst = surface->buf32 + (offset + line->x[1] - 1); + dst = surface->buf32 + offset + line->x[1] - 1; + if (line->x[1] < (int32_t)(surface->w - 1)) pixel = *(dst + 1); else pixel = *dst; + pos = line->length[1]; - pos = width; - while ((int32_t)(width - line->length[1]) < pos) { - *dst = INTERPOLATE(*dst, pixel, 255 - (line->coverage[1] * (line->length[1] - (width - pos)))); + //exceptional handling. out of memory bound. + if (dst - pos < surface->buf32) --pos; + + while (pos > 0) { + *dst = INTERPOLATE(*dst, pixel, 255 - (line->coverage[1] * pos)); --dst; --pos; } - } + } y++; } @@ -1084,7 +1095,7 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans) | / | 3 -- 2 */ -static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox* region, uint8_t opacity) +static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix& transform, const SwBBox* region, uint8_t opacity) { if (surface->channelSize == sizeof(uint8_t)) { TVGERR("SW_ENGINE", "Not supported grayscale Textmap polygon!"); @@ -1092,7 +1103,7 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const } //Exceptions: No dedicated drawing area? - if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false; + if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return true; /* Prepare vertices. shift XY coordinates to match the sub-pixeling technique. */ @@ -1104,7 +1115,7 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const float ys = FLT_MAX, ye = -1.0f; for (int i = 0; i < 4; i++) { - if (transform) vertices[i].pt *= *transform; + vertices[i].pt *= transform; if (vertices[i].pt.y < ys) ys = vertices[i].pt.y; if (vertices[i].pt.y > ye) ye = vertices[i].pt.y; } @@ -1135,68 +1146,3 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const #endif return _apply(surface, aaSpans); } - - -/* - Provide any number of triangles to draw a mesh using the supplied image. - Indexes are not used, so each triangle (Polygon) vertex has to be defined, even if they copy the previous one. - Example: - - 0 -- 1 0 -- 1 0 - | / | --> | / / | - | / | | / / | - 2 -- 3 2 1 -- 2 - - Should provide two Polygons, one for each triangle. - // TODO: region? -*/ -static bool _rasterTexmapPolygonMesh(SwSurface* surface, const SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox* region, uint8_t opacity) -{ - if (surface->channelSize == sizeof(uint8_t)) { - TVGERR("SW_ENGINE", "Not supported grayscale Textmap polygon mesh!"); - return false; - } - - //Exceptions: No dedicated drawing area? - if ((!image->rle && !region) || (image->rle && image->rle->size == 0)) return false; - - // Step polygons once to transform - auto transformedTris = (Polygon*)malloc(sizeof(Polygon) * mesh->triangleCnt); - float ys = FLT_MAX, ye = -1.0f; - for (uint32_t i = 0; i < mesh->triangleCnt; i++) { - transformedTris[i] = mesh->triangles[i]; - transformedTris[i].vertex[0].pt *= *transform; - transformedTris[i].vertex[1].pt *= *transform; - transformedTris[i].vertex[2].pt *= *transform; - - if (transformedTris[i].vertex[0].pt.y < ys) ys = transformedTris[i].vertex[0].pt.y; - else if (transformedTris[i].vertex[0].pt.y > ye) ye = transformedTris[i].vertex[0].pt.y; - if (transformedTris[i].vertex[1].pt.y < ys) ys = transformedTris[i].vertex[1].pt.y; - else if (transformedTris[i].vertex[1].pt.y > ye) ye = transformedTris[i].vertex[1].pt.y; - if (transformedTris[i].vertex[2].pt.y < ys) ys = transformedTris[i].vertex[2].pt.y; - else if (transformedTris[i].vertex[2].pt.y > ye) ye = transformedTris[i].vertex[2].pt.y; - - // Convert normalized UV coordinates to image coordinates - transformedTris[i].vertex[0].uv.x *= (float)image->w; - transformedTris[i].vertex[0].uv.y *= (float)image->h; - transformedTris[i].vertex[1].uv.x *= (float)image->w; - transformedTris[i].vertex[1].uv.y *= (float)image->h; - transformedTris[i].vertex[2].uv.x *= (float)image->w; - transformedTris[i].vertex[2].uv.y *= (float)image->h; - } - - // Get AA spans and step polygons again to draw - if (auto aaSpans = _AASpans(ys, ye, image, region)) { - for (uint32_t i = 0; i < mesh->triangleCnt; i++) { - _rasterPolygonImage(surface, image, region, transformedTris[i], aaSpans, opacity); - } -#if 0 - if (_compositing(surface) && _masking(surface) && !_direct(surface->compositor->method)) { - _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox); - } -#endif - _apply(surface, aaSpans); - } - free(transformedTris); - return true; -} diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 350f33340506..47a7166115bd 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -39,7 +39,7 @@ struct SwTask : Task SwSurface* surface = nullptr; SwMpool* mpool = nullptr; SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region - Matrix* transform = nullptr; + Matrix transform; Array clips; RenderUpdateFlag flags = RenderUpdateFlag::None; uint8_t opacity; @@ -68,10 +68,7 @@ struct SwTask : Task virtual bool clip(SwRleData* target) = 0; virtual SwRleData* rle() = 0; - virtual ~SwTask() - { - free(transform); - } + virtual ~SwTask() {} }; @@ -100,8 +97,7 @@ struct SwShapeTask : SwTask if (!rshape->stroke->fill && (MULTIPLY(rshape->stroke->color[3], opacity) == 0)) return 0.0f; if (mathZero(rshape->stroke->trim.begin - rshape->stroke->trim.end)) return 0.0f; - if (transform) return (width * sqrt(transform->e11 * transform->e11 + transform->e12 * transform->e12)); - else return width; + return (width * sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12)); } @@ -203,64 +199,10 @@ struct SwShapeTask : SwTask }; -struct SwSceneTask : SwTask -{ - Array scene; //list of paints render data (SwTask) - SwRleData* sceneRle = nullptr; - - bool clip(SwRleData* target) override - { - //Only one shape - if (scene.count == 1) { - return static_cast(*scene.data)->clip(target); - } - - //More than one shapes - if (sceneRle) rleClipPath(target, sceneRle); - else TVGLOG("SW_ENGINE", "No clippers in a scene?"); - - return true; - } - - SwRleData* rle() override - { - return sceneRle; - } - - void run(unsigned tid) override - { - //TODO: Skip the run if the scene hans't changed. - if (!sceneRle) sceneRle = static_cast(calloc(1, sizeof(SwRleData))); - else rleReset(sceneRle); - - //Merge shapes if it has more than one shapes - if (scene.count > 1) { - //Merge first two clippers - auto clipper1 = static_cast(*scene.data); - auto clipper2 = static_cast(*(scene.data + 1)); - - rleMerge(sceneRle, clipper1->rle(), clipper2->rle()); - - //Unify the remained clippers - for (auto rd = scene.begin() + 2; rd < scene.end(); ++rd) { - auto clipper = static_cast(*rd); - rleMerge(sceneRle, sceneRle, clipper->rle()); - } - } - } - - void dispose() override - { - rleFree(sceneRle); - } -}; - - struct SwImageTask : SwTask { SwImage image; Surface* source; //Image source - const RenderMesh* mesh = nullptr; //Should be valid ptr in action bool clip(SwRleData* target) override { @@ -293,10 +235,9 @@ struct SwImageTask : SwTask imageReset(&image); if (!image.data || image.w == 0 || image.h == 0) goto end; - if (!imagePrepare(&image, mesh, transform, clipRegion, bbox, mpool, tid)) goto end; + if (!imagePrepare(&image, transform, clipRegion, bbox, mpool, tid)) goto end; - // TODO: How do we clip the triangle mesh? Only clip non-meshed images for now - if (mesh->triangleCnt == 0 && clips.count > 0) { + if (clips.count > 0) { if (!imageGenRle(&image, bbox, false)) goto end; if (image.rle) { //Clear current task memorypool here if the clippers would use the same memory pool @@ -336,7 +277,7 @@ static void _renderFill(SwShapeTask* task, SwSurface* surface, uint8_t opacity) { uint8_t r, g, b, a; if (auto fill = task->rshape->fill) { - rasterGradientShape(surface, &task->shape, fill->identifier()); + rasterGradientShape(surface, &task->shape, fill, opacity); } else { task->rshape->fillColor(&r, &g, &b, &a); a = MULTIPLY(opacity, a); @@ -348,7 +289,7 @@ static void _renderStroke(SwShapeTask* task, SwSurface* surface, uint8_t opacity { uint8_t r, g, b, a; if (auto strokeFill = task->rshape->strokeFill()) { - rasterGradientStroke(surface, &task->shape, strokeFill->identifier()); + rasterGradientStroke(surface, &task->shape, strokeFill, opacity); } else { if (task->rshape->strokeColor(&r, &g, &b, &a)) { a = MULTIPLY(opacity, a); @@ -480,7 +421,7 @@ bool SwRenderer::renderImage(RenderData data) if (task->opacity == 0) return true; - return rasterImage(surface, &task->image, task->mesh, task->transform, task->bbox, task->opacity); + return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity); } @@ -688,7 +629,8 @@ bool SwRenderer::endComposite(Compositor* cmp) //Default is alpha blending if (p->method == CompositeMethod::None) { - return rasterImage(surface, &p->image, nullptr, nullptr, p->bbox, p->opacity); + Matrix m = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + return rasterImage(surface, &p->image, m, p->bbox, p->opacity); } return true; @@ -714,7 +656,7 @@ void SwRenderer::dispose(RenderData data) } -void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, const Array& clips, uint8_t opacity, RenderUpdateFlag flags) +void* SwRenderer::prepareCommon(SwTask* task, const Matrix& transform, const Array& clips, uint8_t opacity, RenderUpdateFlag flags) { if (!surface) return task; if (flags == RenderUpdateFlag::None) return task; @@ -727,20 +669,11 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, } task->clips = clips; - - if (transform) { - if (!task->transform) task->transform = static_cast(malloc(sizeof(Matrix))); - *task->transform = transform->m; - } else { - if (task->transform) free(task->transform); - task->transform = nullptr; - } - + task->transform = transform; + //zero size? - if (task->transform) { - if (task->transform->e11 == 0.0f && task->transform->e12 == 0.0f) return task; //zero width - if (task->transform->e21 == 0.0f && task->transform->e22 == 0.0f) return task; //zero height - } + if (task->transform.e11 == 0.0f && task->transform.e12 == 0.0f) return task; //zero width + if (task->transform.e21 == 0.0f && task->transform.e22 == 0.0f) return task; //zero height task->opacity = opacity; task->surface = surface; @@ -762,7 +695,7 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, } -RenderData SwRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) +RenderData SwRenderer::prepare(Surface* surface, RenderData data, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) { //prepare task auto task = static_cast(data); @@ -770,33 +703,12 @@ RenderData SwRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD else task->done(); task->source = surface; - task->mesh = mesh; - - return prepareCommon(task, transform, clips, opacity, flags); -} - - -RenderData SwRenderer::prepare(const Array& scene, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) -{ - //prepare task - auto task = static_cast(data); - if (!task) task = new SwSceneTask; - else task->done(); - - task->scene = scene; - - //TODO: Failed threading them. It would be better if it's possible. - //See: https://github.com/thorvg/thorvg/issues/1409 - //Guarantee composition targets get ready. - for (auto task = scene.begin(); task < scene.end(); ++task) { - static_cast(*task)->done(); - } return prepareCommon(task, transform, clips, opacity, flags); } -RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) +RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) { //prepare task auto task = static_cast(data); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h index 57be558988ce..fcd8ad46205f 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h @@ -36,9 +36,8 @@ namespace tvg class SwRenderer : public RenderMethod { public: - RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) override; - RenderData prepare(const Array& scene, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) override; - RenderData prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) override; + RenderData prepare(const RenderShape& rshape, RenderData data, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) override; + RenderData prepare(Surface* surface, RenderData data, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) override; bool preRender() override; bool renderShape(RenderData data) override; bool renderImage(RenderData data) override; @@ -77,7 +76,7 @@ class SwRenderer : public RenderMethod SwRenderer(); ~SwRenderer(); - RenderData prepareCommon(SwTask* task, const RenderTransform* transform, const Array& clips, uint8_t opacity, RenderUpdateFlag flags); + RenderData prepareCommon(SwTask* task, const Matrix& transform, const Array& clips, uint8_t opacity, RenderUpdateFlag flags); }; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp index 25c6cd90b921..42b08de6a581 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp @@ -358,7 +358,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor rle->spans = static_cast(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); @@ -822,46 +822,6 @@ static SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRl } -static SwSpan* _mergeSpansRegion(const SwRleData *clip1, const SwRleData *clip2, SwSpan *outSpans) -{ - auto out = outSpans; - auto spans1 = clip1->spans; - auto end1 = clip1->spans + clip1->size; - auto spans2 = clip2->spans; - auto end2 = clip2->spans + clip2->size; - - //list two spans up in y order - //TODO: Remove duplicated regions? - while (spans1 < end1 && spans2 < end2) { - while (spans1 < end1 && spans1->y <= spans2->y) { - *out = *spans1; - ++spans1; - ++out; - } - if (spans1 >= end1) break; - while (spans2 < end2 && spans2->y <= spans1->y) { - *out = *spans2; - ++spans2; - ++out; - } - } - - //Leftovers - while (spans1 < end1) { - *out = *spans1; - ++spans1; - ++out; - } - while (spans2 < end2) { - *out = *spans2; - ++spans2; - ++out; - } - - return out; -} - - void _replaceClipSpan(SwRleData *rle, SwSpan* clippedSpans, uint32_t size) { free(rle->spans); @@ -1030,45 +990,6 @@ void rleFree(SwRleData* rle) } -void rleMerge(SwRleData* rle, SwRleData* clip1, SwRleData* clip2) -{ - if (!rle || (!clip1 && !clip2)) return; - if (clip1 && clip1->size == 0 && clip2 && clip2->size == 0) return; - - TVGLOG("SW_ENGINE", "Unifying Rle!"); - - //clip1 is empty, just copy clip2 - if (!clip1 || clip1->size == 0) { - if (clip2) { - auto spans = static_cast(malloc(sizeof(SwSpan) * (clip2->size))); - memcpy(spans, clip2->spans, clip2->size); - _replaceClipSpan(rle, spans, clip2->size); - } else { - _replaceClipSpan(rle, nullptr, 0); - } - return; - } - - //clip2 is empty, just copy clip1 - if (!clip2 || clip2->size == 0) { - if (clip1) { - auto spans = static_cast(malloc(sizeof(SwSpan) * (clip1->size))); - memcpy(spans, clip1->spans, clip1->size); - _replaceClipSpan(rle, spans, clip1->size); - } else { - _replaceClipSpan(rle, nullptr, 0); - } - return; - } - - auto spanCnt = clip1->size + clip2->size; - auto spans = static_cast(malloc(sizeof(SwSpan) * spanCnt)); - auto spansEnd = _mergeSpansRegion(clip1, clip2, spans); - - _replaceClipSpan(rle, spans, spansEnd - spans); -} - - void rleClipPath(SwRleData *rle, const SwRleData *clip) { if (rle->size == 0 || clip->size == 0) return; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index 4f069ece975a..96c3bc28b9cb 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp @@ -49,7 +49,7 @@ static bool _outlineEnd(SwOutline& outline) } -static bool _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform, bool closed = false) +static bool _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix& transform, bool closed = false) { //make it a contour, if the last contour is not closed yet. if (!closed) _outlineEnd(outline); @@ -60,14 +60,14 @@ static bool _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* tr } -static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix* transform) +static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix& transform) { outline.pts.push(mathTransform(to, transform)); outline.types.push(SW_CURVE_TYPE_POINT); } -static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform) +static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix& transform) { outline.pts.push(mathTransform(ctrl1, transform)); outline.types.push(SW_CURVE_TYPE_CUBIC); @@ -99,7 +99,7 @@ static bool _outlineClose(SwOutline& outline) } -static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* transform) +static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix& transform) { Line cur = {dash.ptCur, *to}; auto len = lineLength(cur.pt1, cur.pt2); @@ -160,7 +160,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans } -static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform) +static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix& transform) { Bezier cur = {dash.ptCur, *ctrl1, *ctrl2, *to}; auto len = bezLength(cur); @@ -221,7 +221,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct } -static void _dashClose(SwDashStroke& dash, const Matrix* transform) +static void _dashClose(SwDashStroke& dash, const Matrix& transform) { _dashLineTo(dash, &dash.ptStart, transform); } @@ -245,10 +245,10 @@ static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const } -static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length) +static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length, float trimBegin, float trimEnd) { - auto begin = length * rshape->stroke->trim.begin; - auto end = length * rshape->stroke->trim.end; + auto begin = length * trimBegin; + auto end = length * trimEnd; //default if (end > begin) { @@ -324,7 +324,7 @@ static float _outlineLength(const RenderShape* rshape, uint32_t shiftPts, uint32 } -static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, bool trimmed, SwMpool* mpool, unsigned tid) +static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& transform, bool trimmed, SwMpool* mpool, unsigned tid) { const PathCommand* cmds = rshape->path.cmds.data; auto cmdCnt = rshape->path.cmds.count; @@ -341,6 +341,8 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans auto offset = 0.0f; dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset); auto simultaneous = rshape->stroke->trim.simultaneous; + float trimBegin = 0.0f, trimEnd = 1.0f; + if (trimmed) rshape->stroke->strokeTrim(trimBegin, trimEnd); if (dash.cnt == 0) { if (trimmed) dash.pattern = (float*)malloc(sizeof(float) * 4); @@ -372,7 +374,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans //must begin with moveTo if (cmds[0] == PathCommand::MoveTo) { - if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous)); + if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous), trimBegin, trimEnd); _dashMoveTo(dash, offIdx, offset, pts); cmds++; pts++; @@ -387,7 +389,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans case PathCommand::MoveTo: { if (trimmed) { if (simultaneous) { - _trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true)); + _trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true), trimBegin, trimEnd); _dashMoveTo(dash, offIdx, offset, pts); } else _dashMoveTo(dash, pts); } else _dashMoveTo(dash, offIdx, offset, pts); @@ -436,7 +438,7 @@ static bool _axisAlignedRect(const SwOutline* outline) } -static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix* transform, SwMpool* mpool, unsigned tid, bool hasComposite) +static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix& transform, SwMpool* mpool, unsigned tid, bool hasComposite) { const PathCommand* cmds = rshape->path.cmds.data; auto cmdCnt = rshape->path.cmds.count; @@ -492,7 +494,7 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix* /* External Class Implementation */ /************************************************************************/ -bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite) +bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite) { if (!_genOutline(shape, rshape, transform, mpool, tid, hasComposite)) return false; if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false; @@ -575,7 +577,7 @@ void shapeDelStroke(SwShape* shape) } -void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* transform) +void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix& transform) { if (!shape->stroke) shape->stroke = static_cast(calloc(1, sizeof(SwStroke))); auto stroke = shape->stroke; @@ -586,7 +588,7 @@ void shapeResetStroke(SwShape* shape, const RenderShape* rshape, const Matrix* t } -bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid) +bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid) { SwOutline* shapeOutline = nullptr; SwOutline* strokeOutline = nullptr; @@ -629,13 +631,13 @@ bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix* } -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable) +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable) { return fillGenColorTable(shape->fill, fill, transform, surface, opacity, ctable); } -bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint8_t opacity, bool ctable) +bool shapeGenStrokeFillColors(SwShape* shape, const Fill* fill, const Matrix& transform, SwSurface* surface, uint8_t opacity, bool ctable) { return fillGenColorTable(shape->stroke->fill, fill, transform, surface, opacity, ctable); } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp index 18f5f3eca825..75ac96be04d4 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp @@ -805,15 +805,10 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke* stroke, const RenderShape* rshape, const Matrix* transform) +void strokeReset(SwStroke* stroke, const RenderShape* rshape, const Matrix& transform) { - if (transform) { - stroke->sx = sqrtf(powf(transform->e11, 2.0f) + powf(transform->e21, 2.0f)); - stroke->sy = sqrtf(powf(transform->e12, 2.0f) + powf(transform->e22, 2.0f)); - } else { - stroke->sx = stroke->sy = 1.0f; - } - + stroke->sx = sqrtf(powf(transform.e11, 2.0f) + powf(transform.e21, 2.0f)); + stroke->sy = sqrtf(powf(transform.e12, 2.0f) + powf(transform.e22, 2.0f)); stroke->width = HALF_STROKE(rshape->strokeWidth()); stroke->cap = rshape->strokeCap(); stroke->miterlimit = static_cast(rshape->strokeMiterlimit() * 65536.0f); diff --git a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp index 903437f29d3a..a14472680477 100644 --- a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp @@ -21,20 +21,21 @@ */ #include "tvgIteratorAccessor.h" +#include "tvgCompressor.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -static bool accessChildren(Iterator* it, function func) +static bool accessChildren(Iterator* it, function func, void* data) { while (auto child = it->next()) { //Access the child - if (!func(child)) return false; + if (!func(child, data)) return false; //Access the children of the child if (auto it2 = IteratorAccessor::iterator(child)) { - if (!accessChildren(it2, func)) { + if (!accessChildren(it2, func, data)) { delete(it2); return false; } @@ -44,26 +45,46 @@ static bool accessChildren(Iterator* it, function func return true; } + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -unique_ptr Accessor::set(unique_ptr picture, function func) noexcept +TVG_DEPRECATED unique_ptr Accessor::set(unique_ptr picture, function func) noexcept +{ + auto backward = [](const tvg::Paint* paint, void* data) -> bool + { + auto func = reinterpret_cast*>(data); + if (!(*func)(paint)) return false; + return true; + }; + + set(picture.get(), backward, reinterpret_cast(&func)); + return picture; +} + + +Result Accessor::set(const Picture* picture, function func, void* data) noexcept { - auto p = picture.get(); - if (!p || !func) return picture; + if (!picture || !func) return Result::InvalidArguments; //Use the Preorder Tree-Search //Root - if (!func(p)) return picture; + if (!func(picture, data)) return Result::Success; //Children - if (auto it = IteratorAccessor::iterator(p)) { - accessChildren(it, func); + if (auto it = IteratorAccessor::iterator(picture)) { + accessChildren(it, func, data); delete(it); } - return picture; + return Result::Success; +} + + +uint32_t Accessor::id(const char* name) noexcept +{ + return djb2Encode(name); } diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp index be6c2dc7de98..6c4711e8c1a3 100644 --- a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp @@ -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.0 || end > 1.0 || begin > end) return Result::InvalidArguments; auto loader = pImpl->picture->pImpl->loader; if (!loader) return Result::InsufficientCondition; diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.h b/thirdparty/thorvg/src/renderer/tvgCanvas.h index 81fd1b7d6f19..199e823034f7 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.h +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.h @@ -93,11 +93,13 @@ struct Canvas::Impl auto flag = RenderUpdateFlag::None; if (status == Status::Damanged || force) flag = RenderUpdateFlag::All; + auto m = Matrix{1, 0, 0, 0, 1, 0, 0, 0, 1}; + if (paint) { - paint->pImpl->update(renderer, nullptr, clips, 255, flag); + paint->pImpl->update(renderer, m, clips, 255, flag); } else { for (auto paint : paints) { - paint->pImpl->update(renderer, nullptr, clips, 255, flag); + paint->pImpl->update(renderer, m, clips, 255, flag); } } status = Status::Updating; diff --git a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp index 76d89b40edb7..c57b20779cca 100644 --- a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp +++ b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp @@ -54,36 +54,30 @@ static constexpr bool operator &(CanvasEngine a, CanvasEngine b) return int(a) & int(b); } -static bool _buildVersionInfo() +static bool _buildVersionInfo(uint32_t* major, uint32_t* minor, uint32_t* micro) { - auto SRC = THORVG_VERSION_STRING; //ex) 0.3.99 - auto p = SRC; + auto VER = THORVG_VERSION_STRING; + auto p = VER; const char* x; - char major[3]; - x = strchr(p, '.'); - if (!x) return false; - memcpy(major, p, x - p); - major[x - p] = '\0'; + if (!(x = strchr(p, '.'))) return false; + uint32_t majorVal = atoi(p); p = x + 1; - char minor[3]; - x = strchr(p, '.'); - if (!x) return false; - memcpy(minor, p, x - p); - minor[x - p] = '\0'; + if (!(x = strchr(p, '.'))) return false; + uint32_t minorVal = atoi(p); p = x + 1; - char micro[3]; - x = SRC + strlen(THORVG_VERSION_STRING); - memcpy(micro, p, x - p); - micro[x - p] = '\0'; + uint32_t microVal = atoi(p); char sum[7]; - snprintf(sum, sizeof(sum), "%s%s%s", major, minor, micro); - + snprintf(sum, sizeof(sum), "%d%02d%02d", majorVal, minorVal, microVal); _version = atoi(sum); + if (major) *major = majorVal; + if (minor) *minor = minorVal; + if (micro) *micro = microVal; + return true; } @@ -122,7 +116,7 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept if (_initCnt++ > 0) return Result::Success; - if (!_buildVersionInfo()) return Result::Unknown; + if (!_buildVersionInfo(nullptr, nullptr, nullptr)) return Result::Unknown; if (!LoaderMgr::init()) return Result::Unknown; @@ -172,8 +166,14 @@ Result Initializer::term(CanvasEngine engine) noexcept } +const char* Initializer::version(uint32_t* major, uint32_t* minor, uint32_t* micro) noexcept +{ + if ((!major && ! minor && !micro) || _buildVersionInfo(major, minor, micro)) return THORVG_VERSION_STRING; + return nullptr; +} + + uint16_t THORVG_VERSION_NUMBER() { return _version; } - diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index 0ce6540f20a5..11cee0c54a75 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp @@ -41,7 +41,7 @@ } -static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before) +static Result _clipRect(RenderMethod* renderer, const Point* pts, const Matrix& pm, const Matrix& rm, RenderRegion& before) { //sorting Point tmp[4]; @@ -50,8 +50,8 @@ static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTr for (int i = 0; i < 4; ++i) { tmp[i] = pts[i]; - if (rTransform) tmp[i] *= rTransform->m; - if (pTransform) tmp[i] *= pTransform->m; + tmp[i] *= rm; + tmp[i] *= pm; if (tmp[i].x < min.x) min.x = tmp[i].x; if (tmp[i].x > max.x) max.x = tmp[i].x; if (tmp[i].y < min.y) min.y = tmp[i].y; @@ -73,7 +73,7 @@ static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTr } -static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before) +static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Matrix& pm, RenderRegion& before) { /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ auto shape = static_cast(cmpTarget); @@ -84,18 +84,17 @@ static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Ren //nothing to clip if (ptsCnt == 0) return Result::InvalidArguments; - if (ptsCnt != 4) return Result::InsufficientCondition; - if (rTransform && (cmpTarget->pImpl->renderFlag & RenderUpdateFlag::Transform)) rTransform->update(); + auto& rm = P(cmpTarget)->transform(); //No rotation and no skewing, still can try out clipping the rect region. auto tryClip = false; - if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) tryClip = true; - if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) tryClip = true; + if ((!mathRightAngle(pm) || mathSkewed(pm))) tryClip = true; + if ((!mathRightAngle(rm) || mathSkewed(rm))) tryClip = true; - if (tryClip) return _clipRect(renderer, pts, pTransform, rTransform, before); + if (tryClip) return _clipRect(renderer, pts, pm, rm, before); //Perpendicular Rectangle? auto pt1 = pts + 0; @@ -110,16 +109,10 @@ static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Ren auto v1 = *pt1; auto v2 = *pt3; - - if (rTransform) { - v1 *= rTransform->m; - v2 *= rTransform->m; - } - - if (pTransform) { - v1 *= pTransform->m; - v2 *= pTransform->m; - } + v1 *= rm; + v2 *= rm; + v1 *= pm; + v2 *= pm; //sorting if (v1.x > v2.x) std::swap(v1.x, v2.x); @@ -158,17 +151,15 @@ Iterator* Paint::Impl::iterator() } -Paint* Paint::Impl::duplicate() +Paint* Paint::Impl::duplicate(Paint* ret) { - Paint* ret; - PAINT_METHOD(ret, duplicate()); + if (ret) ret->composite(nullptr, CompositeMethod::None); + + PAINT_METHOD(ret, duplicate(ret)); //duplicate Transform - if (rTransform) { - ret->pImpl->rTransform = new RenderTransform(); - *ret->pImpl->rTransform = *rTransform; - ret->pImpl->renderFlag |= RenderUpdateFlag::Transform; - } + ret->pImpl->tr = tr; + ret->pImpl->renderFlag |= RenderUpdateFlag::Transform; ret->pImpl->opacity = opacity; @@ -180,14 +171,9 @@ Paint* Paint::Impl::duplicate() bool Paint::Impl::rotate(float degree) { - if (rTransform) { - if (rTransform->overriding) return false; - if (mathEqual(degree, rTransform->degree)) return true; - } else { - if (mathZero(degree)) return true; - rTransform = new RenderTransform(); - } - rTransform->degree = degree; + if (tr.overriding) return false; + if (mathEqual(degree, tr.degree)) return true; + tr.degree = degree; renderFlag |= RenderUpdateFlag::Transform; return true; @@ -196,14 +182,9 @@ bool Paint::Impl::rotate(float degree) bool Paint::Impl::scale(float factor) { - if (rTransform) { - if (rTransform->overriding) return false; - if (mathEqual(factor, rTransform->scale)) return true; - } else { - if (mathEqual(factor, 1.0f)) return true; - rTransform = new RenderTransform(); - } - rTransform->scale = factor; + if (tr.overriding) return false; + if (mathEqual(factor, tr.scale)) return true; + tr.scale = factor; renderFlag |= RenderUpdateFlag::Transform; return true; @@ -212,15 +193,10 @@ bool Paint::Impl::scale(float factor) bool Paint::Impl::translate(float x, float y) { - if (rTransform) { - if (rTransform->overriding) return false; - if (mathEqual(x, rTransform->m.e13) && mathEqual(y, rTransform->m.e23)) return true; - } else { - if (mathZero(x) && mathZero(y)) return true; - rTransform = new RenderTransform(); - } - rTransform->m.e13 = x; - rTransform->m.e23 = y; + if (tr.overriding) return false; + if (mathEqual(x, tr.m.e13) && mathEqual(y, tr.m.e23)) return true; + tr.m.e13 = x; + tr.m.e23 = y; renderFlag |= RenderUpdateFlag::Transform; return true; @@ -229,6 +205,8 @@ bool Paint::Impl::translate(float x, float y) bool Paint::Impl::render(RenderMethod* renderer) { + if (opacity == 0) return true; + Compositor* cmp = nullptr; /* Note: only ClipPath is processed in update() step. @@ -258,7 +236,7 @@ bool Paint::Impl::render(RenderMethod* renderer) } -RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pTransform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) +RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) { if (this->renderer != renderer) { if (this->renderer) TVGERR("RENDERER", "paint's renderer has been changed!"); @@ -266,7 +244,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT this->renderer = renderer; } - if (renderFlag & RenderUpdateFlag::Transform) rTransform->update(); + if (renderFlag & RenderUpdateFlag::Transform) tr.update(); /* 1. Composition Pre Processing */ RenderData trd = nullptr; //composite target render data @@ -277,7 +255,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT if (compData) { auto target = compData->target; auto method = compData->method; - target->pImpl->ctxFlag &= ~ContextFlag::FastTrack; //reset + P(target)->ctxFlag &= ~ContextFlag::FastTrack; //reset /* If the transformation has no rotational factors and the ClipPath/Alpha(InvAlpha)Masking involves a simple rectangle, we can optimize by using the viewport instead of the regular ClipPath/AlphaMasking sequence for improved performance. */ @@ -296,14 +274,14 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT } if (tryFastTrack) { viewport = renderer->viewport(); - if ((compFastTrack = _compFastTrack(renderer, target, pTransform, target->pImpl->rTransform, viewport)) == Result::Success) { - target->pImpl->ctxFlag |= ContextFlag::FastTrack; + if ((compFastTrack = _compFastTrack(renderer, target, pm, viewport)) == Result::Success) { + P(target)->ctxFlag |= ContextFlag::FastTrack; } } } if (compFastTrack == Result::InsufficientCondition) { childClipper = compData->method == CompositeMethod::ClipPath ? true : false; - trd = target->pImpl->update(renderer, pTransform, clips, 255, pFlag, childClipper); + trd = P(target)->update(renderer, pm, clips, 255, pFlag, childClipper); if (childClipper) clips.push(trd); } } @@ -314,8 +292,9 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT opacity = MULTIPLY(opacity, this->opacity); RenderData rd = nullptr; - RenderTransform outTransform(pTransform, rTransform); - PAINT_METHOD(rd, update(renderer, &outTransform, clips, opacity, newFlag, clipper)); + + tr.cm = pm * tr.m; + PAINT_METHOD(rd, update(renderer, tr.cm, clips, opacity, newFlag, clipper)); /* 3. Composition Post Processing */ if (compFastTrack == Result::Success) renderer->viewport(viewport); @@ -325,13 +304,13 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT } -bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking) +bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin) { - Matrix* m = nullptr; bool ret; + const auto& m = this->transform(origin); //Case: No transformed, quick return! - if (!transformed || !(m = this->transform())) { + if (!transformed || mathIdentity(&m)) { PAINT_METHOD(ret, bounds(x, y, w, h, stroking)); return ret; } @@ -355,7 +334,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme //Compute the AABB after transformation for (int i = 0; i < 4; i++) { - pt[i] *= *m; + pt[i] *= m; if (pt[i].x < x1) x1 = pt[i].x; if (pt[i].x > x2) x2 = pt[i].x; @@ -372,6 +351,26 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme } +void Paint::Impl::reset() +{ + if (compData) { + if (P(compData->target)->unref() == 0) delete(compData->target); + free(compData); + compData = nullptr; + } + mathIdentity(&tr.m); + tr.degree = 0.0f; + tr.scale = 1.0f; + tr.overriding = false; + + blendMethod = BlendMethod::Normal; + renderFlag = RenderUpdateFlag::None; + ctxFlag = ContextFlag::Invalid; + opacity = 255; + paint->id = 0; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -417,9 +416,7 @@ Result Paint::transform(const Matrix& m) noexcept Matrix Paint::transform() noexcept { - auto pTransform = pImpl->transform(); - if (pTransform) return *pTransform; - return {1, 0, 0, 0, 1, 0, 0, 0, 1}; + return pImpl->transform(); } @@ -429,9 +426,9 @@ TVG_DEPRECATED Result Paint::bounds(float* x, float* y, float* w, float* h) cons } -Result Paint::bounds(float* x, float* y, float* w, float* h, bool transform) const noexcept +Result Paint::bounds(float* x, float* y, float* w, float* h, bool transformed) const noexcept { - if (pImpl->bounds(x, y, w, h, transform, true)) return Result::Success; + if (pImpl->bounds(x, y, w, h, transformed, true, transformed)) return Result::Success; return Result::InsufficientCondition; } @@ -444,6 +441,11 @@ Paint* Paint::duplicate() const noexcept Result Paint::composite(std::unique_ptr target, CompositeMethod method) noexcept { + if (method == CompositeMethod::ClipPath && target && target->identifier() != TVG_CLASS_ID_SHAPE) { + TVGERR("RENDERER", "ClipPath only allows the Shape!"); + return Result::NonSupport; + } + auto p = target.release(); if (pImpl->composite(this, p, method)) return Result::Success; delete(p); @@ -486,7 +488,7 @@ uint32_t Paint::identifier() const noexcept } -Result Paint::blend(BlendMethod method) const noexcept +Result Paint::blend(BlendMethod method) noexcept { if (pImpl->blendMethod != method) { pImpl->blendMethod = method; diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h index bc07ab52abf7..e43ca239bb7a 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.h +++ b/thirdparty/thorvg/src/renderer/tvgPaint.h @@ -48,17 +48,40 @@ namespace tvg struct Paint::Impl { Paint* paint = nullptr; - RenderTransform* rTransform = nullptr; Composite* compData = nullptr; RenderMethod* renderer = nullptr; - BlendMethod blendMethod = BlendMethod::Normal; //uint8_t - uint8_t renderFlag = RenderUpdateFlag::None; - uint8_t ctxFlag = ContextFlag::Invalid; - uint8_t id; - uint8_t opacity = 255; + struct { + Matrix m; //input matrix + Matrix cm; //multipled parents matrix + float degree; //rotation degree + float scale; //scale factor + bool overriding; //user transform? + + void update() + { + if (overriding) return; + m.e11 = 1.0f; + m.e12 = 0.0f; + m.e21 = 0.0f; + m.e22 = 1.0f; + m.e31 = 0.0f; + m.e32 = 0.0f; + m.e33 = 1.0f; + mathScale(&m, scale, scale); + mathRotate(&m, degree); + } + } tr; + BlendMethod blendMethod; + uint8_t renderFlag; + uint8_t ctxFlag; + uint8_t opacity; uint8_t refCnt = 0; //reference count + uint8_t id; //TODO: deprecated, remove it - Impl(Paint* pnt) : paint(pnt) {} + Impl(Paint* pnt) : paint(pnt) + { + reset(); + } ~Impl() { @@ -66,7 +89,6 @@ namespace tvg if (P(compData->target)->unref() == 0) delete(compData->target); free(compData); } - delete(rTransform); if (renderer && (renderer->unref() == 0)) delete(renderer); } @@ -84,23 +106,19 @@ namespace tvg bool transform(const Matrix& m) { - if (!rTransform) { - if (mathIdentity(&m)) return true; - rTransform = new RenderTransform(); - } - rTransform->override(m); + tr.m = m; + tr.overriding = true; renderFlag |= RenderUpdateFlag::Transform; return true; } - Matrix* transform() + Matrix& transform(bool origin = false) { - if (rTransform) { - if (renderFlag & RenderUpdateFlag::Transform) rTransform->update(); - return &rTransform->m; - } - return nullptr; + //update transform + if (renderFlag & RenderUpdateFlag::Transform) tr.update(); + if (origin) return tr.cm; + return tr.m; } bool composite(Paint* source, Paint* target, CompositeMethod method) @@ -135,10 +153,11 @@ namespace tvg bool rotate(float degree); bool scale(float factor); bool translate(float x, float y); - bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking); - RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false); + bool bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking, bool origin = false); + RenderData update(RenderMethod* renderer, const Matrix& pm, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper = false); bool render(RenderMethod* renderer); - Paint* duplicate(); + Paint* duplicate(Paint* ret = nullptr); + void reset(); }; } diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.cpp b/thirdparty/thorvg/src/renderer/tvgPicture.cpp index 5bd55a3f7b49..68c7a41032fd 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPicture.cpp @@ -104,21 +104,6 @@ RenderRegion Picture::Impl::bounds(RenderMethod* renderer) } -RenderTransform Picture::Impl::resizeTransform(const RenderTransform* pTransform) -{ - //Overriding Transformation by the desired image size - auto sx = w / loader->w; - auto sy = h / loader->h; - auto scale = sx < sy ? sx : sy; - - RenderTransform tmp; - tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1}; - - if (!pTransform) return tmp; - else return RenderTransform(pTransform, &tmp); -} - - Result Picture::Impl::load(ImageLoader* loader) { //Same resource has been loaded. @@ -215,18 +200,24 @@ Result Picture::size(float* w, float* h) const noexcept } -Result Picture::mesh(const Polygon* triangles, uint32_t triangleCnt) noexcept +const Paint* Picture::paint(uint32_t id) noexcept { - if (!triangles && triangleCnt > 0) return Result::InvalidArguments; - if (triangles && triangleCnt == 0) return Result::InvalidArguments; - - pImpl->mesh(triangles, triangleCnt); - return Result::Success; -} + struct Value + { + uint32_t id; + const Paint* ret; + } value = {id, nullptr}; + auto cb = [](const tvg::Paint* paint, void* data) -> bool + { + auto p = static_cast(data); + if (p->id == paint->id) { + p->ret = paint; + return false; + } + return true; + }; -uint32_t Picture::mesh(const Polygon** triangles) const noexcept -{ - if (triangles) *triangles = pImpl->rm.triangles; - return pImpl->rm.triangleCnt; + tvg::Accessor::gen()->set(this, cb, &value); + return value.ret; } diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.h b/thirdparty/thorvg/src/renderer/tvgPicture.h index bd7021218a25..3a4880cabaa3 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.h +++ b/thirdparty/thorvg/src/renderer/tvgPicture.h @@ -63,12 +63,10 @@ struct Picture::Impl Surface* surface = nullptr; //bitmap picture uses RenderData rd = nullptr; //engine data float w = 0, h = 0; - RenderMesh rm; //mesh data Picture* picture = nullptr; bool resizing = false; bool needComp = false; //need composition - RenderTransform resizeTransform(const RenderTransform* pTransform); bool needComposition(uint8_t opacity); bool render(RenderMethod* renderer); bool size(float w, float h); @@ -90,58 +88,37 @@ struct Picture::Impl delete(paint); } - RenderData update(RenderMethod* renderer, const RenderTransform* pTransform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) + RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper) { auto flag = static_cast(pFlag | load()); if (surface) { if (flag == RenderUpdateFlag::None) return rd; - auto transform = resizeTransform(pTransform); - rd = renderer->prepare(surface, &rm, rd, &transform, clips, opacity, flag); + + //Overriding Transformation by the desired image size + auto sx = w / loader->w; + auto sy = h / loader->h; + auto scale = sx < sy ? sx : sy; + auto m = transform * Matrix{scale, 0, 0, 0, scale, 0, 0, 0, 1}; + + rd = renderer->prepare(surface, rd, m, clips, opacity, flag); } else if (paint) { if (resizing) { loader->resize(paint, w, h); resizing = false; } needComp = needComposition(opacity) ? true : false; - rd = paint->pImpl->update(renderer, pTransform, clips, opacity, flag, clipper); + rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false); } return rd; } bool bounds(float* x, float* y, float* w, float* h, bool stroking) { - if (rm.triangleCnt > 0) { - auto triangles = rm.triangles; - auto min = triangles[0].vertex[0].pt; - auto max = triangles[0].vertex[0].pt; - - for (uint32_t i = 0; i < rm.triangleCnt; ++i) { - if (triangles[i].vertex[0].pt.x < min.x) min.x = triangles[i].vertex[0].pt.x; - else if (triangles[i].vertex[0].pt.x > max.x) max.x = triangles[i].vertex[0].pt.x; - if (triangles[i].vertex[0].pt.y < min.y) min.y = triangles[i].vertex[0].pt.y; - else if (triangles[i].vertex[0].pt.y > max.y) max.y = triangles[i].vertex[0].pt.y; - - if (triangles[i].vertex[1].pt.x < min.x) min.x = triangles[i].vertex[1].pt.x; - else if (triangles[i].vertex[1].pt.x > max.x) max.x = triangles[i].vertex[1].pt.x; - if (triangles[i].vertex[1].pt.y < min.y) min.y = triangles[i].vertex[1].pt.y; - else if (triangles[i].vertex[1].pt.y > max.y) max.y = triangles[i].vertex[1].pt.y; - - if (triangles[i].vertex[2].pt.x < min.x) min.x = triangles[i].vertex[2].pt.x; - else if (triangles[i].vertex[2].pt.x > max.x) max.x = triangles[i].vertex[2].pt.x; - if (triangles[i].vertex[2].pt.y < min.y) min.y = triangles[i].vertex[2].pt.y; - else if (triangles[i].vertex[2].pt.y > max.y) max.y = triangles[i].vertex[2].pt.y; - } - if (x) *x = min.x; - if (y) *y = min.y; - if (w) *w = max.x - min.x; - if (h) *h = max.y - min.y; - } else { - if (x) *x = 0; - if (y) *y = 0; - if (w) *w = this->w; - if (h) *h = this->h; - } + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = this->w; + if (h) *h = this->h; return true; } @@ -176,32 +153,21 @@ struct Picture::Impl return load(loader); } - void mesh(const Polygon* triangles, const uint32_t triangleCnt) + Paint* duplicate(Paint* ret) { - if (triangles && triangleCnt > 0) { - this->rm.triangleCnt = triangleCnt; - this->rm.triangles = (Polygon*)malloc(sizeof(Polygon) * triangleCnt); - memcpy(this->rm.triangles, triangles, sizeof(Polygon) * triangleCnt); - } else { - free(this->rm.triangles); - this->rm.triangles = nullptr; - this->rm.triangleCnt = 0; - } - } + if (ret) TVGERR("RENDERER", "TODO: duplicate()"); - Paint* duplicate() - { load(); - auto ret = Picture::gen().release(); - auto dup = ret->pImpl; + auto picture = Picture::gen().release(); + auto dup = picture->pImpl; if (paint) dup->paint = paint->duplicate(); if (loader) { dup->loader = loader; ++dup->loader->sharing; - PP(ret)->renderFlag |= RenderUpdateFlag::Image; + PP(picture)->renderFlag |= RenderUpdateFlag::Image; } dup->surface = surface; @@ -209,13 +175,7 @@ struct Picture::Impl dup->h = h; dup->resizing = resizing; - if (rm.triangleCnt > 0) { - dup->rm.triangleCnt = rm.triangleCnt; - dup->rm.triangles = (Polygon*)malloc(sizeof(Polygon) * rm.triangleCnt); - memcpy(dup->rm.triangles, rm.triangles, sizeof(Polygon) * rm.triangleCnt); - } - - return ret; + return picture; } Iterator* iterator() diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp index 82145b9aa4c6..8ee76493c265 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.cpp +++ b/thirdparty/thorvg/src/renderer/tvgRender.cpp @@ -46,41 +46,6 @@ uint32_t RenderMethod::unref() } -void RenderTransform::override(const Matrix& m) -{ - this->m = m; - overriding = true; -} - - -void RenderTransform::update() -{ - if (overriding) return; - - m.e11 = 1.0f; - m.e12 = 0.0f; - - m.e21 = 0.0f; - m.e22 = 1.0f; - - m.e31 = 0.0f; - m.e32 = 0.0f; - m.e33 = 1.0f; - - mathScale(&m, scale, scale); - mathRotate(&m, degree); -} - - -RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) -{ - if (lhs && rhs) m = lhs->m * rhs->m; - else if (lhs) m = lhs->m; - else if (rhs) m = rhs->m; - else mathIdentity(&m); -} - - void RenderRegion::intersect(const RenderRegion& rhs) { auto x1 = x + w; diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index ff5574803391..b0ee42db8d0d 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -23,6 +23,7 @@ #ifndef _TVG_RENDER_H_ #define _TVG_RENDER_H_ +#include #include "tvgCommon.h" #include "tvgArray.h" #include "tvgLock.h" @@ -85,15 +86,15 @@ struct Compositor uint8_t opacity; }; -struct RenderMesh +struct Vertex { - Polygon* triangles = nullptr; - uint32_t triangleCnt = 0; + Point pt; + Point uv; +}; - ~RenderMesh() - { - free(triangles); - } +struct Polygon +{ + Vertex vertex[3]; }; struct RenderRegion @@ -110,24 +111,6 @@ struct RenderRegion } }; -struct RenderTransform -{ - Matrix m; - float degree = 0.0f; //rotation degree - float scale = 1.0f; //scale factor - bool overriding = false; //user transform? - - void update(); - void override(const Matrix& m); - - RenderTransform() - { - m.e13 = m.e23 = 0.0f; - } - - RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); -}; - struct RenderStroke { float width = 0.0f; @@ -147,6 +130,57 @@ struct RenderStroke bool simultaneous = true; } trim; + void operator=(const RenderStroke& rhs) + { + width = rhs.width; + + memcpy(color, rhs.color, sizeof(color)); + + delete(fill); + if (rhs.fill) fill = rhs.fill->duplicate(); + else fill = nullptr; + + free(dashPattern); + if (rhs.dashCnt > 0) { + dashPattern = static_cast(malloc(sizeof(float) * rhs.dashCnt)); + memcpy(dashPattern, rhs.dashPattern, sizeof(float) * rhs.dashCnt); + } else { + dashPattern = nullptr; + } + dashCnt = rhs.dashCnt; + miterlimit = rhs.miterlimit; + cap = rhs.cap; + join = rhs.join; + strokeFirst = rhs.strokeFirst; + trim = rhs.trim; + } + + bool strokeTrim(float& begin, float& end) const + { + begin = trim.begin; + end = trim.end; + + if (fabsf(end - begin) >= 1.0f) { + begin = 0.0f; + end = 1.0f; + return false; + } + + auto loop = true; + + if (begin > 1.0f && end > 1.0f) loop = false; + if (begin < 0.0f && end < 0.0f) loop = false; + if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f && end <= 1.0f) loop = false; + + if (begin > 1.0f) begin -= 1.0f; + if (begin < 0.0f) begin += 1.0f; + if (end > 1.0f) end -= 1.0f; + if (end < 0.0f) end += 1.0f; + + if ((loop && begin < end) || (!loop && begin > end)) std::swap(begin, end); + return true; + } + ~RenderStroke() { free(dashPattern); @@ -191,7 +225,7 @@ struct RenderShape { if (!stroke) return false; if (stroke->trim.begin == 0.0f && stroke->trim.end == 1.0f) return false; - if (stroke->trim.begin == 1.0f && stroke->trim.end == 0.0f) return false; + if (fabsf(stroke->trim.end - stroke->trim.begin) >= 1.0f) return false; return true; } @@ -252,9 +286,8 @@ class RenderMethod uint32_t unref(); virtual ~RenderMethod() {} - virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) = 0; - virtual RenderData prepare(const Array& scene, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) = 0; - virtual RenderData prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) = 0; + virtual RenderData prepare(const RenderShape& rshape, RenderData data, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags, bool clipper) = 0; + virtual RenderData prepare(Surface* surface, RenderData data, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) = 0; virtual bool preRender() = 0; virtual bool renderShape(RenderData data) = 0; virtual bool renderImage(RenderData data) = 0; @@ -288,6 +321,8 @@ static inline bool MASK_REGION_MERGING(CompositeMethod method) //these might expand the rendering region case CompositeMethod::AddMask: case CompositeMethod::DifferenceMask: + case CompositeMethod::LightenMask: + case CompositeMethod::DarkenMask: return true; default: TVGERR("RENDERER", "Unsupported Composite Method! = %d", (int)method); @@ -321,6 +356,8 @@ static inline ColorSpace COMPOSITE_TO_COLORSPACE(RenderMethod* renderer, Composi case CompositeMethod::DifferenceMask: case CompositeMethod::SubtractMask: case CompositeMethod::IntersectMask: + case CompositeMethod::LightenMask: + case CompositeMethod::DarkenMask: return ColorSpace::Grayscale8; //TODO: Optimize Luma/InvLuma colorspace to Grayscale8 case CompositeMethod::LumaMask: diff --git a/thirdparty/thorvg/src/renderer/tvgScene.h b/thirdparty/thorvg/src/renderer/tvgScene.h index 8b1981edfab1..cb6d179326f7 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.h +++ b/thirdparty/thorvg/src/renderer/tvgScene.h @@ -101,7 +101,7 @@ struct Scene::Impl return true; } - RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flag, bool clipper) + RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag flag, TVG_UNUSED bool clipper) { if ((needComp = needComposition(opacity))) { /* Overriding opacity value. If this scene is half-translucent, @@ -109,20 +109,10 @@ struct Scene::Impl this->opacity = opacity; opacity = 255; } - - if (clipper) { - Array rds(paints.size()); - for (auto paint : paints) { - rds.push(paint->pImpl->update(renderer, transform, clips, opacity, flag, true)); - } - rd = renderer->prepare(rds, rd, transform, clips, opacity, flag); - return rd; - } else { - for (auto paint : paints) { - paint->pImpl->update(renderer, transform, clips, opacity, flag, false); - } - return nullptr; + for (auto paint : paints) { + paint->pImpl->update(renderer, transform, clips, opacity, flag, false); } + return nullptr; } bool render(RenderMethod* renderer) @@ -198,10 +188,12 @@ struct Scene::Impl return true; } - Paint* duplicate() + Paint* duplicate(Paint* ret) { - auto ret = Scene::gen().release(); - auto dup = ret->pImpl; + if (ret) TVGERR("RENDERER", "TODO: duplicate()"); + + auto scene = Scene::gen().release(); + auto dup = scene->pImpl; for (auto paint : paints) { auto cdup = paint->duplicate(); @@ -209,7 +201,7 @@ struct Scene::Impl dup->paints.push_back(cdup); } - return ret; + return scene; } void clear(bool free) diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index ebc0b304abf5..b76fde7ced24 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -34,6 +34,7 @@ struct Shape::Impl RenderData rd = nullptr; //engine data Shape* shape; uint8_t flag = RenderUpdateFlag::None; + uint8_t opacity; //for composition bool needComp = false; //composite or not @@ -95,7 +96,7 @@ struct Shape::Impl return true; } - RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) + RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) { if (static_cast(pFlag | flag) == RenderUpdateFlag::None) return rd; @@ -216,23 +217,6 @@ struct Shape::Impl if (mathEqual(rs.stroke->trim.begin, begin) && mathEqual(rs.stroke->trim.end, end) && rs.stroke->trim.simultaneous == simultaneous) return; - auto loop = true; - - if (begin > 1.0f && end > 1.0f) loop = false; - if (begin < 0.0f && end < 0.0f) loop = false; - if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f && end <= 1.0f) loop = false; - - if (begin > 1.0f) begin -= 1.0f; - if (begin < 0.0f) begin += 1.0f; - if (end > 1.0f) end -= 1.0f; - if (end < 0.0f) end += 1.0f; - - if ((loop && begin < end) || (!loop && begin > end)) { - auto tmp = begin; - begin = end; - end = tmp; - } - rs.stroke->trim.begin = begin; rs.stroke->trim.end = end; rs.stroke->trim.simultaneous = simultaneous; @@ -359,47 +343,56 @@ struct Shape::Impl this->flag |= flag; } - Paint* duplicate() + Paint* duplicate(Paint* ret) { - auto ret = Shape::gen().release(); - auto dup = ret->pImpl; + auto shape = static_cast(ret); + if (shape) shape->reset(); + else shape = Shape::gen().release(); + + auto dup = shape->pImpl; + delete(dup->rs.fill); + //Default Properties + dup->flag = RenderUpdateFlag::All; dup->rs.rule = rs.rule; //Color memcpy(dup->rs.color, rs.color, sizeof(rs.color)); - dup->flag = RenderUpdateFlag::Color; //Path - if (rs.path.cmds.count > 0 && rs.path.pts.count > 0) { - dup->rs.path.cmds = rs.path.cmds; - dup->rs.path.pts = rs.path.pts; - dup->flag |= RenderUpdateFlag::Path; - } + dup->rs.path.cmds.push(rs.path.cmds); + dup->rs.path.pts.push(rs.path.pts); //Stroke if (rs.stroke) { - dup->rs.stroke = new RenderStroke(); + if (!dup->rs.stroke) dup->rs.stroke = new RenderStroke; *dup->rs.stroke = *rs.stroke; - memcpy(dup->rs.stroke->color, rs.stroke->color, sizeof(rs.stroke->color)); - if (rs.stroke->dashCnt > 0) { - dup->rs.stroke->dashPattern = static_cast(malloc(sizeof(float) * rs.stroke->dashCnt)); - memcpy(dup->rs.stroke->dashPattern, rs.stroke->dashPattern, sizeof(float) * rs.stroke->dashCnt); - } - if (rs.stroke->fill) { - dup->rs.stroke->fill = rs.stroke->fill->duplicate(); - dup->flag |= RenderUpdateFlag::GradientStroke; - } - dup->flag |= RenderUpdateFlag::Stroke; + } else { + delete(dup->rs.stroke); + dup->rs.stroke = nullptr; } //Fill - if (rs.fill) { - dup->rs.fill = rs.fill->duplicate(); - dup->flag |= RenderUpdateFlag::Gradient; - } + if (rs.fill) dup->rs.fill = rs.fill->duplicate(); + else dup->rs.fill = nullptr; - return ret; + return shape; + } + + void reset() + { + PP(shape)->reset(); + rs.path.cmds.clear(); + rs.path.pts.clear(); + + rs.color[3] = 0; + rs.rule = FillRule::Winding; + + delete(rs.stroke); + rs.stroke = nullptr; + + delete(rs.fill); + rs.fill = nullptr; } Iterator* iterator() diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h index 93f8481707c2..58918e88f0ef 100644 --- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h +++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h @@ -23,8 +23,6 @@ #ifndef _TVG_TASK_SCHEDULER_H_ #define _TVG_TASK_SCHEDULER_H_ -#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR - #include #include diff --git a/thirdparty/thorvg/src/renderer/tvgText.cpp b/thirdparty/thorvg/src/renderer/tvgText.cpp index 4b5eb35ce528..d54c78783c5d 100644 --- a/thirdparty/thorvg/src/renderer/tvgText.cpp +++ b/thirdparty/thorvg/src/renderer/tvgText.cpp @@ -35,7 +35,7 @@ /************************************************************************/ -Text::Text() : pImpl(new Impl) +Text::Text() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_TEXT; } @@ -95,20 +95,13 @@ Result Text::unload(const std::string& path) noexcept Result Text::fill(uint8_t r, uint8_t g, uint8_t b) noexcept { - if (!pImpl->paint) return Result::InsufficientCondition; - - return pImpl->fill(r, g, b); + return pImpl->shape->fill(r, g, b); } Result Text::fill(unique_ptr f) noexcept { - if (!pImpl->paint) return Result::InsufficientCondition; - - auto p = f.release(); - if (!p) return Result::MemoryCorruption; - - return pImpl->fill(p); + return pImpl->shape->fill(std::move(f)); } diff --git a/thirdparty/thorvg/src/renderer/tvgText.h b/thirdparty/thorvg/src/renderer/tvgText.h index c56ce8b87864..f6faec2d53b0 100644 --- a/thirdparty/thorvg/src/renderer/tvgText.h +++ b/thirdparty/thorvg/src/renderer/tvgText.h @@ -36,27 +36,22 @@ struct Text::Impl { FontLoader* loader = nullptr; - Shape* paint = nullptr; + Text* paint; + Shape* shape; char* utf8 = nullptr; float fontSize; bool italic = false; bool changed = false; - ~Impl() + Impl(Text* p) : paint(p), shape(Shape::gen().release()) { - free(utf8); - LoaderMgr::retrieve(loader); - delete(paint); } - Result fill(uint8_t r, uint8_t g, uint8_t b) - { - return paint->fill(r, g, b); - } - - Result fill(Fill* f) + ~Impl() { - return paint->fill(cast(f)); + free(utf8); + LoaderMgr::retrieve(loader); + delete(shape); } Result text(const char* utf8) @@ -83,8 +78,6 @@ struct Text::Impl } this->loader = static_cast(loader); - if (!paint) paint = Shape::gen().release(); - fontSize = size; if (style && strstr(style, "italic")) italic = true; changed = true; @@ -93,14 +86,12 @@ struct Text::Impl RenderRegion bounds(RenderMethod* renderer) { - if (paint) return P(paint)->bounds(renderer); - else return {0, 0, 0, 0}; + return P(shape)->bounds(renderer); } bool render(RenderMethod* renderer) { - if (paint) return PP(paint)->render(renderer); - return true; + return PP(shape)->render(renderer); } bool load() @@ -109,24 +100,20 @@ struct Text::Impl //reload if (changed) { - loader->request(paint, utf8, italic); + loader->request(shape, utf8, italic); loader->read(); changed = false; } - if (paint) { - loader->resize(paint, fontSize, fontSize); - return true; - } - return false; + return loader->resize(shape, fontSize, fontSize); } - RenderData update(RenderMethod* renderer, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) + RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper) { if (!load()) return nullptr; //transform the gradient coordinates based on the final scaled font. - if (P(paint)->flag & RenderUpdateFlag::Gradient) { - auto fill = P(paint)->rs.fill; + auto fill = P(shape)->rs.fill; + if (fill && P(shape)->flag & RenderUpdateFlag::Gradient) { auto scale = 1.0f / loader->scale; if (fill->identifier() == TVG_CLASS_ID_LINEAR) { P(static_cast(fill))->x1 *= scale; @@ -142,23 +129,25 @@ struct Text::Impl P(static_cast(fill))->fr *= scale; } } - return PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper); + return PP(shape)->update(renderer, transform, clips, opacity, pFlag, false); } bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking) { - if (!load() || !paint) return false; - paint->bounds(x, y, w, h, true); + if (!load()) return false; + PP(shape)->bounds(x, y, w, h, true, true, false); return true; } - Paint* duplicate() + Paint* duplicate(Paint* ret) { + if (ret) TVGERR("RENDERER", "TODO: duplicate()"); + load(); - auto ret = Text::gen().release(); - auto dup = ret->pImpl; - if (paint) dup->paint = static_cast(paint->duplicate()); + auto text = Text::gen().release(); + auto dup = text->pImpl; + P(shape)->duplicate(dup->shape); if (loader) { dup->loader = loader; @@ -169,7 +158,7 @@ struct Text::Impl dup->italic = italic; dup->fontSize = fontSize; - return ret; + return text; } Iterator* iterator() diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 1a68daf3c545..7ff07fe4c2ae 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.14.2 +VERSION=0.14.7 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/