From 1b37743b2ceca1948a6b1df3cc702b9fb313812e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 16 Apr 2025 12:43:55 +0900 Subject: [PATCH] renderer: fixed a clippging update isssue ThorVG did not consider updates to the clipping path when a paint object was modified after being added to the scene. This fix ensures that any updates to clipping are correctly reflected during rendering. issue: https://github.com/thorvg/thorvg/issues/3403 --- src/renderer/sw_engine/tvgSwRenderer.cpp | 49 +++++++++--------------- src/renderer/tvgPaint.cpp | 15 +++++--- src/renderer/tvgPaint.h | 2 +- src/renderer/tvgRender.h | 7 +++- src/renderer/tvgShape.h | 2 +- 5 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/renderer/sw_engine/tvgSwRenderer.cpp b/src/renderer/sw_engine/tvgSwRenderer.cpp index c70fdcfa..60831cc1 100644 --- a/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -118,53 +118,40 @@ struct SwShapeTask : SwTask auto strokeWidth = validStrokeWidth(); SwBBox renderRegion{}; - auto visibleFill = false; - - //This checks also for the case, if the invisible shape turned to visible by alpha. - auto prepareShape = !shapePrepared(&shape) && flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient); + auto updateShape = (RenderUpdateFlag::Path | RenderUpdateFlag::Transform | RenderUpdateFlag::Clip); + auto updateFill = false; //Shape - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform) || prepareShape) { + if (updateShape || flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient)) { uint8_t alpha = 0; rshape->fillColor(nullptr, nullptr, nullptr, &alpha); - alpha = MULTIPLY(alpha, opacity); - visibleFill = (alpha > 0 || rshape->fill); - shapeReset(&shape); - if (visibleFill || clipper) { - if (!shapePrepare(&shape, rshape, transform, bbox, renderRegion, mpool, tid, clips.count > 0 ? true : false)) { - visibleFill = false; + updateFill = (MULTIPLY(alpha, opacity) || rshape->fill); + if (updateShape) shapeReset(&shape); + if (updateFill || clipper) { + if (shapePrepare(&shape, rshape, transform, bbox, renderRegion, mpool, tid, clips.count > 0 ? true : false)) { + if (!shapeGenRle(&shape, rshape, antialiasing(strokeWidth))) goto err; + } else { + updateFill = false; renderRegion.reset(); } } } //Fill - if (flags & (RenderUpdateFlag::Path |RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { - if (visibleFill || clipper) { - if (!shapeGenRle(&shape, rshape, antialiasing(strokeWidth))) goto err; - } + if (updateFill) { if (auto fill = rshape->fill) { auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; if (ctable) shapeResetFill(&shape); if (!shapeGenFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err; - } else { - shapeDelFill(&shape); } } //Stroke - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - if (strokeWidth > 0.0f) { - shapeResetStroke(&shape, rshape, transform); - - if (!shapeGenStrokeRle(&shape, rshape, transform, bbox, renderRegion, mpool, tid)) goto err; - if (auto fill = rshape->strokeFill()) { - auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false; - if (ctable) shapeResetStrokeFill(&shape); - if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err; - } else { - shapeDelStrokeFill(&shape); - } - } else { - shapeDelStroke(&shape); + if ((updateShape || flags & RenderUpdateFlag::Stroke) && (strokeWidth > 0.0f)) { + shapeResetStroke(&shape, rshape, transform); + if (!shapeGenStrokeRle(&shape, rshape, transform, bbox, renderRegion, mpool, tid)) goto err; + if (auto fill = rshape->strokeFill()) { + auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false; + if (ctable) shapeResetStrokeFill(&shape); + if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err; } } diff --git a/src/renderer/tvgPaint.cpp b/src/renderer/tvgPaint.cpp index 93a28853..3a0b4de2 100644 --- a/src/renderer/tvgPaint.cpp +++ b/src/renderer/tvgPaint.cpp @@ -276,16 +276,19 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Arrayclipper) { - P(this->clipper)->ctxFlag &= ~ContextFlag::FastTrack; //reset + auto pclip = P(this->clipper); + if (pclip->renderFlag | static_cast(this->clipper)->pImpl->rFlag) renderFlag |= RenderUpdateFlag::Clip; + pclip->ctxFlag &= ~ContextFlag::FastTrack; //reset viewport = renderer->viewport(); /* TODO: Intersect the clipper's clipper, if both are FastTrack. Update the subsequent clipper first and check its ctxFlag. */ - if (!P(this->clipper)->clipper && (compFastTrack = _compFastTrack(renderer, this->clipper, pm, viewport)) == Result::Success) { - P(this->clipper)->ctxFlag |= ContextFlag::FastTrack; - } - if (compFastTrack == Result::InsufficientCondition) { - trd = P(this->clipper)->update(renderer, pm, clips, 255, pFlag, true); + if (!pclip->clipper && _compFastTrack(renderer, this->clipper, pm, viewport) == Result::Success) { + pclip->ctxFlag |= ContextFlag::FastTrack; + compFastTrack = Result::Success; + } else { + trd = pclip->update(renderer, pm, clips, 255, pFlag, true); clips.push(trd); + compFastTrack = Result::InsufficientCondition; } } diff --git a/src/renderer/tvgPaint.h b/src/renderer/tvgPaint.h index bf805297..603fd151 100644 --- a/src/renderer/tvgPaint.h +++ b/src/renderer/tvgPaint.h @@ -72,8 +72,8 @@ namespace tvg tvg::rotate(&m, degree); } } tr; + RenderUpdateFlag renderFlag = RenderUpdateFlag::None; BlendMethod blendMethod; - uint8_t renderFlag; uint8_t ctxFlag; uint8_t opacity; uint8_t refCnt = 0; //reference count diff --git a/src/renderer/tvgRender.h b/src/renderer/tvgRender.h index ce4a1bc9..4e48eed5 100644 --- a/src/renderer/tvgRender.h +++ b/src/renderer/tvgRender.h @@ -37,9 +37,14 @@ using pixel_t = uint32_t; #define DASH_PATTERN_THRESHOLD 0.001f -enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255}; +enum RenderUpdateFlag : uint16_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, Clip = 256, All = 0xffff}; enum CompositionFlag : uint8_t {Invalid = 0, Opacity = 1, Blending = 2, Masking = 4, PostProcessing = 8}; //Composition Purpose +static inline void operator|=(RenderUpdateFlag& a, const RenderUpdateFlag b) +{ + a = RenderUpdateFlag(uint16_t(a) | uint16_t(b)); +} + //TODO: Move this in public header unifying with SwCanvas::Colorspace enum ColorSpace : uint8_t { diff --git a/src/renderer/tvgShape.h b/src/renderer/tvgShape.h index a19b8d6c..d1932764 100644 --- a/src/renderer/tvgShape.h +++ b/src/renderer/tvgShape.h @@ -33,7 +33,7 @@ struct Shape::Impl RenderShape rs; //shape data RenderData rd = nullptr; //engine data Shape* shape; - uint8_t rFlag = RenderUpdateFlag::None; + RenderUpdateFlag rFlag = RenderUpdateFlag::None; uint8_t cFlag = CompositionFlag::Invalid; uint8_t opacity; //for composition