From 0de3872be33793d2c8db03d5b85da38670410626 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 27 Dec 2022 16:21:42 +0100 Subject: [PATCH] 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 --- inc/thorvg.h | 14 ++++++++++++++ src/lib/sw_engine/tvgSwRenderer.cpp | 8 +++++--- src/lib/tvgPaint.cpp | 13 +++++++++++++ src/lib/tvgPaint.h | 2 ++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 594fe9b1..45eeb5bb 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -363,6 +363,20 @@ 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. * diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 6e7b738f..a303d2d3 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -77,7 +77,9 @@ struct SwShapeTask : SwTask void run(unsigned tid) override { - if (opacity == 0) 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; @@ -99,7 +101,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) { + if (visibleFill || visibleStroke || usedAsClip) { shapeReset(&shape); if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; } @@ -111,7 +113,7 @@ struct SwShapeTask : SwTask //Fill if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { - if (visibleFill) { + 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. diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index 05b7078c..ba5b0500 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -385,6 +385,19 @@ 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 c54b97a3..a0bd3c96 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -63,6 +63,7 @@ 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; @@ -137,6 +138,7 @@ 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;