From 5eb9b5207205d6a53dd087eb65340661b13d1ac0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 22 Jan 2023 10:15:03 +0900 Subject: [PATCH 01/16] doc: updated the header description. Change-Id: Ib5fc0343dce8adef2ffdeefca583219aeafe1d90 --- inc/thorvg.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 45eeb5b..c5a140f 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -2,11 +2,12 @@ * @file thorvg.h * * The main APIs enabling the TVG initialization, preparation of the canvas and provisioning of its content: - * - drawing shapes such as line, curve, arc, rectangle, circle or user-defined - * - drawing pictures - SVG, PNG, JPG, RAW - * - solid or gradient filling - * - continuous and dashed stroking - * - clipping and masking + * - drawing shapes: line, arc, curve, path, polygon... + * - drawing pictures: tvg, svg, png, jpg, bitmap... + * - drawing fillings: solid, linear and radial gradient... + * - drawing stroking: continuous stroking with arbitrary width, join, cap, dash styles. + * - drawing composition: blending, masking, path clipping... + * - drawing scene graph & affine transformation (translation, rotation, scale, ...) * and finally drawing the canvas and TVG termination. */ @@ -291,6 +292,7 @@ public: * @return Result::Success when succeed. * * @note Setting the opacity with this API may require multiple render pass for composition. It is recommended to avoid changing the opacity if possible. + * @note ClipPath won't use the opacity value. (see: enum class CompositeMethod::ClipPath) */ Result opacity(uint8_t o) noexcept; @@ -963,6 +965,7 @@ public: * @return Result::Success when succeed. * * @note Either a solid color or a gradient fill is applied, depending on what was set as last. + * @note ClipPath won't use the fill values. (see: enum class CompositeMethod::ClipPath) */ Result fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; -- 2.7.4 From c3f1a937d7126450c15c895823404256c44bac13 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 28 Jan 2023 11:36:54 +0900 Subject: [PATCH 02/16] updated copyright. Change-Id: I6b3ff60849bdb849ce09555624593145e07af7d3 --- src/lib/gl_engine/tvgGlRenderer.cpp | 2 +- src/lib/gl_engine/tvgGlRenderer.h | 4 ++-- src/lib/sw_engine/tvgSwRenderer.cpp | 14 +++++++------- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/tvgPaint.cpp | 9 +++++---- src/lib/tvgPaint.h | 8 ++++---- src/lib/tvgPictureImpl.h | 4 ++-- src/lib/tvgRender.h | 2 +- src/lib/tvgSceneImpl.h | 4 ++-- src/lib/tvgShapeImpl.h | 4 ++-- 10 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index ce82368..95582fb 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -197,7 +197,7 @@ RenderData GlRenderer::prepare(TVG_UNUSED Surface* image, TVG_UNUSED RenderData } -RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array& clips, RenderUpdateFlag flags) +RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array& clips, RenderUpdateFlag flags, TVG_UNUSED bool clipper) { //prepare shape data GlShape* sdata = static_cast(data); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 790ea31..2688566 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -30,8 +30,8 @@ class GlRenderer : public RenderMethod public: Surface surface = {nullptr, 0, 0, 0}; - RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; - RenderData prepare(Surface* image, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; + RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) override; + RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; bool preRender() override; bool renderShape(RenderData data) override; bool renderImage(RenderData data) override; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index a303d2d..93d0d5d 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -74,12 +74,11 @@ struct SwShapeTask : SwTask SwShape shape; const Shape* sdata = nullptr; bool cmpStroking = false; + bool clipper = false; void run(unsigned tid) override - { - auto compMethod = CompositeMethod::None; - auto usedAsClip = (sdata->composite(nullptr, &compMethod) == Result::Success) && (compMethod == CompositeMethod::ClipPath); - if (opacity == 0 && !usedAsClip) return; //Invisible + { + if (opacity == 0 && !clipper) return; //Invisible uint8_t strokeAlpha = 0; auto visibleStroke = false; @@ -101,7 +100,7 @@ struct SwShapeTask : SwTask sdata->fillColor(nullptr, nullptr, nullptr, &alpha); alpha = static_cast(static_cast(alpha) * opacity / 255); visibleFill = (alpha > 0 || sdata->fill()); - if (visibleFill || visibleStroke || usedAsClip) { + if (visibleFill || visibleStroke || clipper) { shapeReset(&shape); if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; } @@ -113,7 +112,7 @@ struct SwShapeTask : SwTask //Fill if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { - if (visibleFill || usedAsClip) { + if (visibleFill || clipper) { /* We assume that if stroke width is bigger than 2, shape outline below stroke could be full covered by stroke drawing. Thus it turns off antialising in that condition. @@ -644,13 +643,14 @@ RenderData SwRenderer::prepare(Surface* image, Polygon* triangles, uint32_t tria } -RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) +RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) { //prepare task auto task = static_cast(data); if (!task) { task = new SwShapeTask; task->sdata = &sdata; + task->clipper = clipper; } return prepareCommon(task, transform, opacity, clips, flags); } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 460659c..819141f 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -36,7 +36,7 @@ namespace tvg class SwRenderer : public RenderMethod { public: - RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; + RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) override; RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; bool preRender() override; bool renderShape(RenderData data) override; diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index ba5b050..0b49122 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -184,7 +184,7 @@ bool Paint::Impl::render(RenderMethod& renderer) } -void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag) +void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag, bool clipper) { if (renderFlag & RenderUpdateFlag::Transform) { if (!rTransform) return nullptr; @@ -224,7 +224,8 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf } } if (!compFastTrack) { - tdata = target->pImpl->update(renderer, pTransform, 255, clips, pFlag); + auto clipper = compData->method == CompositeMethod::ClipPath ? true : false; + tdata = target->pImpl->update(renderer, pTransform, 255, clips, pFlag, clipper); if (method == CompositeMethod::ClipPath) clips.push(tdata); } } @@ -237,10 +238,10 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf if (rTransform && pTransform) { RenderTransform outTransform(pTransform, rTransform); - edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag); + edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag, clipper); } else { auto outTransform = pTransform ? pTransform : rTransform; - edata = smethod->update(renderer, outTransform, opacity, clips, newFlag); + edata = smethod->update(renderer, outTransform, opacity, clips, newFlag, clipper); } /* 3. Composition Post Processing */ diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index a0bd3c9..45c679d 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -43,7 +43,7 @@ namespace tvg virtual ~StrategyMethod() {} virtual bool dispose(RenderMethod& renderer) = 0; - virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) = 0; //Return engine data if it has. + virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) = 0; //Return engine data if it has. virtual bool render(RenderMethod& renderer) = 0; virtual bool bounds(float* x, float* y, float* w, float* h) = 0; virtual RenderRegion bounds(RenderMethod& renderer) const = 0; @@ -149,7 +149,7 @@ namespace tvg bool scale(float factor); bool translate(float x, float y); bool bounds(float* x, float* y, float* w, float* h, bool transformed); - void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag); + void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag, bool clipper = false); bool render(RenderMethod& renderer); Paint* duplicate(); }; @@ -178,9 +178,9 @@ namespace tvg return inst->dispose(renderer); } - void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag renderFlag) override + void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag renderFlag, bool clipper) override { - return inst->update(renderer, transform, opacity, clips, renderFlag); + return inst->update(renderer, transform, opacity, clips, renderFlag, clipper); } bool render(RenderMethod& renderer) override diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index e039532..b7e2ba0 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -126,7 +126,7 @@ struct Picture::Impl else return RenderTransform(pTransform, &tmp); } - void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) + void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) { auto flag = reload(); @@ -138,7 +138,7 @@ struct Picture::Impl loader->resize(paint, w, h); resizing = false; } - rdata = paint->pImpl->update(renderer, pTransform, opacity, clips, static_cast(pFlag | flag)); + rdata = paint->pImpl->update(renderer, pTransform, opacity, clips, static_cast(pFlag | flag), clipper); } return rdata; } diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 34e3101..88fe502 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -90,7 +90,7 @@ class RenderMethod { public: virtual ~RenderMethod() {} - virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) = 0; + virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) = 0; virtual RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) = 0; virtual bool preRender() = 0; virtual bool renderShape(RenderData data) = 0; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 2338b60..5c07cb5 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -91,7 +91,7 @@ struct Scene::Impl return false; } - void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flag) + void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flag, bool clipper) { /* Overriding opacity value. If this scene is half-translucent, It must do intermeidate composition with that opacity value. */ @@ -99,7 +99,7 @@ struct Scene::Impl if (needComposition(opacity)) opacity = 255; for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { - (*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast(flag)); + (*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast(flag), clipper); } /* FXIME: it requires to return list of children engine data diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 8e1fe08..fa2786f 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -235,9 +235,9 @@ struct Shape::Impl return renderer.renderShape(rdata); } - void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) + void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) { - this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast(pFlag | flag)); + this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast(pFlag | flag), clipper); flag = RenderUpdateFlag::None; return this->rdata; } -- 2.7.4 From f84959c2a420462fe621a6650c0baca3150131a9 Mon Sep 17 00:00:00 2001 From: jykeon Date: Wed, 15 Mar 2023 12:35:26 +0900 Subject: [PATCH 03/16] Bump up 0.8.8 Change-Id: Ia2288194406d03caa4149af22e5d1ce495a41f64 Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index aecaafa..f39d1fd 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.8.7 +Version: 0.8.8 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 11b14411c5336432f65b1cbbc97bf3e8e64099fc Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 17 Jan 2023 13:11:43 +0100 Subject: [PATCH 04/16] svg_loader: overwrite the clip's opacity/alpha According to the svg standard the clips opacity doesn't affect the final rendering. In order to avoid any confusion the opacity values are overwritten by the max possible value. Change-Id: I96699a2f74e97fae0a940e18d834f258a8c4cd86 --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 5e97b74..f60c0f6 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -264,8 +264,11 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox if (_appendChildShape(*child, comp.get(), vBox, svgPath)) valid = true; } - if (valid) paint->composite(move(comp), CompositeMethod::ClipPath); - + if (valid) { + comp->fill(255, 255, 255, 255); + comp->opacity(255); + paint->composite(move(comp), CompositeMethod::ClipPath); + } node->style->clipPath.applying = false; } } -- 2.7.4 From fc64dddb8a786a90eff11d71c7f3ec0d1f0ec869 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 27 Dec 2022 16:21:42 +0100 Subject: [PATCH 05/16] common: ignoring color/alpha/opacity of a clip object According to the svg specs clip's fill and opacity should be ignored. Till now setting the alpha/opacity value to zero resulted in the shape's rendering abort. @Issue: https://github.com/Samsung/thorvg/issues/1192 Change-Id: I76c10068d6d35dc171be3c936c5429ea1a3becf1 --- src/lib/sw_engine/tvgSwRenderer.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 93d0d5d..48787a3 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -77,8 +77,10 @@ struct SwShapeTask : SwTask bool clipper = false; void run(unsigned tid) override - { - if (opacity == 0 && !clipper) return; //Invisible + { + auto compMethod = CompositeMethod::None; + auto usedAsClip = (sdata->composite(nullptr, &compMethod) == Result::Success) && (compMethod == CompositeMethod::ClipPath); + if (opacity == 0 && !usedAsClip) return; //Invisible uint8_t strokeAlpha = 0; auto visibleStroke = false; @@ -100,7 +102,7 @@ struct SwShapeTask : SwTask sdata->fillColor(nullptr, nullptr, nullptr, &alpha); alpha = static_cast(static_cast(alpha) * opacity / 255); visibleFill = (alpha > 0 || sdata->fill()); - if (visibleFill || visibleStroke || clipper) { + if (visibleFill || visibleStroke || usedAsClip) { shapeReset(&shape); if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; } @@ -112,7 +114,7 @@ struct SwShapeTask : SwTask //Fill if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { - if (visibleFill || clipper) { + if (visibleFill || usedAsClip) { /* We assume that if stroke width is bigger than 2, shape outline below stroke could be full covered by stroke drawing. Thus it turns off antialising in that condition. -- 2.7.4 From a335a9458c61e4165ac5d3cdadf04a6a504b2512 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 22 Jan 2023 09:53:27 +0900 Subject: [PATCH 06/16] svg loader: correct clipper usage. that has been changed by 0de3872be33793d2c8db03d5b85da38670410626 Change-Id: If0b014910235253416ca8585b6fd5fe336538f4c --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index f60c0f6..5e97b74 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -264,11 +264,8 @@ static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox if (_appendChildShape(*child, comp.get(), vBox, svgPath)) valid = true; } - if (valid) { - comp->fill(255, 255, 255, 255); - comp->opacity(255); - paint->composite(move(comp), CompositeMethod::ClipPath); - } + if (valid) paint->composite(move(comp), CompositeMethod::ClipPath); + node->style->clipPath.applying = false; } } -- 2.7.4 From 31f70fb7a1dd1e34d45a7877a1ffb5bca1e012a0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 28 Jan 2023 11:36:54 +0900 Subject: [PATCH 07/16] common: enhance clipping behavior. If a paint is used as a clipper, it must be determined in the paint behavior. Propagate its decision to the immediate derived classes so that not only shapes but also scenes must be dealt as a clipper properly. This revised this change 0de3872be33793d2c8db03d5b85da38670410626 for better a solution. Change-Id: I5525cc3ce952b74eec2a52f3bdc769f5ed600f58 --- src/lib/sw_engine/tvgSwRenderer.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 48787a3..93d0d5d 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -77,10 +77,8 @@ struct SwShapeTask : SwTask bool clipper = false; void run(unsigned tid) override - { - auto compMethod = CompositeMethod::None; - auto usedAsClip = (sdata->composite(nullptr, &compMethod) == Result::Success) && (compMethod == CompositeMethod::ClipPath); - if (opacity == 0 && !usedAsClip) return; //Invisible + { + if (opacity == 0 && !clipper) return; //Invisible uint8_t strokeAlpha = 0; auto visibleStroke = false; @@ -102,7 +100,7 @@ struct SwShapeTask : SwTask sdata->fillColor(nullptr, nullptr, nullptr, &alpha); alpha = static_cast(static_cast(alpha) * opacity / 255); visibleFill = (alpha > 0 || sdata->fill()); - if (visibleFill || visibleStroke || usedAsClip) { + if (visibleFill || visibleStroke || clipper) { shapeReset(&shape); if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; } @@ -114,7 +112,7 @@ struct SwShapeTask : SwTask //Fill if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { - if (visibleFill || usedAsClip) { + if (visibleFill || clipper) { /* We assume that if stroke width is bigger than 2, shape outline below stroke could be full covered by stroke drawing. Thus it turns off antialising in that condition. -- 2.7.4 From f26e2ee6c0b6864f10fcd714d29a974f3b454bfa Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 28 Jan 2023 11:44:40 +0900 Subject: [PATCH 08/16] common paint: keep clean apis and small size. these are no more necessary. Change-Id: I315b39c77c413da1bc6102cabd5d797a1931eb9b --- inc/thorvg.h | 14 -------------- src/lib/tvgPaint.cpp | 13 ------------- src/lib/tvgPaint.h | 2 -- 3 files changed, 29 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index c5a140f..1fd0f90 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -366,20 +366,6 @@ public: CompositeMethod composite(const Paint** target) const noexcept; /** - * @brief Gets the composition source object and the composition method. - * - * @param[out] source The paint of the composition source object. - * @param[out] method The method used to composite the source object with the target. - * - * @return Result::Success when the paint object used as a composition target, Result::InsufficientCondition otherwise. - * - * @warning Please do not use it, this API is not official one. It could be modified in the next version. - * - * @BETA_API - */ - Result composite(const Paint** source, CompositeMethod* method) const noexcept; - - /** * @brief Return the unique id value of the paint instance. * * This method can be called for checking the current concrete instance type. diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index 0b49122..506fc55 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -386,19 +386,6 @@ CompositeMethod Paint::composite(const Paint** target) const noexcept } -Result Paint::composite(const Paint** source, CompositeMethod* method) const noexcept -{ - if (source) *source = pImpl->compSource; - auto met = (pImpl->compSource && pImpl->compSource->pImpl->compData ? - pImpl->compSource->pImpl->compData->method : CompositeMethod::None); - if (method) *method = met; - - if (pImpl->compSource != nullptr && met != CompositeMethod::None) - return Result::Success; - return Result::InsufficientCondition; -} - - Result Paint::opacity(uint8_t o) noexcept { if (pImpl->opacity == o) return Result::Success; diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 45c679d..9ec0232 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -63,7 +63,6 @@ namespace tvg StrategyMethod* smethod = nullptr; RenderTransform* rTransform = nullptr; Composite* compData = nullptr; - Paint* compSource = nullptr; uint32_t renderFlag = RenderUpdateFlag::None; uint32_t ctxFlag = ContextFlag::Invalid; uint32_t id; @@ -138,7 +137,6 @@ namespace tvg if (!target && method == CompositeMethod::None) return true; compData = static_cast(calloc(1, sizeof(Composite))); } - target->pImpl->compSource = source; compData->target = target; compData->source = source; compData->method = method; -- 2.7.4 From efe38299e4829cf6f202b417196f6d2dd1245ec1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 15 Jan 2023 20:20:43 +0900 Subject: [PATCH 09/16] common shape: code refactoring & data optimization. re-design the shape data structure so that render backends are able to access them directly. This also let us remove tvgShape member data from the Shape::Impl. To achieve this, migrate shape/stroke/path from the canvas interface to the render interface. Change-Id: Iac398dedec39c6bc88fa4c1c3cfdb3f5db4c25e2 --- src/lib/gl_engine/tvgGlCommon.h | 2 +- src/lib/gl_engine/tvgGlGeometry.cpp | 15 +- src/lib/gl_engine/tvgGlGeometry.h | 6 +- src/lib/gl_engine/tvgGlRenderer.cpp | 27 ++- src/lib/gl_engine/tvgGlRenderer.h | 2 +- src/lib/sw_engine/tvgSwCommon.h | 10 +- src/lib/sw_engine/tvgSwRenderer.cpp | 38 ++-- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 42 ++--- src/lib/sw_engine/tvgSwStroke.cpp | 8 +- src/lib/tvgRender.h | 97 +++++++++- src/lib/tvgShape.cpp | 157 +++++++--------- src/lib/tvgShapeImpl.h | 351 +++++++++++++++--------------------- 13 files changed, 374 insertions(+), 383 deletions(-) diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h index 90d6b14..0121900 100644 --- a/src/lib/gl_engine/tvgGlCommon.h +++ b/src/lib/gl_engine/tvgGlCommon.h @@ -54,7 +54,7 @@ class GlGeometry; struct GlShape { - const Shape* shape = nullptr; + const RenderShape* rshape = nullptr; float viewWd; float viewHt; RenderUpdateFlag updateFlag = None; diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp index c3d3297..b8273e2 100644 --- a/src/lib/gl_engine/tvgGlGeometry.cpp +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -43,13 +43,12 @@ const GlSize GlGeometry::getPrimitiveSize(const uint32_t primitiveIndex) const } -bool GlGeometry::decomposeOutline(const Shape& shape) +bool GlGeometry::decomposeOutline(const RenderShape& rshape) { - const PathCommand* cmds = nullptr; - auto cmdCnt = shape.pathCommands(&cmds); - - Point* pts = nullptr; - auto ptsCnt = shape.pathCoords(const_cast(&pts)); + auto cmds = rshape.path.cmds; + auto cmdCnt = rshape.path.cmdCnt; + auto pts = rshape.path.pts; + auto ptsCnt = rshape.path.ptsCnt; //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return false; @@ -101,7 +100,7 @@ bool GlGeometry::decomposeOutline(const Shape& shape) return true; } -bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, RenderUpdateFlag flag) +bool GlGeometry::generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag) { for (auto& shapeGeometry : mPrimitives) { vector normalInfo; @@ -158,7 +157,7 @@ bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, return true; } -bool GlGeometry::tesselate(TVG_UNUSED const Shape& shape, float viewWd, float viewHt, RenderUpdateFlag flag) +bool GlGeometry::tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag) { for (auto& shapeGeometry : mPrimitives) { constexpr float opaque = 1.0f; diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h index ec1b7e8..c5e5b29 100644 --- a/src/lib/gl_engine/tvgGlGeometry.h +++ b/src/lib/gl_engine/tvgGlGeometry.h @@ -237,9 +237,9 @@ public: uint32_t getPrimitiveCount(); const GlSize getPrimitiveSize(const uint32_t primitiveIndex) const; - bool decomposeOutline(const Shape& shape); - bool generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, RenderUpdateFlag flag); - bool tesselate(TVG_UNUSED const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag); + bool decomposeOutline(const RenderShape& rshape); + bool generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag); + bool tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag); void disableVertex(uint32_t location); void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag); void updateTransform(const RenderTransform* transform, float w, float h); diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 95582fb..3031f46 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -150,16 +150,13 @@ bool GlRenderer::renderShape(RenderData data) { if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { - const Fill* gradient = sdata->shape->fill(); - if (gradient != nullptr) - { - drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient); - } + auto gradient = sdata->rshape->fill; + if (gradient) drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient); } if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform)) { - sdata->shape->fillColor(&r, &g, &b, &a); + sdata->rshape->fillColor(&r, &g, &b, &a); if (a > 0) { drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color); @@ -168,7 +165,7 @@ bool GlRenderer::renderShape(RenderData data) if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - sdata->shape->strokeColor(&r, &g, &b, &a); + sdata->rshape->strokeColor(&r, &g, &b, &a); if (a > 0) { drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke); @@ -197,13 +194,13 @@ RenderData GlRenderer::prepare(TVG_UNUSED Surface* image, TVG_UNUSED RenderData } -RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array& clips, RenderUpdateFlag flags, TVG_UNUSED bool clipper) +RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array& clips, RenderUpdateFlag flags, TVG_UNUSED bool clipper) { //prepare shape data GlShape* sdata = static_cast(data); if (!sdata) { sdata = new GlShape; - sdata->shape = &shape; + sdata->rshape = &rshape; } sdata->viewWd = static_cast(surface.w); @@ -216,9 +213,9 @@ RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const Render //invisible? uint8_t alphaF, alphaS; - shape.fillColor(nullptr, nullptr, nullptr, &alphaF); - shape.strokeColor(nullptr, nullptr, nullptr, &alphaS); - auto strokeWd = shape.strokeWidth(); + rshape.fillColor(nullptr, nullptr, nullptr, &alphaF); + rshape.strokeColor(nullptr, nullptr, nullptr, &alphaS); + auto strokeWd = rshape.strokeWidth(); if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) && ((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) && @@ -231,9 +228,9 @@ RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const Render if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) ) { - if (!sdata->geometry->decomposeOutline(shape)) return sdata; - if (!sdata->geometry->generateAAPoints(shape, static_cast(strokeWd), sdata->updateFlag)) return sdata; - if (!sdata->geometry->tesselate(shape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata; + if (!sdata->geometry->decomposeOutline(rshape)) return sdata; + if (!sdata->geometry->generateAAPoints(rshape, static_cast(strokeWd), sdata->updateFlag)) return sdata; + if (!sdata->geometry->tesselate(rshape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata; } return sdata; } diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 2688566..4d1bb87 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -30,7 +30,7 @@ class GlRenderer : public RenderMethod public: Surface surface = {nullptr, 0, 0, 0}; - RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) override; + RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) override; RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; bool preRender() override; bool renderShape(RenderData data) override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 1f920eb..e177f61 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -302,12 +302,12 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S bool mathClipBBox(const SwBBox& clipper, SwBBox& clipee); void shapeReset(SwShape* shape); -bool shapePrepare(SwShape* shape, const Shape* sdata, 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 Shape* sdata, bool antiAlias); +bool shapeGenRle(SwShape* shape, const RenderShape* rshape, bool antiAlias); void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid); -void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform); -bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, 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, uint32_t opacity, bool ctable); @@ -317,7 +317,7 @@ void shapeResetStrokeFill(SwShape* shape); void shapeDelFill(SwShape* shape); void shapeDelStrokeFill(SwShape* shape); -void strokeReset(SwStroke* stroke, const Shape* 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); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 93d0d5d..17dff57 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -72,7 +72,7 @@ struct SwTask : Task struct SwShapeTask : SwTask { SwShape shape; - const Shape* sdata = nullptr; + const RenderShape* rshape = nullptr; bool cmpStroking = false; bool clipper = false; @@ -85,9 +85,9 @@ struct SwShapeTask : SwTask bool visibleFill = false; auto clipRegion = bbox; - if (HALF_STROKE(sdata->strokeWidth()) > 0) { - sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); - visibleStroke = sdata->strokeFill() || (static_cast(strokeAlpha * opacity / 255) > 0); + if (HALF_STROKE(rshape->strokeWidth()) > 0) { + rshape->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); + visibleStroke = rshape->strokeFill() || (static_cast(strokeAlpha * opacity / 255) > 0); } //This checks also for the case, if the invisible shape turned to visible by alpha. @@ -97,12 +97,12 @@ struct SwShapeTask : SwTask //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform) || prepareShape) { uint8_t alpha = 0; - sdata->fillColor(nullptr, nullptr, nullptr, &alpha); + rshape->fillColor(nullptr, nullptr, nullptr, &alpha); alpha = static_cast(static_cast(alpha) * opacity / 255); - visibleFill = (alpha > 0 || sdata->fill()); + visibleFill = (alpha > 0 || rshape->fill); if (visibleFill || visibleStroke || clipper) { shapeReset(&shape); - if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; + if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; } } @@ -117,11 +117,11 @@ struct SwShapeTask : SwTask shape outline below stroke could be full covered by stroke drawing. Thus it turns off antialising in that condition. Also, it shouldn't be dash style. */ - auto antiAlias = (strokeAlpha == 255 && sdata->strokeWidth() > 2 && sdata->strokeDash(nullptr) == 0) ? false : true; + auto antiAlias = (strokeAlpha == 255 && rshape->strokeWidth() > 2 && rshape->strokeDash(nullptr) == 0) ? false : true; - if (!shapeGenRle(&shape, sdata, antiAlias)) goto err; + if (!shapeGenRle(&shape, rshape, antiAlias)) goto err; } - if (auto fill = sdata->fill()) { + if (auto fill = rshape->fill) { auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; if (ctable) shapeResetFill(&shape); if (!shapeGenFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err; @@ -133,10 +133,10 @@ struct SwShapeTask : SwTask //Stroke if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (visibleStroke) { - shapeResetStroke(&shape, sdata, transform); - if (!shapeGenStrokeRle(&shape, sdata, transform, clipRegion, bbox, mpool, tid)) goto err; + shapeResetStroke(&shape, rshape, transform); + if (!shapeGenStrokeRle(&shape, rshape, transform, clipRegion, bbox, mpool, tid)) goto err; - if (auto fill = sdata->strokeFill()) { + if (auto fill = rshape->strokeFill()) { auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false; if (ctable) shapeResetStrokeFill(&shape); if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err; @@ -397,18 +397,18 @@ bool SwRenderer::renderShape(RenderData data) //Main raster stage uint8_t r, g, b, a; - if (auto fill = task->sdata->fill()) { + if (auto fill = task->rshape->fill) { rasterGradientShape(surface, &task->shape, fill->identifier()); } else { - task->sdata->fillColor(&r, &g, &b, &a); + task->rshape->fillColor(&r, &g, &b, &a); a = static_cast((opacity * (uint32_t) a) / 255); if (a > 0) rasterShape(surface, &task->shape, r, g, b, a); } - if (auto strokeFill = task->sdata->strokeFill()) { + if (auto strokeFill = task->rshape->strokeFill()) { rasterGradientStroke(surface, &task->shape, strokeFill->identifier()); } else { - if (task->sdata->strokeColor(&r, &g, &b, &a) == Result::Success) { + if (task->rshape->strokeColor(&r, &g, &b, &a)) { a = static_cast((opacity * (uint32_t) a) / 255); if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a); } @@ -643,13 +643,13 @@ RenderData SwRenderer::prepare(Surface* image, Polygon* triangles, uint32_t tria } -RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) +RenderData SwRenderer::prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) { //prepare task auto task = static_cast(data); if (!task) { task = new SwShapeTask; - task->sdata = &sdata; + task->rshape = &rshape; task->clipper = clipper; } return prepareCommon(task, transform, opacity, clips, flags); diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 819141f..c3eadbd 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -36,7 +36,7 @@ namespace tvg class SwRenderer : public RenderMethod { public: - RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) override; + RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) override; RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; bool preRender() override; bool renderShape(RenderData data) override; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 82d812e..7462a7b 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -267,13 +267,13 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct } -static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) +static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform) { - const PathCommand* cmds = nullptr; - auto cmdCnt = sdata->pathCommands(&cmds); + const PathCommand* cmds = rshape->path.cmds; + auto cmdCnt = rshape->path.cmdCnt; - const Point* pts = nullptr; - auto ptsCnt = sdata->pathCoords(&pts); + const Point* pts = rshape->path.pts; + auto ptsCnt = rshape->path.ptsCnt; //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return nullptr; @@ -286,7 +286,7 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) dash.curOpGap = false; const float* pattern; - dash.cnt = sdata->strokeDash(&pattern); + dash.cnt = rshape->strokeDash(&pattern); if (dash.cnt == 0) return nullptr; //OPTMIZE ME: Use mempool??? @@ -381,13 +381,13 @@ static bool _axisAlignedRect(const SwOutline* outline) -static bool _genOutline(SwShape* shape, const Shape* sdata, 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 = nullptr; - auto cmdCnt = sdata->pathCommands(&cmds); + const PathCommand* cmds = rshape->path.cmds; + auto cmdCnt = rshape->path.cmdCnt; - const Point* pts = nullptr; - auto ptsCnt = sdata->pathCoords(&pts); + const Point* pts = rshape->path.pts; + auto ptsCnt = rshape->path.ptsCnt; //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return false; @@ -467,7 +467,7 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf _outlineEnd(*outline); - outline->fillRule = sdata->fillRule(); + outline->fillRule = rshape->rule; shape->outline = outline; shape->fastTrack = (!hasComposite && _axisAlignedRect(shape->outline)); @@ -479,9 +479,9 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf /* External Class Implementation */ /************************************************************************/ -bool shapePrepare(SwShape* shape, const Shape* sdata, 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, sdata, transform, mpool, tid, hasComposite)) return false; + if (!_genOutline(shape, rshape, transform, mpool, tid, hasComposite)) return false; if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false; //Keep it for Rasterization Region @@ -504,7 +504,7 @@ bool shapePrepared(const SwShape* shape) } -bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias) +bool shapeGenRle(SwShape* shape, TVG_UNUSED const RenderShape* rshape, bool antiAlias) { //FIXME: Should we draw it? //Case: Stroke Line @@ -558,18 +558,18 @@ void shapeDelStroke(SwShape* shape) } -void shapeResetStroke(SwShape* shape, const Shape* sdata, 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; if (!stroke) return; - strokeReset(stroke, sdata, transform); + strokeReset(stroke, rshape, transform); rleReset(shape->strokeRle); } -bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, 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; @@ -577,14 +577,14 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo bool ret = true; //Dash Style Stroke - if (sdata->strokeDash(nullptr) > 0) { - shapeOutline = _genDashOutline(sdata, transform); + if (rshape->strokeDash(nullptr) > 0) { + shapeOutline = _genDashOutline(rshape, transform); if (!shapeOutline) return false; freeOutline = true; //Normal Style stroke } else { if (!shape->outline) { - if (!_genOutline(shape, sdata, transform, mpool, tid, false)) return false; + if (!_genOutline(shape, rshape, transform, mpool, tid, false)) return false; } shapeOutline = shape->outline; } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index d1803bd..c404bf9 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -826,7 +826,7 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke* stroke, const Shape* sdata, 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)); @@ -835,11 +835,11 @@ void strokeReset(SwStroke* stroke, const Shape* sdata, const Matrix* transform) stroke->sx = stroke->sy = 1.0f; } - stroke->width = HALF_STROKE(sdata->strokeWidth()); - stroke->cap = sdata->strokeCap(); + stroke->width = HALF_STROKE(rshape->strokeWidth()); + stroke->cap = rshape->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... - stroke->joinSaved = stroke->join = sdata->strokeJoin(); + stroke->joinSaved = stroke->join = rshape->strokeJoin(); stroke->borders[0].ptsCnt = 0; stroke->borders[0].start = -1; diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 88fe502..e9ad821 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -85,12 +85,107 @@ struct RenderTransform RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); }; +struct RenderStroke +{ + float width = 0.0f; + uint8_t color[4] = {0, 0, 0, 0}; + Fill *fill = nullptr; + float* dashPattern = nullptr; + uint32_t dashCnt = 0; + StrokeCap cap = StrokeCap::Square; + StrokeJoin join = StrokeJoin::Bevel; + + ~RenderStroke() + { + free(dashPattern); + if (fill) delete(fill); + } +}; + +struct RenderShape +{ + struct + { + PathCommand* cmds = nullptr; + uint32_t cmdCnt = 0; + uint32_t reservedCmdCnt = 0; + + Point *pts = nullptr; + uint32_t ptsCnt = 0; + uint32_t reservedPtsCnt = 0; + } path; + + Fill *fill = nullptr; + RenderStroke *stroke = nullptr; + uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a + FillRule rule = FillRule::Winding; + + ~RenderShape() + { + free(path.cmds); + free(path.pts); + + if (fill) delete(fill); + if (stroke) delete(stroke); + } + + void fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const + { + if (r) *r = color[0]; + if (g) *g = color[1]; + if (b) *b = color[2]; + if (a) *a = color[3]; + } + + float strokeWidth() const + { + if (!stroke) return 0; + return stroke->width; + } + + bool strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const + { + if (!stroke) return false; + + if (r) *r = stroke->color[0]; + if (g) *g = stroke->color[1]; + if (b) *b = stroke->color[2]; + if (a) *a = stroke->color[3]; + + return true; + } + + const Fill* strokeFill() const + { + if (!stroke) return nullptr; + return stroke->fill; + } + + uint32_t strokeDash(const float** dashPattern) const + { + if (!stroke) return 0; + if (dashPattern) *dashPattern = stroke->dashPattern; + return stroke->dashCnt; + } + + StrokeCap strokeCap() const + { + if (!stroke) return StrokeCap::Square; + return stroke->cap; + } + + StrokeJoin strokeJoin() const + { + if (!stroke) return StrokeJoin::Bevel; + return stroke->join; + } +}; class RenderMethod { public: virtual ~RenderMethod() {} - virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) = 0; + virtual RenderData prepare(const RenderShape& rshape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags, bool clipper) = 0; virtual RenderData prepare(Surface* image, Polygon* triangles, uint32_t triangleCnt, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) = 0; virtual bool preRender() = 0; virtual bool renderShape(RenderData data) = 0; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 23291eb..3d12698 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -32,7 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f; /* External Class Implementation */ /************************************************************************/ -Shape :: Shape() : pImpl(new Impl(this)) +Shape :: Shape() : pImpl(new Impl()) { Paint::pImpl->id = TVG_CLASS_ID_SHAPE; Paint::pImpl->method(new PaintMethod(pImpl)); @@ -59,8 +59,7 @@ uint32_t Shape::identifier() noexcept Result Shape::reset() noexcept { - pImpl->path.reset(); - pImpl->flag = RenderUpdateFlag::Path; + pImpl->reset(); return Result::Success; } @@ -70,9 +69,9 @@ uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept { if (!cmds) return 0; - *cmds = pImpl->path.cmds; + *cmds = pImpl->rs.path.cmds; - return pImpl->path.cmdCnt; + return pImpl->rs.path.cmdCnt; } @@ -80,9 +79,9 @@ uint32_t Shape::pathCoords(const Point** pts) const noexcept { if (!pts) return 0; - *pts = pImpl->path.pts; + *pts = pImpl->rs.path.pts; - return pImpl->path.ptsCnt; + return pImpl->rs.path.ptsCnt; } @@ -90,10 +89,8 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* { if (cmdCnt == 0 || ptsCnt == 0 || !cmds || !pts) return Result::InvalidArguments; - pImpl->path.grow(cmdCnt, ptsCnt); - pImpl->path.append(cmds, cmdCnt, pts, ptsCnt); - - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->grow(cmdCnt, ptsCnt); + pImpl->append(cmds, cmdCnt, pts, ptsCnt); return Result::Success; } @@ -101,9 +98,7 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* Result Shape::moveTo(float x, float y) noexcept { - pImpl->path.moveTo(x, y); - - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->moveTo(x, y); return Result::Success; } @@ -111,9 +106,7 @@ Result Shape::moveTo(float x, float y) noexcept Result Shape::lineTo(float x, float y) noexcept { - pImpl->path.lineTo(x, y); - - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->lineTo(x, y); return Result::Success; } @@ -121,9 +114,7 @@ Result Shape::lineTo(float x, float y) noexcept Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { - pImpl->path.cubicTo(cx1, cy1, cx2, cy2, x, y); - - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y); return Result::Success; } @@ -131,9 +122,7 @@ Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float Result Shape::close() noexcept { - pImpl->path.close(); - - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->close(); return Result::Success; } @@ -144,15 +133,13 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept auto rxKappa = rx * PATH_KAPPA; auto ryKappa = ry * PATH_KAPPA; - pImpl->path.grow(6, 13); - pImpl->path.moveTo(cx, cy - ry); - pImpl->path.cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); - pImpl->path.cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry); - pImpl->path.cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy); - pImpl->path.cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry); - pImpl->path.close(); - - pImpl->flag |= RenderUpdateFlag::Path; + pImpl->grow(6, 13); + pImpl->moveTo(cx, cy - ry); + pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); + pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry); + pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy); + pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry); + pImpl->close(); return Result::Success; } @@ -174,10 +161,10 @@ Result Shape::appendArc(float cx, float cy, float radius, float startAngle, floa Point start = {radius * cosf(startAngle), radius * sinf(startAngle)}; if (pie) { - pImpl->path.moveTo(cx, cy); - pImpl->path.lineTo(start.x + cx, start.y + cy); + pImpl->moveTo(cx, cy); + pImpl->lineTo(start.x + cx, start.y + cy); } else { - pImpl->path.moveTo(start.x + cx, start.y + cy); + pImpl->moveTo(start.x + cx, start.y + cy); } for (int i = 0; i < nCurves; ++i) { @@ -204,14 +191,12 @@ Result Shape::appendArc(float cx, float cy, float radius, float startAngle, floa Point ctrl1 = {ax - k2 * ay + cx, ay + k2 * ax + cy}; Point ctrl2 = {bx + k2 * by + cx, by - k2 * bx + cy}; - pImpl->path.cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y); + pImpl->cubicTo(ctrl1.x, ctrl1.y, ctrl2.x, ctrl2.y, end.x, end.y); startAngle = endAngle; } - if (pie) pImpl->path.close(); - - pImpl->flag |= RenderUpdateFlag::Path; + if (pie) pImpl->close(); return Result::Success; } @@ -228,48 +213,46 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) //rectangle if (rx == 0 && ry == 0) { - pImpl->path.grow(5, 4); - pImpl->path.moveTo(x, y); - pImpl->path.lineTo(x + w, y); - pImpl->path.lineTo(x + w, y + h); - pImpl->path.lineTo(x, y + h); - pImpl->path.close(); + pImpl->grow(5, 4); + pImpl->moveTo(x, y); + pImpl->lineTo(x + w, y); + pImpl->lineTo(x + w, y + h); + pImpl->lineTo(x, y + h); + pImpl->close(); //circle } else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) { return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry); } else { auto hrx = rx * 0.5f; auto hry = ry * 0.5f; - pImpl->path.grow(10, 17); - pImpl->path.moveTo(x + rx, y); - pImpl->path.lineTo(x + w - rx, y); - pImpl->path.cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); - pImpl->path.lineTo(x + w, y + h - ry); - pImpl->path.cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h); - pImpl->path.lineTo(x + rx, y + h); - pImpl->path.cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry); - pImpl->path.lineTo(x, y + ry); - pImpl->path.cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y); - pImpl->path.close(); + pImpl->grow(10, 17); + pImpl->moveTo(x + rx, y); + pImpl->lineTo(x + w - rx, y); + pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); + pImpl->lineTo(x + w, y + h - ry); + pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h); + pImpl->lineTo(x + rx, y + h); + pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry); + pImpl->lineTo(x, y + ry); + pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y); + pImpl->close(); } - pImpl->flag |= RenderUpdateFlag::Path; - return Result::Success; } Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { - pImpl->color[0] = r; - pImpl->color[1] = g; - pImpl->color[2] = b; - pImpl->color[3] = a; + pImpl->rs.color[0] = r; + pImpl->rs.color[1] = g; + pImpl->rs.color[2] = b; + pImpl->rs.color[3] = a; pImpl->flag |= RenderUpdateFlag::Color; - if (pImpl->fill) { - delete(pImpl->fill); - pImpl->fill = nullptr; + if (pImpl->rs.fill) { + delete(pImpl->rs.fill); + pImpl->rs.fill = nullptr; pImpl->flag |= RenderUpdateFlag::Gradient; } @@ -282,8 +265,8 @@ Result Shape::fill(unique_ptr f) noexcept auto p = f.release(); if (!p) return Result::MemoryCorruption; - if (pImpl->fill && pImpl->fill != p) delete(pImpl->fill); - pImpl->fill = p; + if (pImpl->rs.fill && pImpl->rs.fill != p) delete(pImpl->rs.fill); + pImpl->rs.fill = p; pImpl->flag |= RenderUpdateFlag::Gradient; return Result::Success; @@ -292,17 +275,15 @@ Result Shape::fill(unique_ptr f) noexcept Result Shape::fillColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { - if (r) *r = pImpl->color[0]; - if (g) *g = pImpl->color[1]; - if (b) *b = pImpl->color[2]; - if (a) *a = pImpl->color[3]; + pImpl->rs.fillColor(r, g, b, a); return Result::Success; } + const Fill* Shape::fill() const noexcept { - return pImpl->fill; + return pImpl->rs.fill; } @@ -316,8 +297,7 @@ Result Shape::stroke(float width) noexcept float Shape::strokeWidth() const noexcept { - if (!pImpl->stroke) return 0; - return pImpl->stroke->width; + return pImpl->rs.strokeWidth(); } @@ -331,12 +311,7 @@ Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { - if (!pImpl->stroke) return Result::InsufficientCondition; - - if (r) *r = pImpl->stroke->color[0]; - if (g) *g = pImpl->stroke->color[1]; - if (b) *b = pImpl->stroke->color[2]; - if (a) *a = pImpl->stroke->color[3]; + if (!pImpl->rs.strokeColor(r, g, b, a)) return Result::InsufficientCondition; return Result::Success; } @@ -350,9 +325,7 @@ Result Shape::stroke(unique_ptr f) noexcept const Fill* Shape::strokeFill() const noexcept { - if (!pImpl->stroke) return nullptr; - - return pImpl->stroke->fill; + return pImpl->rs.strokeFill(); } @@ -373,11 +346,7 @@ Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept uint32_t Shape::strokeDash(const float** dashPattern) const noexcept { - if (!pImpl->stroke) return 0; - - if (dashPattern) *dashPattern = pImpl->stroke->dashPattern; - - return pImpl->stroke->dashCnt; + return pImpl->rs.strokeDash(dashPattern); } @@ -399,23 +368,19 @@ Result Shape::stroke(StrokeJoin join) noexcept StrokeCap Shape::strokeCap() const noexcept { - if (!pImpl->stroke) return StrokeCap::Square; - - return pImpl->stroke->cap; + return pImpl->rs.strokeCap(); } StrokeJoin Shape::strokeJoin() const noexcept { - if (!pImpl->stroke) return StrokeJoin::Bevel; - - return pImpl->stroke->join; + return pImpl->rs.strokeJoin(); } Result Shape::fill(FillRule r) noexcept { - pImpl->rule = r; + pImpl->rs.rule = r; return Result::Success; } @@ -423,5 +388,5 @@ Result Shape::fill(FillRule r) noexcept FillRule Shape::fillRule() const noexcept { - return pImpl->rule; + return pImpl->rs.rule; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index fa2786f..9f39dfa 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -30,243 +30,155 @@ /* Internal Class Implementation */ /************************************************************************/ -struct ShapeStroke +struct Shape::Impl { - float width; - uint8_t color[4]; - Fill *fill; - float* dashPattern; - uint32_t dashCnt; - StrokeCap cap; - StrokeJoin join; - - void copy(const ShapeStroke* src) + RenderShape rs; //shape data + RenderData rdata = nullptr; //engine data + uint32_t flag = RenderUpdateFlag::None; + + bool dispose(RenderMethod& renderer) { - width = src->width; - dashCnt = src->dashCnt; - cap = src->cap; - join = src->join; - - memcpy(color, src->color, sizeof(color)); - if (dashCnt > 0) { - dashPattern = static_cast(malloc(sizeof(float) * dashCnt)); - memcpy(dashPattern, src->dashPattern, sizeof(float) * dashCnt); - } - if (src->fill) fill = src->fill->duplicate(); + auto ret = renderer.dispose(rdata); + rdata = nullptr; + return ret; } - void clear() + bool render(RenderMethod& renderer) { - if (dashPattern) free(dashPattern); - if (fill) delete(fill); + return renderer.renderShape(rdata); } -}; - - -struct ShapePath -{ - PathCommand* cmds = nullptr; - uint32_t cmdCnt = 0; - uint32_t reservedCmdCnt = 0; - - Point *pts = nullptr; - uint32_t ptsCnt = 0; - uint32_t reservedPtsCnt = 0; - ~ShapePath() + void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) { - if (cmds) free(cmds); - if (pts) free(pts); + rdata = renderer.prepare(rs, rdata, transform, opacity, clips, static_cast(pFlag | flag), clipper); + flag = RenderUpdateFlag::None; + return rdata; } - ShapePath() + RenderRegion bounds(RenderMethod& renderer) { + return renderer.region(rdata); } - void duplicate(const ShapePath* src) + bool bounds(float* x, float* y, float* w, float* h) { - if (src->cmdCnt == 0 || src->ptsCnt == 0) return; - - cmdCnt = src->cmdCnt; - reservedCmdCnt = src->reservedCmdCnt; - ptsCnt = src->ptsCnt; - reservedPtsCnt = src->reservedPtsCnt; + //Path bounding size + if (rs.path.ptsCnt > 0 ) { + Point min = { rs.path.pts[0].x, rs.path.pts[0].y }; + Point max = { rs.path.pts[0].x, rs.path.pts[0].y }; + + for (uint32_t i = 1; i < rs.path.ptsCnt; ++i) { + if (rs.path.pts[i].x < min.x) min.x = rs.path.pts[i].x; + if (rs.path.pts[i].y < min.y) min.y = rs.path.pts[i].y; + if (rs.path.pts[i].x > max.x) max.x = rs.path.pts[i].x; + if (rs.path.pts[i].y > max.y) max.y = rs.path.pts[i].y; + } - cmds = static_cast(malloc(sizeof(PathCommand) * reservedCmdCnt)); - if (!cmds) return; - memcpy(cmds, src->cmds, sizeof(PathCommand) * cmdCnt); + if (x) *x = min.x; + if (y) *y = min.y; + if (w) *w = max.x - min.x; + if (h) *h = max.y - min.y; + } - pts = static_cast(malloc(sizeof(Point) * reservedPtsCnt)); - if (!pts) { - free(cmds); - return; + //Stroke feathering + if (rs.stroke) { + if (x) *x -= rs.stroke->width * 0.5f; + if (y) *y -= rs.stroke->width * 0.5f; + if (w) *w += rs.stroke->width; + if (h) *h += rs.stroke->width; } - memcpy(pts, src->pts, sizeof(Point) * ptsCnt); + return rs.path.ptsCnt > 0 ? true : false; } void reserveCmd(uint32_t cmdCnt) { - if (cmdCnt <= reservedCmdCnt) return; - reservedCmdCnt = cmdCnt; - cmds = static_cast(realloc(cmds, sizeof(PathCommand) * reservedCmdCnt)); + if (cmdCnt <= rs.path.reservedCmdCnt) return; + rs.path.reservedCmdCnt = cmdCnt; + rs.path.cmds = static_cast(realloc(rs.path.cmds, sizeof(PathCommand) * rs.path.reservedCmdCnt)); } void reservePts(uint32_t ptsCnt) { - if (ptsCnt <= reservedPtsCnt) return; - reservedPtsCnt = ptsCnt; - pts = static_cast(realloc(pts, sizeof(Point) * reservedPtsCnt)); + if (ptsCnt <= rs.path.reservedPtsCnt) return; + rs.path.reservedPtsCnt = ptsCnt; + rs.path.pts = static_cast(realloc(rs.path.pts, sizeof(Point) * rs.path.reservedPtsCnt)); } void grow(uint32_t cmdCnt, uint32_t ptsCnt) { - reserveCmd(this->cmdCnt + cmdCnt); - reservePts(this->ptsCnt + ptsCnt); + reserveCmd(rs.path.cmdCnt + cmdCnt); + reservePts(rs.path.ptsCnt + ptsCnt); } void reset() { - cmdCnt = 0; - ptsCnt = 0; - } - - void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) - { - memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); - memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt); - this->cmdCnt += cmdCnt; - this->ptsCnt += ptsCnt; - } - - void moveTo(float x, float y) - { - if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); - if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); + rs.path.cmdCnt = 0; + rs.path.ptsCnt = 0; - cmds[cmdCnt++] = PathCommand::MoveTo; - pts[ptsCnt++] = {x, y}; + flag = RenderUpdateFlag::Path; } - void lineTo(float x, float y) + void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) { - if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); - if (ptsCnt + 2 > reservedPtsCnt) reservePts((ptsCnt + 2) * 2); + memcpy(rs.path.cmds + rs.path.cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); + memcpy(rs.path.pts + rs.path.ptsCnt, pts, sizeof(Point) * ptsCnt); + rs.path.cmdCnt += cmdCnt; + rs.path.ptsCnt += ptsCnt; - cmds[cmdCnt++] = PathCommand::LineTo; - pts[ptsCnt++] = {x, y}; + flag |= RenderUpdateFlag::Path; } - void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) + void moveTo(float x, float y) { - if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); - if (ptsCnt + 3 > reservedPtsCnt) reservePts((ptsCnt + 3) * 2); + if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2); + if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2); - cmds[cmdCnt++] = PathCommand::CubicTo; - pts[ptsCnt++] = {cx1, cy1}; - pts[ptsCnt++] = {cx2, cy2}; - pts[ptsCnt++] = {x, y}; - } + rs.path.cmds[rs.path.cmdCnt++] = PathCommand::MoveTo; + rs.path.pts[rs.path.ptsCnt++] = {x, y}; - void close() - { - if (cmdCnt > 0 && cmds[cmdCnt - 1] == PathCommand::Close) return; - - if (cmdCnt + 1 > reservedCmdCnt) reserveCmd((cmdCnt + 1) * 2); - cmds[cmdCnt++] = PathCommand::Close; + flag |= RenderUpdateFlag::Path; } - bool bounds(float* x, float* y, float* w, float* h) const + void lineTo(float x, float y) { - if (ptsCnt == 0) return false; - - Point min = { pts[0].x, pts[0].y }; - Point max = { pts[0].x, pts[0].y }; - - for (uint32_t i = 1; i < ptsCnt; ++i) { - if (pts[i].x < min.x) min.x = pts[i].x; - if (pts[i].y < min.y) min.y = pts[i].y; - if (pts[i].x > max.x) max.x = pts[i].x; - if (pts[i].y > max.y) max.y = pts[i].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; - - return true; - } -}; - - -struct Shape::Impl -{ - ShapePath path; - Fill *fill = nullptr; - ShapeStroke *stroke = nullptr; - uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a - FillRule rule = FillRule::Winding; - RenderData rdata = nullptr; //engine data - Shape *shape = nullptr; - uint32_t flag = RenderUpdateFlag::None; + if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2); + if (rs.path.ptsCnt + 2 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 2) * 2); - Impl(Shape* s) : shape(s) - { - } + rs.path.cmds[rs.path.cmdCnt++] = PathCommand::LineTo; + rs.path.pts[rs.path.ptsCnt++] = {x, y}; - ~Impl() - { - if (fill) delete(fill); - if (stroke) { - stroke->clear(); - free (stroke); - } + flag |= RenderUpdateFlag::Path; } - bool dispose(RenderMethod& renderer) + void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) { - auto ret = renderer.dispose(rdata); - rdata = nullptr; - return ret; - } + if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2); + if (rs.path.ptsCnt + 3 > rs.path.reservedPtsCnt) reservePts((rs.path.ptsCnt + 3) * 2); - bool render(RenderMethod& renderer) - { - return renderer.renderShape(rdata); - } + rs.path.cmds[rs.path.cmdCnt++] = PathCommand::CubicTo; + rs.path.pts[rs.path.ptsCnt++] = {cx1, cy1}; + rs.path.pts[rs.path.ptsCnt++] = {cx2, cy2}; + rs.path.pts[rs.path.ptsCnt++] = {x, y}; - void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) - { - this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast(pFlag | flag), clipper); - flag = RenderUpdateFlag::None; - return this->rdata; + flag |= RenderUpdateFlag::Path; } - RenderRegion bounds(RenderMethod& renderer) + void close() { - return renderer.region(rdata); - } + if (rs.path.cmdCnt > 0 && rs.path.cmds[rs.path.cmdCnt - 1] == PathCommand::Close) return; - bool bounds(float* x, float* y, float* w, float* h) - { - auto ret = path.bounds(x, y, w, h); + if (rs.path.cmdCnt + 1 > rs.path.reservedCmdCnt) reserveCmd((rs.path.cmdCnt + 1) * 2); + rs.path.cmds[rs.path.cmdCnt++] = PathCommand::Close; - //Stroke feathering - if (stroke) { - if (x) *x -= stroke->width * 0.5f; - if (y) *y -= stroke->width * 0.5f; - if (w) *w += stroke->width; - if (h) *h += stroke->width; - } - return ret; + flag |= RenderUpdateFlag::Path; } bool strokeWidth(float width) { //TODO: Size Exception? - if (!stroke) stroke = static_cast(calloc(sizeof(ShapeStroke), 1)); - stroke->width = width; + if (!rs.stroke) rs.stroke = new RenderStroke(); + rs.stroke->width = width; flag |= RenderUpdateFlag::Stroke; return true; @@ -274,8 +186,8 @@ struct Shape::Impl bool strokeCap(StrokeCap cap) { - if (!stroke) stroke = static_cast(calloc(sizeof(ShapeStroke), 1)); - stroke->cap = cap; + if (!rs.stroke) rs.stroke = new RenderStroke(); + rs.stroke->cap = cap; flag |= RenderUpdateFlag::Stroke; return true; @@ -283,8 +195,8 @@ struct Shape::Impl bool strokeJoin(StrokeJoin join) { - if (!stroke) stroke = static_cast(calloc(sizeof(ShapeStroke), 1)); - stroke->join = join; + if (!rs.stroke) rs.stroke = new RenderStroke(); + rs.stroke->join = join; flag |= RenderUpdateFlag::Stroke; return true; @@ -292,17 +204,17 @@ struct Shape::Impl bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - if (!stroke) stroke = static_cast(calloc(sizeof(ShapeStroke), 1)); - if (stroke->fill) { - delete(stroke->fill); - stroke->fill = nullptr; + if (!rs.stroke) rs.stroke = new RenderStroke(); + if (rs.stroke->fill) { + delete(rs.stroke->fill); + rs.stroke->fill = nullptr; flag |= RenderUpdateFlag::GradientStroke; } - stroke->color[0] = r; - stroke->color[1] = g; - stroke->color[2] = b; - stroke->color[3] = a; + rs.stroke->color[0] = r; + rs.stroke->color[1] = g; + rs.stroke->color[2] = b; + rs.stroke->color[3] = a; flag |= RenderUpdateFlag::Stroke; @@ -314,9 +226,9 @@ struct Shape::Impl auto p = f.release(); if (!p) return Result::MemoryCorruption; - if (!stroke) stroke = static_cast(calloc(sizeof(ShapeStroke), 1)); - if (stroke->fill && stroke->fill != p) delete(stroke->fill); - stroke->fill = p; + if (!rs.stroke) rs.stroke = new RenderStroke(); + if (rs.stroke->fill && rs.stroke->fill != p) delete(rs.stroke->fill); + rs.stroke->fill = p; flag |= RenderUpdateFlag::Stroke; flag |= RenderUpdateFlag::GradientStroke; @@ -328,23 +240,23 @@ struct Shape::Impl { //Reset dash if (!pattern && cnt == 0) { - free(stroke->dashPattern); - stroke->dashPattern = nullptr; + free(rs.stroke->dashPattern); + rs.stroke->dashPattern = nullptr; } else { - if (!stroke) stroke = static_cast(calloc(sizeof(ShapeStroke), 1)); - if (stroke->dashCnt != cnt) { - free(stroke->dashPattern); - stroke->dashPattern = nullptr; + if (!rs.stroke) rs.stroke = new RenderStroke(); + if (rs.stroke->dashCnt != cnt) { + free(rs.stroke->dashPattern); + rs.stroke->dashPattern = nullptr; } - if (!stroke->dashPattern) { - stroke->dashPattern = static_cast(malloc(sizeof(float) * cnt)); - if (!stroke->dashPattern) return false; + if (!rs.stroke->dashPattern) { + rs.stroke->dashPattern = static_cast(malloc(sizeof(float) * cnt)); + if (!rs.stroke->dashPattern) return false; } for (uint32_t i = 0; i < cnt; ++i) { - stroke->dashPattern[i] = pattern[i]; + rs.stroke->dashPattern[i] = pattern[i]; } } - stroke->dashCnt = cnt; + rs.stroke->dashCnt = cnt; flag |= RenderUpdateFlag::Stroke; return true; @@ -355,29 +267,52 @@ struct Shape::Impl auto ret = Shape::gen(); auto dup = ret.get()->pImpl; - dup->rule = rule; + dup->rs.rule = rs.rule; //Color - memcpy(dup->color, color, sizeof(color)); + memcpy(dup->rs.color, rs.color, sizeof(rs.color)); dup->flag = RenderUpdateFlag::Color; //Path - dup->path.duplicate(&path); + if (rs.path.cmdCnt > 0 && rs.path.ptsCnt > 0) { + dup->rs.path.cmdCnt = rs.path.cmdCnt; + dup->rs.path.reservedCmdCnt = rs.path.reservedCmdCnt; + dup->rs.path.ptsCnt = rs.path.ptsCnt; + dup->rs.path.reservedPtsCnt = rs.path.reservedPtsCnt; + + dup->rs.path.cmds = static_cast(malloc(sizeof(PathCommand) * dup->rs.path.reservedCmdCnt)); + if (dup->rs.path.cmds) memcpy(dup->rs.path.cmds, rs.path.cmds, sizeof(PathCommand) * dup->rs.path.cmdCnt); + + dup->rs.path.pts = static_cast(malloc(sizeof(Point) * dup->rs.path.reservedPtsCnt)); + if (dup->rs.path.pts) memcpy(dup->rs.path.pts, rs.path.pts, sizeof(Point) * dup->rs.path.ptsCnt); + } dup->flag |= RenderUpdateFlag::Path; //Stroke - if (stroke) { - dup->stroke = static_cast(calloc(sizeof(ShapeStroke), 1)); - dup->stroke->copy(stroke); + if (rs.stroke) { + dup->rs.stroke = new RenderStroke(); + dup->rs.stroke->width = rs.stroke->width; + dup->rs.stroke->dashCnt = rs.stroke->dashCnt; + dup->rs.stroke->cap = rs.stroke->cap; + dup->rs.stroke->join = rs.stroke->join; + 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); + } + dup->flag |= RenderUpdateFlag::Stroke; - if (stroke->fill) + if (rs.stroke->fill) { + dup->rs.stroke->fill = rs.stroke->fill->duplicate(); dup->flag |= RenderUpdateFlag::GradientStroke; + } } //Fill - if (fill) { - dup->fill = fill->duplicate(); + if (rs.fill) { + dup->rs.fill = rs.fill->duplicate(); dup->flag |= RenderUpdateFlag::Gradient; } -- 2.7.4 From 76231d664046b9b078355c7831211be191abc425 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 5 Feb 2023 11:42:37 +0900 Subject: [PATCH 10/16] gl_engine: -- compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit ../src/lib/gl_engine/tvgGlRenderer.cpp: In member function ‘virtual bool GlRenderer::renderShape(tvg::RenderData)’: ../src/lib/gl_engine/tvgGlRenderer.cpp:171:30: warning: ‘a’ may be used uninitialized in this function [-Wmaybe-uninitialized] 171 | drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke); | ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../src/lib/gl_engine/tvgGlRenderer.cpp:171:30: warning: ‘b’ may be used uninitialized in this function [-Wmaybe-uninitialized] ../src/lib/gl_engine/tvgGlRenderer.cpp:171:30: warning: ‘g’ may be used uninitialized in this function [-Wmaybe-uninitialized] ../src/lib/gl_engine/tvgGlRenderer.cpp:171:30: warning: ‘r’ may be used uninitialized in this function [-Wmaybe-uninitialized] ../src/lib/gl_engine/tvgGlRenderer.cpp: In member function ‘virtual void* GlRenderer::prepare(const tvg::RenderShape&, tvg::RenderData, const tvg::RenderTransform*, uint32_t, tvg::Array&, tvg::RenderUpdateFlag, bool)’: ../src/lib/gl_engine/tvgGlRenderer.cpp:215:21: warning: ‘alphaS’ may be used uninitialized in this function [-Wmaybe-uninitialized] 215 | uint8_t alphaF, alphaS; Change-Id: I65d6cc0b6449342232287f295c06ef640e50b389 --- src/lib/gl_engine/tvgGlRenderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 3031f46..517e64e 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -140,7 +140,7 @@ bool GlRenderer::renderShape(RenderData data) auto sdata = static_cast(data); if (!sdata) return false; - uint8_t r, g, b, a; + uint8_t r = 0, g = 0, b = 0, a = 0; size_t flags = static_cast(sdata->updateFlag); GL_CHECK(glViewport(0, 0, (GLsizei)sdata->viewWd, (GLsizei)sdata->viewHt)); @@ -212,7 +212,7 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const sdata->geometry = make_unique(); //invisible? - uint8_t alphaF, alphaS; + uint8_t alphaF = 0, alphaS = 0; rshape.fillColor(nullptr, nullptr, nullptr, &alphaF); rshape.strokeColor(nullptr, nullptr, nullptr, &alphaS); auto strokeWd = rshape.strokeWidth(); -- 2.7.4 From 3311bccc0d92ea1536b654a2e5cfa1c8f4c5d14c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sun, 5 Feb 2023 11:44:59 +0900 Subject: [PATCH 11/16] common shape: code refactoring. keep name consistency. Change-Id: I902d163f50457e7e82180ad9259e8952257cd302 --- src/lib/tvgShapeImpl.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 9f39dfa..74988c3 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -33,31 +33,31 @@ struct Shape::Impl { RenderShape rs; //shape data - RenderData rdata = nullptr; //engine data + RenderData rd = nullptr; //engine data uint32_t flag = RenderUpdateFlag::None; bool dispose(RenderMethod& renderer) { - auto ret = renderer.dispose(rdata); - rdata = nullptr; + auto ret = renderer.dispose(rd); + rd = nullptr; return ret; } bool render(RenderMethod& renderer) { - return renderer.renderShape(rdata); + return renderer.renderShape(rd); } void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) { - rdata = renderer.prepare(rs, rdata, transform, opacity, clips, static_cast(pFlag | flag), clipper); + rd = renderer.prepare(rs, rd, transform, opacity, clips, static_cast(pFlag | flag), clipper); flag = RenderUpdateFlag::None; - return rdata; + return rd; } RenderRegion bounds(RenderMethod& renderer) { - return renderer.region(rdata); + return renderer.region(rd); } bool bounds(float* x, float* y, float* w, float* h) -- 2.7.4 From b2dc9433f70278c29b659081627399ecd3dfd6b9 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 20 Jan 2023 13:13:01 +0900 Subject: [PATCH 12/16] loader: Support ABGR colorspace Since the color space is set at the time of specifying the target buffer of the canvas, there is no way to know the color space when the picture is loaded. So, check the color space applied to SwCanvas at the time of reload() and change the color space. There is an issue of BGR color space support for each loader. The external_jpg loader resets the TJPF color space and calls read() to get a new buffer. In the case of external_png, we need to change the color value directly because it have to start over from begin_read_*. This solution can affect performance as much as it access again image buffer that have already been `read()` done. However, this only happens once. Change-Id: Ib7f25b5bc5871cfe59ad3963d26536269b48a3f5 --- src/lib/gl_engine/tvgGlRenderer.cpp | 7 +++++++ src/lib/gl_engine/tvgGlRenderer.h | 2 ++ src/lib/sw_engine/tvgSwRenderer.cpp | 11 ++++++++-- src/lib/sw_engine/tvgSwRenderer.h | 4 +++- src/lib/tvgLoadModule.h | 3 ++- src/lib/tvgPictureImpl.h | 4 +++- src/lib/tvgRender.h | 2 ++ src/loaders/external_jpg/tvgJpgLoader.cpp | 30 ++++++++++++++++++++++---- src/loaders/external_jpg/tvgJpgLoader.h | 2 +- src/loaders/external_png/tvgPngLoader.cpp | 29 ++++++++++++++++++++++--- src/loaders/external_png/tvgPngLoader.h | 4 ++-- src/loaders/jpg/tvgJpgLoader.cpp | 28 ++++++++++++++++++++++--- src/loaders/jpg/tvgJpgLoader.h | 2 +- src/loaders/png/tvgPngLoader.cpp | 28 ++++++++++++++++++++++--- src/loaders/png/tvgPngLoader.h | 2 +- src/loaders/raw/tvgRawLoader.cpp | 35 ++++++++++++++++++++++++------- src/loaders/raw/tvgRawLoader.h | 4 ++-- 17 files changed, 165 insertions(+), 32 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 517e64e..fcd33ad 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -123,6 +123,13 @@ bool GlRenderer::endComposite(TVG_UNUSED Compositor* cmp) } +int32_t GlRenderer::colorSpace() +{ + //TODO: return a proper color space value. + return -1; +} + + bool GlRenderer::renderImage(TVG_UNUSED void* data) { return false; diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 4d1bb87..3263231 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -50,6 +50,8 @@ public: bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override; bool endComposite(Compositor* cmp) override; + uint32_t colorSpace() override; + static GlRenderer* gen(); static int init(TVG_UNUSED uint32_t threads); static int32_t init(); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 17dff57..6a1a881 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -296,7 +296,7 @@ bool SwRenderer::viewport(const RenderRegion& vp) } -bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs) +bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace) { if (!buffer || stride == 0 || w == 0 || h == 0 || w > stride) return false; @@ -306,7 +306,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t surface->stride = stride; surface->w = w; surface->h = h; - surface->cs = cs; + surface->cs = colorSpace; vport.x = vport.y = 0; vport.w = surface->w; @@ -661,6 +661,13 @@ SwRenderer::SwRenderer():mpool(globalMpool) } +uint32_t SwRenderer::colorSpace() +{ + if (surface) return surface->cs; + return tvg::SwCanvas::ARGB8888; +} + + bool SwRenderer::init(uint32_t threads) { if ((initEngineCnt++) > 0) return true; diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index c3eadbd..690b7ff 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -50,7 +50,7 @@ public: bool clear() override; bool sync() override; - bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace); bool mempool(bool shared); Compositor* target(const RenderRegion& region) override; @@ -58,6 +58,8 @@ public: bool endComposite(Compositor* cmp) override; void clearCompositors(); + uint32_t colorSpace() override; + static SwRenderer* gen(); static bool init(uint32_t threads); static int32_t init(); diff --git a/src/lib/tvgLoadModule.h b/src/lib/tvgLoadModule.h index 2c2ffda..4637c90 100644 --- a/src/lib/tvgLoadModule.h +++ b/src/lib/tvgLoadModule.h @@ -37,6 +37,7 @@ public: float vw = 0; float vh = 0; float w = 0, h = 0; //default image size + uint32_t colorSpace = SwCanvas::ARGB8888; virtual ~LoadModule() {} @@ -49,7 +50,7 @@ public: virtual bool read() = 0; virtual bool close() = 0; - virtual unique_ptr bitmap() { return nullptr; } + virtual unique_ptr bitmap(uint32_t colorSpace) { return nullptr; } virtual unique_ptr paint() { return nullptr; } }; diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index b7e2ba0..6ef2313 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -69,6 +69,7 @@ struct Picture::Impl void* rdata = nullptr; //engine data float w = 0, h = 0; bool resizing = false; + uint32_t rendererColorSpace = 0; ~Impl() { @@ -104,7 +105,7 @@ struct Picture::Impl } } free(surface); - if ((surface = loader->bitmap().release())) { + if ((surface = loader->bitmap(rendererColorSpace).release())) { loader->close(); return RenderUpdateFlag::Image; } @@ -128,6 +129,7 @@ struct Picture::Impl void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) { + rendererColorSpace = renderer.colorSpace(); auto flag = reload(); if (surface) { diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index e9ad821..55bbec1 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -203,6 +203,8 @@ public: virtual Compositor* target(const RenderRegion& region) = 0; virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0; virtual bool endComposite(Compositor* cmp) = 0; + + virtual uint32_t colorSpace() = 0; }; } diff --git a/src/loaders/external_jpg/tvgJpgLoader.cpp b/src/loaders/external_jpg/tvgJpgLoader.cpp index 5920f7c..7ead54c 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.cpp +++ b/src/loaders/external_jpg/tvgJpgLoader.cpp @@ -37,6 +37,24 @@ void JpgLoader::clear() freeData = false; } +uint32_t convertColorSpaceType(uint32_t colorSpace) +{ + uint32_t tjpfColorSpace = TJPF_RGBX; + switch (colorSpace) + { + case SwCanvas::ARGB8888: + case SwCanvas::ARGB8888_STRAIGHT: + default: + tjpfColorSpace = TJPF_BGRX; + break; + case SwCanvas::ABGR8888: + case SwCanvas::ABGR8888_STRAIGHT: + tjpfColorSpace = TJPF_RGBX; + break; + } + return tjpfColorSpace; +} + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -127,11 +145,11 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy) bool JpgLoader::read() { if (image) tjFree(image); - image = (unsigned char *)tjAlloc(static_cast(w) * static_cast(h) * tjPixelSize[TJPF_BGRX]); + image = (unsigned char *)tjAlloc(static_cast(w) * static_cast(h) * tjPixelSize[convertColorSpaceType(colorSpace)]); if (!image) return false; //decompress jpg image - if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), TJPF_BGRX, 0) < 0) { + if (tjDecompress2(jpegDecompressor, data, size, image, static_cast(w), 0, static_cast(h), convertColorSpaceType(colorSpace), 0) < 0) { TVGERR("JPG LOADER", "%s", tjGetErrorStr()); tjFree(image); image = nullptr; @@ -149,16 +167,20 @@ bool JpgLoader::close() } -unique_ptr JpgLoader::bitmap() +unique_ptr JpgLoader::bitmap(uint32_t colorSpace) { if (!image) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + read(); + } auto surface = static_cast(malloc(sizeof(Surface))); surface->buffer = (uint32_t*)(image); surface->stride = w; surface->w = w; surface->h = h; - surface->cs = SwCanvas::ARGB8888; + surface->cs = colorSpace; return unique_ptr(surface); } diff --git a/src/loaders/external_jpg/tvgJpgLoader.h b/src/loaders/external_jpg/tvgJpgLoader.h index c8c9345..da7b59e 100644 --- a/src/loaders/external_jpg/tvgJpgLoader.h +++ b/src/loaders/external_jpg/tvgJpgLoader.h @@ -38,7 +38,7 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; private: void clear(); diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index 4061a49..2dbedd8 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -42,6 +42,24 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h) } +static inline uint32_t CHANGE_COLORSPACE(uint32_t c) +{ + return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16); +} + + +static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h) +{ + auto buffer = data; + for (uint32_t y = 0; y < h; ++y, buffer += w) { + auto src = buffer; + for (uint32_t x = 0; x < w; ++x, ++src) { + *src = CHANGE_COLORSPACE(*src); + } + } +} + + PngLoader::PngLoader() { image = static_cast(calloc(1, sizeof(png_image))); @@ -110,16 +128,21 @@ bool PngLoader::close() return true; } -unique_ptr PngLoader::bitmap() +unique_ptr PngLoader::bitmap(uint32_t colorSpace) { if (!content) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(content, w, h); + } auto surface = static_cast(malloc(sizeof(Surface))); - surface->buffer = (uint32_t*)(content); + surface->buffer = content; surface->stride = w; surface->w = w; surface->h = h; - surface->cs = SwCanvas::ARGB8888; + surface->cs = colorSpace; return unique_ptr(surface); } + diff --git a/src/loaders/external_png/tvgPngLoader.h b/src/loaders/external_png/tvgPngLoader.h index 39d5fdb..48f44f5 100644 --- a/src/loaders/external_png/tvgPngLoader.h +++ b/src/loaders/external_png/tvgPngLoader.h @@ -37,11 +37,11 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; private: png_imagep image = nullptr; - const uint32_t* content = nullptr; + uint32_t* content = nullptr; }; #endif //_TVG_PNG_LOADER_H_ diff --git a/src/loaders/jpg/tvgJpgLoader.cpp b/src/loaders/jpg/tvgJpgLoader.cpp index dc50848..2b16090 100644 --- a/src/loaders/jpg/tvgJpgLoader.cpp +++ b/src/loaders/jpg/tvgJpgLoader.cpp @@ -28,6 +28,24 @@ /* Internal Class Implementation */ /************************************************************************/ +static inline uint32_t CHANGE_COLORSPACE(uint32_t c) +{ + return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16); +} + + +static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h) +{ + auto buffer = data; + for (uint32_t y = 0; y < h; ++y, buffer += w) { + auto src = buffer; + for (uint32_t x = 0; x < w; ++x, ++src) { + *src = CHANGE_COLORSPACE(*src); + } + } +} + + void JpgLoader::clear() { jpgdDelete(decoder); @@ -110,18 +128,22 @@ bool JpgLoader::close() } -unique_ptr JpgLoader::bitmap() +unique_ptr JpgLoader::bitmap(uint32_t colorSpace) { this->done(); if (!image) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(reinterpret_cast(image), w, h); + } auto surface = static_cast(malloc(sizeof(Surface))); - surface->buffer = (uint32_t*)(image); + surface->buffer = reinterpret_cast(image); surface->stride = static_cast(w); surface->w = static_cast(w); surface->h = static_cast(h); - surface->cs = SwCanvas::ARGB8888; + surface->cs = colorSpace; return unique_ptr(surface); } diff --git a/src/loaders/jpg/tvgJpgLoader.h b/src/loaders/jpg/tvgJpgLoader.h index 6d2febe..02aee45 100644 --- a/src/loaders/jpg/tvgJpgLoader.h +++ b/src/loaders/jpg/tvgJpgLoader.h @@ -45,7 +45,7 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; void run(unsigned tid) override; }; diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index cc44b0d..7233f30 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -49,6 +49,24 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h) } +static inline uint32_t CHANGE_COLORSPACE(uint32_t c) +{ + return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16); +} + + +static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h) +{ + auto buffer = data; + for (uint32_t y = 0; y < h; ++y, buffer += w) { + auto src = buffer; + for (uint32_t x = 0; x < w; ++x, ++src) { + *src = CHANGE_COLORSPACE(*src); + } + } +} + + void PngLoader::clear() { lodepng_state_cleanup(&state); @@ -163,18 +181,22 @@ bool PngLoader::close() } -unique_ptr PngLoader::bitmap() +unique_ptr PngLoader::bitmap(uint32_t colorSpace) { this->done(); if (!image) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(reinterpret_cast(image), w, h); + } auto surface = static_cast(malloc(sizeof(Surface))); - surface->buffer = (uint32_t*)(image); + surface->buffer = reinterpret_cast(image); surface->stride = static_cast(w); surface->w = static_cast(w); surface->h = static_cast(h); - surface->cs = SwCanvas::ARGB8888; + surface->cs = colorSpace; return unique_ptr(surface); } diff --git a/src/loaders/png/tvgPngLoader.h b/src/loaders/png/tvgPngLoader.h index 579d197..5e3c930 100644 --- a/src/loaders/png/tvgPngLoader.h +++ b/src/loaders/png/tvgPngLoader.h @@ -48,7 +48,7 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; void run(unsigned tid) override; }; diff --git a/src/loaders/raw/tvgRawLoader.cpp b/src/loaders/raw/tvgRawLoader.cpp index d8c0559..524cff1 100644 --- a/src/loaders/raw/tvgRawLoader.cpp +++ b/src/loaders/raw/tvgRawLoader.cpp @@ -29,6 +29,23 @@ /* Internal Class Implementation */ /************************************************************************/ +static inline uint32_t CHANGE_COLORSPACE(uint32_t c) +{ + return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16); +} + + +static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h) +{ + auto buffer = data; + for (uint32_t y = 0; y < h; ++y, buffer += w) { + auto src = buffer; + for (uint32_t x = 0; x < w; ++x, ++src) { + *src = CHANGE_COLORSPACE(*src); + } + } +} + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -55,7 +72,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) if (!content) return false; memcpy((void*)content, data, sizeof(uint32_t) * w * h); } - else content = data; + else content = const_cast(data); return true; } @@ -73,16 +90,20 @@ bool RawLoader::close() } -unique_ptr RawLoader::bitmap() +unique_ptr RawLoader::bitmap(uint32_t colorSpace) { if (!content) return nullptr; + if (this->colorSpace != colorSpace) { + this->colorSpace = colorSpace; + _changeColorSpace(content, w, h); + } auto surface = static_cast(malloc(sizeof(Surface))); - surface->buffer = (uint32_t*)(content); - surface->stride = (uint32_t)w; - surface->w = (uint32_t)w; - surface->h = (uint32_t)h; - surface->cs = SwCanvas::ARGB8888; + surface->buffer = content; + surface->stride = static_cast(w); + surface->w = static_cast(w); + surface->h = static_cast(h); + surface->cs = colorSpace; return unique_ptr(surface); } diff --git a/src/loaders/raw/tvgRawLoader.h b/src/loaders/raw/tvgRawLoader.h index d381010..a5e3d59 100644 --- a/src/loaders/raw/tvgRawLoader.h +++ b/src/loaders/raw/tvgRawLoader.h @@ -26,7 +26,7 @@ class RawLoader : public LoadModule { public: - const uint32_t* content = nullptr; + uint32_t* content = nullptr; bool copy = false; ~RawLoader(); @@ -36,7 +36,7 @@ public: bool read() override; bool close() override; - unique_ptr bitmap() override; + unique_ptr bitmap(uint32_t colorSpace) override; }; -- 2.7.4 From 776a4f4d2fab0a40c7ed672ca8bfc2bb3dd5ff48 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 10 Feb 2023 10:50:16 +0900 Subject: [PATCH 13/16] png_loader(static): Fix the colorspace of an image with an alpha channel Set colorspace to ABGR when colortype of lodepng is LCT_RGBA. Since an image without an alpha channel becomes an ARGB colorspace with LCT_RGB, it is the same as the default colorspace. Change-Id: Ia33ca50ab3340fe72f1b7af2ced35850854fc835 --- src/loaders/png/tvgPngLoader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index 7233f30..d415332 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -213,5 +213,7 @@ void PngLoader::run(unsigned tid) lodepng_decode(&image, &width, &height, &state, data, size); + if (state.info_png.color.colortype == LCT_RGBA) colorSpace = SwCanvas::ABGR8888; + _premultiply((uint32_t*)(image), width, height); } -- 2.7.4 From af593fe0eccc5fd337bbc12e2358db9a8541b02f Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Fri, 10 Feb 2023 13:46:06 +0900 Subject: [PATCH 14/16] png_loader(static): Move the colortype check code to open() Change-Id: I6711b294b24e3e89bf93f96e0c78f8026ac75375 --- src/loaders/png/tvgPngLoader.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index d415332..2d8f78b 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -125,6 +125,8 @@ bool PngLoader::open(const string& path) h = static_cast(height); ret = true; + if (state.info_png.color.colortype == LCT_RGBA) colorSpace = SwCanvas::ABGR8888; + goto finalize; failure: @@ -159,6 +161,8 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) h = static_cast(height); this->size = size; + if (state.info_png.color.colortype == LCT_RGBA) colorSpace = SwCanvas::ABGR8888; + return true; } @@ -213,7 +217,5 @@ void PngLoader::run(unsigned tid) lodepng_decode(&image, &width, &height, &state, data, size); - if (state.info_png.color.colortype == LCT_RGBA) colorSpace = SwCanvas::ABGR8888; - _premultiply((uint32_t*)(image), width, height); } -- 2.7.4 From 48719759e834522753e224cff8c0bb517fbc3cde Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 14 Mar 2023 23:39:48 +0900 Subject: [PATCH 15/16] sw_engine - ++safety Prevent any potential crash. @Issues: https://github.com/thorvg/thorvg/issues/1327 Change-Id: I57e6582f17a3beae475d85261439aa78ca5f6919 --- src/lib/sw_engine/tvgSwRasterTexmap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRasterTexmap.h b/src/lib/sw_engine/tvgSwRasterTexmap.h index 58906b6..40d4037 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmap.h +++ b/src/lib/sw_engine/tvgSwRasterTexmap.h @@ -548,7 +548,7 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans) static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox* region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) { //Exceptions: No dedicated drawing area? - if (!region && image->rle->size == 0) return false; + if (!image->rle || (!region && image->rle->size == 0)) return false; /* Prepare vertices. shift XY coordinates to match the sub-pixeling technique. */ @@ -605,7 +605,7 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const static bool _rasterTexmapPolygonMesh(SwSurface* surface, const SwImage* image, const Polygon* triangles, const uint32_t triangleCount, const Matrix* transform, const SwBBox* region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) { //Exceptions: No dedicated drawing area? - if (!region && image->rle->size == 0) return false; + if (!image->rle || (!region && image->rle->size == 0)) return false; // Step polygons once to transform auto transformedTris = (Polygon*)malloc(sizeof(Polygon) * triangleCount); -- 2.7.4 From 456f8c62ad81d8ce9fc6e4c3366f6719019a3bb6 Mon Sep 17 00:00:00 2001 From: jykeon Date: Thu, 16 Mar 2023 10:16:57 +0900 Subject: [PATCH 16/16] Bump up 0.8.9 Change-Id: I9c28a1e14fa3cb2bcad516b119f82316b730b130 Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index f39d1fd..9f6f5a0 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.8.8 +Version: 0.8.9 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4