From d8687314a61dd7a11733984926861214a8d41974 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 16 May 2023 17:22:14 +0900 Subject: [PATCH] common picture: fix a composition bug. Previously, a picture with a half-translucent mask would not function correctly. This fix addresses the bug by applying the expected composition step. Note: Even after applying this patch, a half-translucent mask with shape fill alpha will still not work properly. We should consider removing the fill alpha property, as it duplicates the Paint opacity. @Issue: https://github.com/thorvg/thorvg/issues/1423 --- src/examples/Performance.cpp | 6 ++++-- src/lib/tvgPicture.cpp | 2 +- src/lib/tvgPictureImpl.h | 33 +++++++++++++++++++++++++++++++-- src/lib/tvgSceneImpl.h | 2 +- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/examples/Performance.cpp b/src/examples/Performance.cpp index 3316c940..1f6b9d0a 100644 --- a/src/examples/Performance.cpp +++ b/src/examples/Performance.cpp @@ -36,8 +36,10 @@ void tvgDrawCmds(tvg::Canvas* canvas) if (!canvas) return; auto mask = tvg::Shape::gen(); - mask->appendCircle(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2); - mask->fill(255, 255, 255, 100); + mask->appendCircle(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2); + mask->fill(255, 255, 255, 255); + //Use the opacity for a half-translucent mask. + mask->opacity(125); auto picture = tvg::Picture::gen(); picture->load(EXAMPLE_DIR"/tiger.svg"); diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index ad89a3a9..95ae14b8 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -26,7 +26,7 @@ /* External Class Implementation */ /************************************************************************/ -Picture::Picture() : pImpl(new Impl) +Picture::Picture() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_PICTURE; Paint::pImpl->method(new PaintMethod(pImpl)); diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 6af7a732..1caf3a4c 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -67,7 +67,13 @@ struct Picture::Impl RenderData rd = nullptr; //engine data float w = 0, h = 0; RenderMesh rm; //mesh data + Picture* picture = nullptr; bool resizing = false; + bool needComp = false; //need composition + + Impl(Picture* p) : picture(p) + { + } ~Impl() { @@ -127,6 +133,19 @@ struct Picture::Impl else return RenderTransform(pTransform, &tmp); } + bool needComposition(uint32_t opacity) + { + //In this case, paint(scene) would try composition itself. + if (opacity < 255) return false; + + //Composition test + const Paint* target; + auto method = picture->composite(&target); + if (!target || method == tvg::CompositeMethod::ClipPath) return false; + if (target->pImpl->opacity < 255 && target->pImpl->opacity > 0) return true; + return false; + } + RenderData update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag, bool clipper) { auto flag = load(); @@ -139,6 +158,7 @@ struct Picture::Impl loader->resize(paint, w, h); resizing = false; } + needComp = needComposition(opacity) ? true : false; rd = paint->pImpl->update(renderer, pTransform, opacity, clips, static_cast(pFlag | flag), clipper); } return rd; @@ -146,9 +166,18 @@ struct Picture::Impl bool render(RenderMethod &renderer) { + bool ret = false; if (surface) return renderer.renderImage(rd); - else if (paint) return paint->pImpl->render(renderer); - return false; + else if (paint) { + Compositor* cmp = nullptr; + if (needComp) { + cmp = renderer.target(bounds(renderer), renderer.colorSpace()); + renderer.beginComposite(cmp, CompositeMethod::None, 255); + } + ret = paint->pImpl->render(renderer); + if (cmp) renderer.endComposite(cmp); + } + return ret; } bool viewbox(float* x, float* y, float* w, float* h) diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index d0a0530f..3f594539 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -59,10 +59,10 @@ struct SceneIterator : Iterator struct Scene::Impl { Array paints; - uint8_t opacity; //for composition RenderMethod* renderer = nullptr; //keep it for explicit clear RenderData rd = nullptr; Scene* scene = nullptr; + uint8_t opacity; //for composition Impl(Scene* s) : scene(s) {