From 1a332acd37cd061f7be109fe6db62c3759cac503 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 18 Apr 2025 13:40:37 +0900 Subject: [PATCH] renderer: revise the pImpl design with a better efficiency The following is a redesign that extends the class internally. The main goal is to preserve the characteristics of the pImpl idiom for data encapsulation, while simultaneously reducing the memory allocation overhead typically associated with pImpl. The stragegy is here: Rather than alloc the impl memory inside of the thorvg engine, impl extends the API classes in order to consolidate the memory. size has been decreased by -4kb with optimization=s issue: https://github.com/thorvg/thorvg/issues/3214 --- inc/thorvg.h | 23 ++++++-- src/loaders/lottie/tvgLottieBuilder.cpp | 6 +- src/renderer/gl_engine/tvgGlRenderer.cpp | 8 +-- src/renderer/sw_engine/tvgSwFill.cpp | 8 +-- src/renderer/tvgCommon.h | 2 - src/renderer/tvgFill.cpp | 36 ++++-------- src/renderer/tvgFill.h | 47 +++++++++------ src/renderer/tvgPaint.cpp | 19 ++---- src/renderer/tvgPaint.h | 16 +++--- src/renderer/tvgPicture.cpp | 9 +-- src/renderer/tvgPicture.h | 30 +++++----- src/renderer/tvgRender.h | 6 ++ src/renderer/tvgScene.cpp | 9 +-- src/renderer/tvgScene.h | 29 +++++----- src/renderer/tvgShape.cpp | 35 ++++++------ src/renderer/tvgShape.h | 73 ++++++++++++------------ src/renderer/tvgText.cpp | 7 +-- src/renderer/tvgText.h | 18 +++--- 18 files changed, 192 insertions(+), 189 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 37df5293..9a029eb0 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -801,8 +801,10 @@ public: * * Besides the APIs inherited from the Fill class, it enables setting and getting the linear gradient bounds. * The behavior outside the gradient bounds depends on the value specified in the spread API. + * + * @warning This class is not designed for inheritance. */ -class TVG_API LinearGradient final : public Fill +class TVG_API LinearGradient : public Fill { public: /** @@ -863,8 +865,9 @@ public: * * @brief A class representing the radial gradient fill of the Shape object. * + * @warning This class is not designed for inheritance. */ -class TVG_API RadialGradient final : public Fill +class TVG_API RadialGradient : public Fill { public: /** @@ -939,8 +942,10 @@ public: * * The stroke of Shape is an optional property in case the Shape needs to be represented with/without the outline borders. * It's efficient since the shape path and the stroking path can be shared with each other. It's also convenient when controlling both in one context. + * + * @warning This class is not designed for inheritance. */ -class TVG_API Shape final : public Paint +class TVG_API Shape : public Paint { public: /** @@ -1319,8 +1324,10 @@ public: * * @note Supported formats are depended on the available TVG loaders. * @note See Animation class if the picture data is animatable. + * + * @warning This class is not designed for inheritance. */ -class TVG_API Picture final : public Paint +class TVG_API Picture : public Paint { public: /** @@ -1450,8 +1457,10 @@ public: * * As a group, the scene can be transformed, made translucent and composited with other target paints, * its children will be affected by the scene world. + * + * @warning This class is not designed for inheritance. */ -class TVG_API Scene final : public Paint +class TVG_API Scene : public Paint { public: /** @@ -1546,9 +1555,11 @@ public: * * @brief A class to represent text objects in a graphical context, allowing for rendering and manipulation of unicode text. * + * @warning This class is not designed for inheritance. + * * @since 0.15 */ -class TVG_API Text final : public Paint +class TVG_API Text : public Paint { public: /** diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index 5b83d8d9..6f12338e 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -481,7 +481,7 @@ void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float if (ctx->repeaters.empty()) { _draw(parent, path, ctx); if (path->pathset(frameNo, SHAPE(ctx->merging)->rs.path, ctx->transform, tween, exps, ctx->modifier)) { - PAINT(ctx->merging)->update(RenderUpdateFlag::Path); + PAINT(ctx->merging)->mark(RenderUpdateFlag::Path); } } else { auto shape = path->pooling(); @@ -695,7 +695,7 @@ void LottieBuilder::updatePolystar(LottieGroup* parent, LottieObject** child, fl _draw(parent, star, ctx); if (star->type == LottiePolyStar::Star) updateStar(star, frameNo, (identity ? nullptr : &matrix), ctx->merging, ctx, tween, exps); else updatePolygon(parent, star, frameNo, (identity ? nullptr : &matrix), ctx->merging, ctx, tween, exps); - PAINT(ctx->merging)->update(RenderUpdateFlag::Path); + PAINT(ctx->merging)->mark(RenderUpdateFlag::Path); } else { auto shape = star->pooling(); shape->reset(); @@ -1037,7 +1037,7 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo) auto group = static_cast(*p); ARRAY_FOREACH(p, group->children) { if (static_cast(*p)->pathset(frameNo, SHAPE(shape)->rs.path, nullptr, tween, exps)) { - PAINT(shape)->update(RenderUpdateFlag::Path); + PAINT(shape)->mark(RenderUpdateFlag::Path); } } } diff --git a/src/renderer/gl_engine/tvgGlRenderer.cpp b/src/renderer/gl_engine/tvgGlRenderer.cpp index c8cdd986..f38504a9 100644 --- a/src/renderer/gl_engine/tvgGlRenderer.cpp +++ b/src/renderer/gl_engine/tvgGlRenderer.cpp @@ -1469,10 +1469,10 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const if (clipper) { sdata->updateFlag = (rshape.stroke && (rshape.stroke->width > 0)) ? RenderUpdateFlag::Stroke : RenderUpdateFlag::Path; } else { - if (alphaF) sdata->updateFlag = static_cast(RenderUpdateFlag::Color | sdata->updateFlag); - if (rshape.fill) sdata->updateFlag = static_cast(RenderUpdateFlag::Gradient | sdata->updateFlag); - if (alphaS) sdata->updateFlag = static_cast(RenderUpdateFlag::Stroke | sdata->updateFlag); - if (rshape.strokeFill()) sdata->updateFlag = static_cast(RenderUpdateFlag::GradientStroke | sdata->updateFlag); + if (alphaF) sdata->updateFlag = (RenderUpdateFlag::Color | sdata->updateFlag); + if (rshape.fill) sdata->updateFlag = (RenderUpdateFlag::Gradient | sdata->updateFlag); + if (alphaS) sdata->updateFlag = (RenderUpdateFlag::Stroke | sdata->updateFlag); + if (rshape.strokeFill()) sdata->updateFlag = (RenderUpdateFlag::GradientStroke | sdata->updateFlag); } if (sdata->updateFlag == RenderUpdateFlag::None) return sdata; diff --git a/src/renderer/sw_engine/tvgSwFill.cpp b/src/renderer/sw_engine/tvgSwFill.cpp index 01814566..fd31a744 100644 --- a/src/renderer/sw_engine/tvgSwFill.cpp +++ b/src/renderer/sw_engine/tvgSwFill.cpp @@ -67,10 +67,10 @@ static uint32_t _estimateAAMargin(const Fill* fdata) constexpr float marginScalingFactor = 800.0f; if (fdata->type() == Type::RadialGradient) { - auto radius = RADIAL(fdata)->r; + auto radius = CONST_RADIAL(fdata)->r; return tvg::zero(radius) ? 0 : static_cast(marginScalingFactor / radius); } else { - auto grad = LINEAR(fdata); + auto grad = CONST_LINEAR(fdata); Point p1 {grad->x1, grad->y1}; Point p2 {grad->x2, grad->y2}; auto len = length(&p1, &p2); @@ -226,7 +226,7 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix& pT fill->linear.dy /= len; fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; - auto transform = pTransform * linear->transform(); + const auto& transform = pTransform * linear->transform(); Matrix itransform; if (!inverse(&transform, &itransform)) return false; @@ -279,7 +279,7 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix& pT if (fill->radial.a > 0) fill->radial.invA = 1.0f / fill->radial.a; - auto transform = pTransform * radial->transform(); + const auto& transform = pTransform * radial->transform(); Matrix itransform; if (!inverse(&transform, &itransform)) return false; diff --git a/src/renderer/tvgCommon.h b/src/renderer/tvgCommon.h index fdd6b48f..b9071c44 100644 --- a/src/renderer/tvgCommon.h +++ b/src/renderer/tvgCommon.h @@ -89,8 +89,6 @@ namespace tvg { uint16_t THORVG_VERSION_NUMBER(); - #define PIMPL(INST, CLASS) ((CLASS::Impl*)INST->pImpl) //Access to pimpl - #define TVG_DELETE(PAINT) \ if (PAINT->refCnt() == 0) delete(PAINT) diff --git a/src/renderer/tvgFill.cpp b/src/renderer/tvgFill.cpp index 279f5ab1..acbbcfd5 100644 --- a/src/renderer/tvgFill.cpp +++ b/src/renderer/tvgFill.cpp @@ -27,16 +27,8 @@ /* Fill Class Implementation */ /************************************************************************/ -Fill::Fill() -{ -} - - -Fill::~Fill() -{ - delete(pImpl); -} - +Fill::Fill() = default; +Fill::~Fill() = default; Result Fill::colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept { @@ -79,7 +71,9 @@ Matrix& Fill::transform() const noexcept Fill* Fill::duplicate() const noexcept { - return pImpl->duplicate(); + if (type() == Type::LinearGradient) return CONST_LINEAR(this)->duplicate(); + else if (type() == Type::RadialGradient) return CONST_RADIAL(this)->duplicate(); + return nullptr; } @@ -87,11 +81,7 @@ Fill* Fill::duplicate() const noexcept /* RadialGradient Class Implementation */ /************************************************************************/ - -RadialGradient::RadialGradient() -{ - Fill::pImpl = new Impl; -} +RadialGradient::RadialGradient() = default; Result RadialGradient::radial(float cx, float cy, float r, float fx, float fy, float fr) noexcept @@ -102,13 +92,13 @@ Result RadialGradient::radial(float cx, float cy, float r, float fx, float fy, f Result RadialGradient::radial(float* cx, float* cy, float* r, float* fx, float* fy, float* fr) const noexcept { - return RADIAL(this)->radial(cx, cy, r, fx, fy, fr); + return CONST_RADIAL(this)->radial(cx, cy, r, fx, fy, fr); } RadialGradient* RadialGradient::gen() noexcept { - return new RadialGradient; + return new RadialGradientImpl; } @@ -122,11 +112,7 @@ Type RadialGradient::type() const noexcept /* LinearGradient Class Implementation */ /************************************************************************/ - -LinearGradient::LinearGradient() -{ - Fill::pImpl = new Impl; -} +LinearGradient::LinearGradient() = default; Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept @@ -137,13 +123,13 @@ Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept { - return LINEAR(this)->linear(x1, y1, x2, y2); + return CONST_LINEAR(this)->linear(x1, y1, x2, y2); } LinearGradient* LinearGradient::gen() noexcept { - return new LinearGradient; + return new LinearGradientImpl; } diff --git a/src/renderer/tvgFill.h b/src/renderer/tvgFill.h index 0a4b1743..86325871 100644 --- a/src/renderer/tvgFill.h +++ b/src/renderer/tvgFill.h @@ -26,8 +26,11 @@ #include "tvgCommon.h" #include "tvgMath.h" -#define LINEAR(A) PIMPL(A, LinearGradient) -#define RADIAL(A) PIMPL(A, RadialGradient) +#define LINEAR(A) static_cast(A) +#define CONST_LINEAR(A) static_cast(A) + +#define RADIAL(A) static_cast(A) +#define CONST_RADIAL(A) static_cast(A) struct Fill::Impl { @@ -41,13 +44,13 @@ struct Fill::Impl tvg::free(colorStops); } - void copy(Fill::Impl* dup) + void copy(const Fill::Impl& dup) { - cnt = dup->cnt; - spread = dup->spread; - colorStops = tvg::malloc(sizeof(ColorStop) * dup->cnt); - if (dup->cnt > 0) memcpy(colorStops, dup->colorStops, sizeof(ColorStop) * dup->cnt); - transform = dup->transform; + cnt = dup.cnt; + spread = dup.spread; + colorStops = tvg::malloc(sizeof(ColorStop) * dup.cnt); + if (dup.cnt > 0) memcpy(colorStops, dup.colorStops, sizeof(ColorStop) * dup.cnt); + transform = dup.transform; } Result update(const ColorStop* colorStops, uint32_t cnt) @@ -72,21 +75,26 @@ struct Fill::Impl return Result::Success; } - - virtual Fill* duplicate() = 0; }; -struct RadialGradient::Impl : Fill::Impl +struct RadialGradientImpl : RadialGradient { + Fill::Impl impl; + float cx = 0.0f, cy = 0.0f; float fx = 0.0f, fy = 0.0f; float r = 0.0f, fr = 0.0f; - Fill* duplicate() override + RadialGradientImpl() + { + Fill::pImpl = &impl; + } + + Fill* duplicate() const { auto ret = RadialGradient::gen(); - RADIAL(ret)->copy(this); + RADIAL(ret)->impl.copy(this->impl); RADIAL(ret)->cx = cx; RADIAL(ret)->cy = cy; RADIAL(ret)->r = r; @@ -125,17 +133,24 @@ struct RadialGradient::Impl : Fill::Impl }; -struct LinearGradient::Impl : Fill::Impl +struct LinearGradientImpl : LinearGradient { + Fill::Impl impl; + float x1 = 0.0f; float y1 = 0.0f; float x2 = 0.0f; float y2 = 0.0f; - Fill* duplicate() override + LinearGradientImpl() + { + Fill::pImpl = &impl; + } + + Fill* duplicate() const { auto ret = LinearGradient::gen(); - LINEAR(ret)->copy(this); + LINEAR(ret)->impl.copy(this->impl); LINEAR(ret)->x1 = x1; LINEAR(ret)->y1 = y1; LINEAR(ret)->x2 = x2; diff --git a/src/renderer/tvgPaint.cpp b/src/renderer/tvgPaint.cpp index ad9fa0b2..e4d9d26e 100644 --- a/src/renderer/tvgPaint.cpp +++ b/src/renderer/tvgPaint.cpp @@ -163,7 +163,7 @@ Paint* Paint::Impl::duplicate(Paint* ret) //duplicate Transform ret->pImpl->tr = tr; - ret->pImpl->renderFlag |= RenderUpdateFlag::Transform; + ret->pImpl->mark(RenderUpdateFlag::Transform); ret->pImpl->opacity = opacity; @@ -247,7 +247,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Arrayclipper) { auto pclip = PAINT(this->clipper); - if (pclip->renderFlag) renderFlag |= RenderUpdateFlag::Clip; + if (pclip->renderFlag) mark(RenderUpdateFlag::Clip); pclip->ctxFlag &= ~ContextFlag::FastTrack; //reset viewport = renderer->viewport(); /* TODO: Intersect the clipper's clipper, if both are FastTrack. @@ -263,7 +263,7 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Array(pFlag | renderFlag); + auto newFlag = pFlag | renderFlag; renderFlag = RenderUpdateFlag::None; opacity = MULTIPLY(opacity, this->opacity); @@ -317,15 +317,8 @@ Result Paint::Impl::bounds(Point* pt4, Matrix* pm, bool obb, bool stroking) /* External Class Implementation */ /************************************************************************/ -Paint :: Paint() -{ -} - - -Paint :: ~Paint() -{ - delete(pImpl); -} +Paint :: Paint() = default; +Paint :: ~Paint() = default; Result Paint::rotate(float degree) noexcept @@ -410,7 +403,7 @@ Result Paint::opacity(uint8_t o) noexcept if (pImpl->opacity == o) return Result::Success; pImpl->opacity = o; - pImpl->renderFlag |= RenderUpdateFlag::Color; + pImpl->mark(RenderUpdateFlag::Color); return Result::Success; } diff --git a/src/renderer/tvgPaint.h b/src/renderer/tvgPaint.h index 9c02af46..d0d84455 100644 --- a/src/renderer/tvgPaint.h +++ b/src/renderer/tvgPaint.h @@ -27,7 +27,8 @@ #include "tvgRender.h" #include "tvgMath.h" -#define PAINT(A) PIMPL(A, Paint) + +#define PAINT(A) ((Paint::Impl*)A->pImpl) namespace tvg { @@ -85,6 +86,7 @@ namespace tvg Impl(Paint* pnt) : paint(pnt) { + pnt->pImpl = this; reset(); } @@ -129,7 +131,7 @@ namespace tvg return refCnt; } - void update(RenderUpdateFlag flag) + void mark(RenderUpdateFlag flag) { renderFlag |= flag; } @@ -138,7 +140,7 @@ namespace tvg { if (&tr.m != &m) tr.m = m; tr.overriding = true; - renderFlag |= RenderUpdateFlag::Transform; + mark(RenderUpdateFlag::Transform); return true; } @@ -236,7 +238,7 @@ namespace tvg if (tr.overriding) return false; if (tvg::equal(degree, tr.degree)) return true; tr.degree = degree; - renderFlag |= RenderUpdateFlag::Transform; + mark(RenderUpdateFlag::Transform); return true; } @@ -246,7 +248,7 @@ namespace tvg if (tr.overriding) return false; if (tvg::equal(factor, tr.scale)) return true; tr.scale = factor; - renderFlag |= RenderUpdateFlag::Transform; + mark(RenderUpdateFlag::Transform); return true; } @@ -257,7 +259,7 @@ namespace tvg if (tvg::equal(x, tr.m.e13) && tvg::equal(y, tr.m.e23)) return true; tr.m.e13 = x; tr.m.e23 = y; - renderFlag |= RenderUpdateFlag::Transform; + mark(RenderUpdateFlag::Transform); return true; } @@ -266,7 +268,7 @@ namespace tvg { if (blendMethod != method) { blendMethod = method; - renderFlag |= RenderUpdateFlag::Blend; + mark(RenderUpdateFlag::Blend); } } diff --git a/src/renderer/tvgPicture.cpp b/src/renderer/tvgPicture.cpp index 2997fa7c..7f710de5 100644 --- a/src/renderer/tvgPicture.cpp +++ b/src/renderer/tvgPicture.cpp @@ -23,15 +23,12 @@ #include "tvgPaint.h" #include "tvgPicture.h" -Picture::Picture() -{ - pImpl = new Impl(this); -} +Picture::Picture() = default; Picture* Picture::gen() noexcept { - return new Picture; + return new PictureImpl; } @@ -74,7 +71,7 @@ Result Picture::size(float w, float h) noexcept Result Picture::size(float* w, float* h) const noexcept { - return PICTURE(this)->size(w, h); + return CONST_PICTURE(this)->size(w, h); } diff --git a/src/renderer/tvgPicture.h b/src/renderer/tvgPicture.h index 259e790a..5a032c5a 100644 --- a/src/renderer/tvgPicture.h +++ b/src/renderer/tvgPicture.h @@ -26,7 +26,8 @@ #include "tvgPaint.h" #include "tvgLoader.h" -#define PICTURE(A) PIMPL(A, Picture) +#define PICTURE(A) static_cast(A) +#define CONST_PICTURE(A) static_cast(A) struct PictureIterator : Iterator { @@ -55,8 +56,9 @@ struct PictureIterator : Iterator }; -struct Picture::Impl : Paint::Impl +struct PictureImpl : Picture { + Paint::Impl impl; ImageLoader* loader = nullptr; Paint* vector = nullptr; //vector picture uses RenderSurface* bitmap = nullptr; //bitmap picture uses @@ -64,11 +66,11 @@ struct Picture::Impl : Paint::Impl uint8_t compFlag = CompositionFlag::Invalid; bool resizing = false; - Impl(Picture* p) : Paint::Impl(p) + PictureImpl() : impl(Paint::Impl(this)) { } - ~Impl() + ~PictureImpl() { LoaderMgr::retrieve(loader); delete(vector); @@ -76,10 +78,10 @@ struct Picture::Impl : Paint::Impl RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper) { - auto flag = static_cast(pFlag | load()); + auto flag = (pFlag | load()); if (bitmap) { - if (flag == RenderUpdateFlag::None) return rd; + if (flag == RenderUpdateFlag::None) return impl.rd; //Overriding Transformation by the desired image size auto sx = w / loader->w; @@ -87,7 +89,7 @@ struct Picture::Impl : Paint::Impl auto scale = sx < sy ? sx : sy; auto m = transform * Matrix{scale, 0, 0, 0, scale, 0, 0, 0, 1}; - rd = renderer->prepare(bitmap, rd, m, clips, opacity, flag); + impl.rd = renderer->prepare(bitmap, impl.rd, m, clips, opacity, flag); } else if (vector) { if (resizing) { loader->resize(vector, w, h); @@ -96,7 +98,7 @@ struct Picture::Impl : Paint::Impl queryComposition(opacity); return vector->pImpl->update(renderer, transform, clips, opacity, flag, false); } - return rd; + return impl.rd; } void size(float w, float h) @@ -173,7 +175,7 @@ struct Picture::Impl : Paint::Impl if (loader) { dup->loader = loader; ++dup->loader->sharing; - PAINT(picture)->renderFlag |= RenderUpdateFlag::Image; + PAINT(picture)->mark(RenderUpdateFlag::Image); } dup->bitmap = bitmap; @@ -214,7 +216,7 @@ struct Picture::Impl : Paint::Impl } else { vector = loader->paint(); if (vector) { - PAINT(vector)->parent = paint; + PAINT(vector)->parent = this; if (w != loader->w || h != loader->h) { if (!resizing) { w = loader->w; @@ -244,7 +246,7 @@ struct Picture::Impl : Paint::Impl //Composition test const Paint* target; - paint->mask(&target); + PAINT(this)->mask(&target); if (!target || target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return; compFlag = CompositionFlag::Opacity; } @@ -252,9 +254,9 @@ struct Picture::Impl : Paint::Impl bool render(RenderMethod* renderer) { bool ret = false; - renderer->blend(blendMethod); + renderer->blend(impl.blendMethod); - if (bitmap) return renderer->renderImage(rd); + if (bitmap) return renderer->renderImage(impl.rd); else if (vector) { RenderCompositor* cmp = nullptr; if (compFlag) { @@ -269,7 +271,7 @@ struct Picture::Impl : Paint::Impl RenderRegion bounds(RenderMethod* renderer) { - if (rd) return renderer->region(rd); + if (impl.rd) return renderer->region(impl.rd); if (vector) return vector->pImpl->bounds(renderer); return {0, 0, 0, 0}; } diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index 6c76cf50..16e209c2 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -45,6 +45,12 @@ static inline void operator|=(RenderUpdateFlag& a, const RenderUpdateFlag b) a = RenderUpdateFlag(uint16_t(a) | uint16_t(b)); } +static inline RenderUpdateFlag operator|(const RenderUpdateFlag a, const RenderUpdateFlag b) +{ + return RenderUpdateFlag(uint16_t(a) | uint16_t(b)); +} + + struct RenderSurface { union { diff --git a/src/renderer/tvgScene.cpp b/src/renderer/tvgScene.cpp index 1ca7e664..207eb07f 100644 --- a/src/renderer/tvgScene.cpp +++ b/src/renderer/tvgScene.cpp @@ -23,15 +23,12 @@ #include "tvgScene.h" -Scene::Scene() -{ - pImpl = new Impl(this); -} +Scene::Scene() = default; Scene* Scene::gen() noexcept { - return new Scene; + return new SceneImpl; } @@ -56,7 +53,7 @@ Result Scene::remove(Paint* paint) noexcept const list& Scene::paints() const noexcept { - return SCENE(this)->paints; + return CONST_SCENE(this)->paints; } diff --git a/src/renderer/tvgScene.h b/src/renderer/tvgScene.h index 62fe6a85..8f4395b0 100644 --- a/src/renderer/tvgScene.h +++ b/src/renderer/tvgScene.h @@ -28,7 +28,8 @@ #include "tvgMath.h" #include "tvgPaint.h" -#define SCENE(A) PIMPL(A, Scene) +#define SCENE(A) static_cast(A) +#define CONST_SCENE(A) static_cast(A) struct SceneIterator : Iterator { @@ -59,22 +60,22 @@ struct SceneIterator : Iterator } }; -struct Scene::Impl : Paint::Impl +struct SceneImpl : Scene { + Paint::Impl impl; list paints; //children list RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX}; Array* effects = nullptr; uint8_t compFlag = CompositionFlag::Invalid; uint8_t opacity; //for composition - Impl(Scene* s) : Paint::Impl(s) + SceneImpl() : impl(Paint::Impl(this)) { } - ~Impl() + ~SceneImpl() { resetEffects(); - clearPaints(); } @@ -86,8 +87,8 @@ struct Scene::Impl : Paint::Impl //post effects, masking, blending may require composition if (effects) compFlag |= CompositionFlag::PostProcessing; - if (paint->mask(nullptr) != MaskMethod::None) compFlag |= CompositionFlag::Masking; - if (blendMethod != BlendMethod::Normal) compFlag |= CompositionFlag::Blending; + if (PAINT(this)->mask(nullptr) != MaskMethod::None) compFlag |= CompositionFlag::Masking; + if (impl.blendMethod != BlendMethod::Normal) compFlag |= CompositionFlag::Blending; //Half translucent requires intermediate composition. if (opacity == 255) return compFlag; @@ -130,7 +131,7 @@ struct Scene::Impl : Paint::Impl RenderCompositor* cmp = nullptr; auto ret = true; - renderer->blend(blendMethod); + renderer->blend(impl.blendMethod); if (compFlag) { cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(compFlag)); @@ -258,7 +259,7 @@ struct Scene::Impl : Paint::Impl Result remove(Paint* paint) { - if (PAINT(paint)->parent != this->paint) return Result::InsufficientCondition; + if (PAINT(paint)->parent != this) return Result::InsufficientCondition; PAINT(paint)->unref(); paints.remove(paint); return Result::Success; @@ -273,7 +274,7 @@ struct Scene::Impl : Paint::Impl target->ref(); //Relocated the paint to the current scene space - timpl->renderFlag |= RenderUpdateFlag::Transform; + timpl->mark(RenderUpdateFlag::Transform); if (!at) { paints.push_back(target); @@ -283,9 +284,9 @@ struct Scene::Impl : Paint::Impl if (itr == paints.end()) return Result::InvalidArguments; paints.insert(itr, target); } - timpl->parent = paint; - if (timpl->clipper) PAINT(timpl->clipper)->parent = paint; - if (timpl->maskData) PAINT(timpl->maskData->target)->parent = paint; + timpl->parent = this; + if (timpl->clipper) PAINT(timpl->clipper)->parent = this; + if (timpl->maskData) PAINT(timpl->maskData->target)->parent = this; return Result::Success; } @@ -298,7 +299,7 @@ struct Scene::Impl : Paint::Impl { if (effects) { ARRAY_FOREACH(p, *effects) { - renderer->dispose(*p); + impl.renderer->dispose(*p); delete(*p); } delete(effects); diff --git a/src/renderer/tvgShape.cpp b/src/renderer/tvgShape.cpp index e82cd80d..db6baf98 100644 --- a/src/renderer/tvgShape.cpp +++ b/src/renderer/tvgShape.cpp @@ -24,15 +24,12 @@ #include "tvgShape.h" -Shape :: Shape() -{ - pImpl = new Impl(this); -} +Shape :: Shape() = default; Shape* Shape::gen() noexcept { - return new Shape; + return new ShapeImpl; } @@ -51,11 +48,11 @@ Result Shape::reset() noexcept Result Shape::path(const PathCommand** cmds, uint32_t* cmdsCnt, const Point** pts, uint32_t* ptsCnt) const noexcept { - if (cmds) *cmds = SHAPE(this)->rs.path.cmds.data; - if (cmdsCnt) *cmdsCnt = SHAPE(this)->rs.path.cmds.count; + if (cmds) *cmds = CONST_SHAPE(this)->rs.path.cmds.data; + if (cmdsCnt) *cmdsCnt = CONST_SHAPE(this)->rs.path.cmds.count; - if (pts) *pts = SHAPE(this)->rs.path.pts.data; - if (ptsCnt) *ptsCnt = SHAPE(this)->rs.path.pts.count; + if (pts) *pts = CONST_SHAPE(this)->rs.path.pts.data; + if (ptsCnt) *ptsCnt = CONST_SHAPE(this)->rs.path.pts.count; return Result::Success; } @@ -124,14 +121,14 @@ Result Shape::fill(Fill* f) noexcept Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { - SHAPE(this)->rs.fillColor(r, g, b, a); + CONST_SHAPE(this)->rs.fillColor(r, g, b, a); return Result::Success; } const Fill* Shape::fill() const noexcept { - return SHAPE(this)->rs.fill; + return CONST_SHAPE(this)->rs.fill; } @@ -151,7 +148,7 @@ Result Shape::strokeWidth(float width) noexcept float Shape::strokeWidth() const noexcept { - return SHAPE(this)->rs.strokeWidth(); + return CONST_SHAPE(this)->rs.strokeWidth(); } @@ -164,7 +161,7 @@ Result Shape::strokeFill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept Result Shape::strokeFill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { - if (!SHAPE(this)->rs.strokeFill(r, g, b, a)) return Result::InsufficientCondition; + if (!CONST_SHAPE(this)->rs.strokeFill(r, g, b, a)) return Result::InsufficientCondition; return Result::Success; } @@ -177,7 +174,7 @@ Result Shape::strokeFill(Fill* f) noexcept const Fill* Shape::strokeFill() const noexcept { - return SHAPE(this)->rs.strokeFill(); + return CONST_SHAPE(this)->rs.strokeFill(); } @@ -189,7 +186,7 @@ Result Shape::strokeDash(const float* dashPattern, uint32_t cnt, float offset) n uint32_t Shape::strokeDash(const float** dashPattern, float* offset) const noexcept { - return SHAPE(this)->rs.strokeDash(dashPattern, offset); + return CONST_SHAPE(this)->rs.strokeDash(dashPattern, offset); } @@ -215,19 +212,19 @@ Result Shape::strokeMiterlimit(float miterlimit) noexcept StrokeCap Shape::strokeCap() const noexcept { - return SHAPE(this)->rs.strokeCap(); + return CONST_SHAPE(this)->rs.strokeCap(); } StrokeJoin Shape::strokeJoin() const noexcept { - return SHAPE(this)->rs.strokeJoin(); + return CONST_SHAPE(this)->rs.strokeJoin(); } float Shape::strokeMiterlimit() const noexcept { - return SHAPE(this)->rs.strokeMiterlimit(); + return CONST_SHAPE(this)->rs.strokeMiterlimit(); } @@ -247,5 +244,5 @@ Result Shape::fill(FillRule r) noexcept FillRule Shape::fillRule() const noexcept { - return SHAPE(this)->rs.rule; + return CONST_SHAPE(this)->rs.rule; } diff --git a/src/renderer/tvgShape.h b/src/renderer/tvgShape.h index d99b5d7b..c0950724 100644 --- a/src/renderer/tvgShape.h +++ b/src/renderer/tvgShape.h @@ -27,32 +27,34 @@ #include "tvgMath.h" #include "tvgPaint.h" -#define SHAPE(A) PIMPL(A, Shape) +#define SHAPE(A) static_cast(A) +#define CONST_SHAPE(A) static_cast(A) -struct Shape::Impl : Paint::Impl +struct ShapeImpl : Shape { + Paint::Impl impl; RenderShape rs; uint8_t compFlag = CompositionFlag::Invalid; uint8_t opacity; //for composition - Impl(Shape* s) : Paint::Impl(s) + ShapeImpl() : impl(Paint::Impl(this)) { } bool render(RenderMethod* renderer) { - if (!rd) return false; + if (!impl.rd) return false; RenderCompositor* cmp = nullptr; - renderer->blend(blendMethod); + renderer->blend(impl.blendMethod); if (compFlag) { cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast(compFlag)); renderer->beginComposite(cmp, MaskMethod::None, opacity); } - auto ret = renderer->renderShape(rd); + auto ret = renderer->renderShape(impl.rd); if (cmp) renderer->endComposite(cmp); return ret; } @@ -75,10 +77,10 @@ struct Shape::Impl : Paint::Impl //Composition test const Paint* target; - auto method = paint->mask(&target); + auto method = PAINT(this)->mask(&target); if (!target) return false; - if ((target->pImpl->opacity == 255 || target->pImpl->opacity == 0) && target->type() == Type::Shape) { + if ((target->pImpl->opacity == 255 || target->pImpl->opacity == 0) && target->type() == tvg::Type::Shape) { auto shape = static_cast(target); if (!shape->fill()) { uint8_t r, g, b, a; @@ -97,7 +99,7 @@ struct Shape::Impl : Paint::Impl RenderData update(RenderMethod* renderer, const Matrix& transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) { - if (static_cast(pFlag | renderFlag) == RenderUpdateFlag::None) return rd; + if ((pFlag | impl.renderFlag) == RenderUpdateFlag::None) return impl.rd; if (needComposition(opacity)) { /* Overriding opacity value. If this scene is half-translucent, @@ -106,14 +108,14 @@ struct Shape::Impl : Paint::Impl opacity = 255; } - rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast(pFlag | renderFlag), clipper); - return rd; + impl.rd = renderer->prepare(rs, impl.rd, transform, clips, opacity, (pFlag | impl.renderFlag), clipper); + return impl.rd; } RenderRegion bounds(RenderMethod* renderer) { - if (!rd) return {0, 0, 0, 0}; - return renderer->region(rd); + if (!impl.rd) return {0, 0, 0, 0}; + return renderer->region(impl.rd); } Result bounds(Point* pt4, Matrix& m, bool obb, bool stroking) @@ -178,7 +180,7 @@ struct Shape::Impl : Paint::Impl { rs.path.cmds.push(PathCommand::LineTo); rs.path.pts.push({x, y}); - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); } void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) @@ -188,7 +190,7 @@ struct Shape::Impl : Paint::Impl rs.path.pts.push({cx2, cy2}); rs.path.pts.push({x, y}); - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); } void close() @@ -196,14 +198,14 @@ struct Shape::Impl : Paint::Impl //Don't close multiple times. if (rs.path.cmds.count > 0 && rs.path.cmds.last() == PathCommand::Close) return; rs.path.cmds.push(PathCommand::Close); - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); } void strokeWidth(float width) { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->width = width; - renderFlag |= RenderUpdateFlag::Stroke; + impl.mark(RenderUpdateFlag::Stroke); } void trimpath(const RenderTrimPath& trim) @@ -216,7 +218,7 @@ struct Shape::Impl : Paint::Impl if (tvg::equal(rs.stroke->trim.begin, trim.begin) && tvg::equal(rs.stroke->trim.end, trim.end) && rs.stroke->trim.simultaneous == trim.simultaneous) return; rs.stroke->trim = trim; - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); } bool trimpath(float* begin, float* end) @@ -236,14 +238,14 @@ struct Shape::Impl : Paint::Impl { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->cap = cap; - renderFlag |= RenderUpdateFlag::Stroke; + impl.mark(RenderUpdateFlag::Stroke); } void strokeJoin(StrokeJoin join) { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->join = join; - renderFlag |= RenderUpdateFlag::Stroke; + impl.mark(RenderUpdateFlag::Stroke); } Result strokeMiterlimit(float miterlimit) @@ -253,7 +255,7 @@ struct Shape::Impl : Paint::Impl if (miterlimit < 0.0f) return Result::InvalidArguments; if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->miterlimit = miterlimit; - renderFlag |= RenderUpdateFlag::Stroke; + impl.mark(RenderUpdateFlag::Stroke); return Result::Success; } @@ -264,12 +266,12 @@ struct Shape::Impl : Paint::Impl if (rs.stroke->fill) { delete(rs.stroke->fill); rs.stroke->fill = nullptr; - renderFlag |= RenderUpdateFlag::GradientStroke; + impl.mark(RenderUpdateFlag::GradientStroke); } rs.stroke->color = {r, g, b, a}; - renderFlag |= RenderUpdateFlag::Stroke; + impl.mark(RenderUpdateFlag::Stroke); } Result strokeFill(Fill* f) @@ -281,8 +283,7 @@ struct Shape::Impl : Paint::Impl rs.stroke->fill = f; rs.stroke->color.a = 0; - renderFlag |= RenderUpdateFlag::Stroke; - renderFlag |= RenderUpdateFlag::GradientStroke; + impl.mark(RenderUpdateFlag::Stroke | RenderUpdateFlag::GradientStroke); return Result::Success; } @@ -311,7 +312,7 @@ struct Shape::Impl : Paint::Impl } rs.stroke->dash.count = cnt; rs.stroke->dash.offset = offset; - renderFlag |= RenderUpdateFlag::Stroke; + impl.mark(RenderUpdateFlag::Stroke); return Result::Success; } @@ -326,7 +327,7 @@ struct Shape::Impl : Paint::Impl { if (!rs.stroke) rs.stroke = new RenderStroke(); rs.stroke->strokeFirst = strokeFirst; - renderFlag |= RenderUpdateFlag::Stroke; + impl.mark(RenderUpdateFlag::Stroke); } Result fill(Fill* f) @@ -335,7 +336,7 @@ struct Shape::Impl : Paint::Impl if (rs.fill && rs.fill != f) delete(rs.fill); rs.fill = f; - renderFlag |= RenderUpdateFlag::Gradient; + impl.mark(RenderUpdateFlag::Gradient); return Result::Success; } @@ -345,20 +346,20 @@ struct Shape::Impl : Paint::Impl if (rs.fill) { delete(rs.fill); rs.fill = nullptr; - renderFlag |= RenderUpdateFlag::Gradient; + impl.mark(RenderUpdateFlag::Gradient); } if (r == rs.color.r && g == rs.color.g && b == rs.color.b && a == rs.color.a) return; rs.color = {r, g, b, a}; - renderFlag |= RenderUpdateFlag::Color; + impl.mark(RenderUpdateFlag::Color); } void resetPath() { rs.path.cmds.clear(); rs.path.pts.clear(); - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); } Result appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) @@ -367,7 +368,7 @@ struct Shape::Impl : Paint::Impl grow(cmdCnt, ptsCnt); append(cmds, cmdCnt, pts, ptsCnt); - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); return Result::Success; } @@ -403,7 +404,7 @@ struct Shape::Impl : Paint::Impl rs.path.pts.count += 13; - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); } void appendRect(float x, float y, float w, float h, float rx, float ry, bool cw) @@ -478,7 +479,7 @@ struct Shape::Impl : Paint::Impl rs.path.cmds.count += 10; rs.path.pts.count += 17; } - renderFlag |= RenderUpdateFlag::Path; + impl.mark(RenderUpdateFlag::Path); } Paint* duplicate(Paint* ret) @@ -491,7 +492,7 @@ struct Shape::Impl : Paint::Impl delete(dup->rs.fill); //Default Properties - dup->renderFlag = RenderUpdateFlag::All; + dup->impl.mark(RenderUpdateFlag::All); dup->rs.rule = rs.rule; dup->rs.color = rs.color; @@ -517,7 +518,7 @@ struct Shape::Impl : Paint::Impl void reset() { - PAINT(paint)->reset(); + PAINT(this)->reset(); rs.path.cmds.clear(); rs.path.pts.clear(); diff --git a/src/renderer/tvgText.cpp b/src/renderer/tvgText.cpp index 35336747..9389e4d3 100644 --- a/src/renderer/tvgText.cpp +++ b/src/renderer/tvgText.cpp @@ -24,10 +24,7 @@ #include "tvgText.h" -Text::Text() -{ - pImpl = new Impl(this); -} +Text::Text() = default; Result Text::text(const char* text) noexcept @@ -102,7 +99,7 @@ Result Text::fill(Fill* f) noexcept Text* Text::gen() noexcept { - return new Text; + return new TextImpl; } diff --git a/src/renderer/tvgText.h b/src/renderer/tvgText.h index 32b58077..edc95e1d 100644 --- a/src/renderer/tvgText.h +++ b/src/renderer/tvgText.h @@ -29,10 +29,12 @@ #include "tvgFill.h" #include "tvgLoader.h" -#define TEXT(A) PIMPL(A, Text) +#define TEXT(A) static_cast(A) +#define CONST_TEXT(A) static_cast(A) -struct Text::Impl : Paint::Impl +struct TextImpl : Text { + Paint::Impl impl; Shape* shape; //text shape FontLoader* loader = nullptr; FontMetrics metrics; @@ -41,13 +43,13 @@ struct Text::Impl : Paint::Impl bool italic = false; bool changed = false; - Impl(Text* p) : Paint::Impl(p), shape(Shape::gen()) + TextImpl() : impl(Paint::Impl(this)), shape(Shape::gen()) { - PAINT(shape)->parent = p; + PAINT(shape)->parent = this; shape->fill(FillRule::EvenOdd); } - ~Impl() + ~TextImpl() { tvg::free(utf8); LoaderMgr::retrieve(loader); @@ -95,7 +97,7 @@ struct Text::Impl : Paint::Impl bool render(RenderMethod* renderer) { if (!loader) return true; - renderer->blend(blendMethod); + renderer->blend(impl.blendMethod); return PAINT(shape)->render(renderer); } @@ -118,7 +120,7 @@ struct Text::Impl : Paint::Impl //transform the gradient coordinates based on the final scaled font. auto fill = SHAPE(shape)->rs.fill; - if (fill && SHAPE(shape)->renderFlag & RenderUpdateFlag::Gradient) { + if (fill && SHAPE(shape)->impl.renderFlag & RenderUpdateFlag::Gradient) { if (fill->type() == Type::LinearGradient) { LINEAR(fill)->x1 *= scale; LINEAR(fill)->y1 *= scale; @@ -172,6 +174,4 @@ struct Text::Impl : Paint::Impl } }; - - #endif //_TVG_TEXT_H