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
This commit is contained in:
Hermet Park 2023-05-16 17:22:14 +09:00 committed by Hermet Park
parent c7d77b3517
commit d8687314a6
4 changed files with 37 additions and 6 deletions

View file

@ -37,7 +37,9 @@ void tvgDrawCmds(tvg::Canvas* canvas)
auto mask = tvg::Shape::gen();
mask->appendCircle(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2);
mask->fill(255, 255, 255, 100);
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");

View file

@ -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<Picture::Impl>(pImpl));

View file

@ -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<RenderData>& 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<RenderUpdateFlag>(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)

View file

@ -59,10 +59,10 @@ struct SceneIterator : Iterator
struct Scene::Impl
{
Array<Paint*> 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)
{