common sw_engine: gather scattered stroking composition.

There are two branches for completing stroke composition between the canvas and sw_engine.

It is necessary to centralize the task on the canvas engine side so that
we can maintain the logic without confusion.
This commit is contained in:
Hermet Park 2023-05-17 17:24:10 +09:00
parent 3626ded041
commit 89db13037d
3 changed files with 30 additions and 38 deletions

View file

@ -125,10 +125,6 @@ struct SwShapeTask : SwTask
}
}
//Decide Stroking Composition
if (visibleStroke && visibleFill && opacity < 255) cmpStroking = true;
else cmpStroking = false;
//Fill
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
if (visibleFill || clipper) {
@ -143,7 +139,7 @@ struct SwShapeTask : SwTask
if (auto fill = rshape->fill) {
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
if (ctable) shapeResetFill(&shape);
if (!shapeGenFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
if (!shapeGenFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err;
} else {
shapeDelFill(&shape);
}
@ -158,7 +154,7 @@ struct SwShapeTask : SwTask
if (auto fill = rshape->strokeFill()) {
auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false;
if (ctable) shapeResetStrokeFill(&shape);
if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, cmpStroking ? 255 : opacity, ctable)) goto err;
if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err;
} else {
shapeDelStrokeFill(&shape);
}
@ -490,30 +486,15 @@ bool SwRenderer::renderShape(RenderData data)
if (task->opacity == 0) return true;
uint32_t opacity;
Compositor* cmp = nullptr;
//Do Stroking Composition
if (task->cmpStroking) {
opacity = 255;
cmp = target(task->bounds(), colorSpace());
beginComposite(cmp, CompositeMethod::None, task->opacity);
//No Stroking Composition
} else {
opacity = task->opacity;
}
//Main raster stage
if (task->rshape->stroke && task->rshape->stroke->strokeFirst) {
_renderStroke(task, surface, opacity);
_renderFill(task, surface, opacity);
_renderStroke(task, surface, task->opacity);
_renderFill(task, surface, task->opacity);
} else {
_renderFill(task, surface, opacity);
_renderStroke(task, surface, opacity);
_renderFill(task, surface, task->opacity);
_renderStroke(task, surface, task->opacity);
}
if (task->cmpStroking) endComposite(cmp);
return true;
}

View file

@ -63,6 +63,7 @@ struct Scene::Impl
RenderData rd = nullptr;
Scene* scene = nullptr;
uint8_t opacity; //for composition
bool needComp; //composite or not
Impl(Scene* s) : scene(s)
{
@ -109,10 +110,12 @@ struct Scene::Impl
RenderData update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag, bool clipper)
{
/* Overriding opacity value. If this scene is half-translucent,
It must do intermeidate composition with that opacity value. */
this->opacity = static_cast<uint8_t>(opacity);
if (needComposition(opacity)) opacity = 255;
if ((needComp = needComposition(opacity))) {
/* Overriding opacity value. If this scene is half-translucent,
It must do intermeidate composition with that opacity value. */
this->opacity = static_cast<uint8_t>(opacity);
opacity = 255;
}
this->renderer = &renderer;
@ -136,7 +139,7 @@ struct Scene::Impl
{
Compositor* cmp = nullptr;
if (needComposition(opacity)) {
if (needComp) {
cmp = renderer.target(bounds(renderer), renderer.colorSpace());
renderer.beginComposite(cmp, CompositeMethod::None, opacity);
}

View file

@ -36,7 +36,8 @@ struct Shape::Impl
RenderData rd = nullptr; //engine data
uint32_t flag = RenderUpdateFlag::None;
Shape* shape;
bool needComp; //for composition
uint8_t opacity; //for composition
bool needComp; //composite or not
Impl(Shape* s) : shape(s)
{
@ -56,7 +57,7 @@ struct Shape::Impl
if (needComp) {
cmp = renderer.target(bounds(renderer), renderer.colorSpace());
renderer.beginComposite(cmp, CompositeMethod::None, 255);
renderer.beginComposite(cmp, CompositeMethod::None, opacity);
}
ret = renderer.renderShape(rd);
if (cmp) renderer.endComposite(cmp);
@ -65,12 +66,14 @@ struct Shape::Impl
bool needComposition(uint32_t opacity)
{
//In this case, paint(shape) would try composition by backends. (See: SwShapeTask::run())
//TODO: that composition should be moved here?
if (opacity < 255) return false;
if (opacity == 0) return false;
//Shape composition is only necessary when stroking is valid.
//Shape composition is only necessary when stroking & fill are valid.
if (!rs.stroke || rs.stroke->width < FLT_EPSILON || rs.stroke->color[3] == 0) return false;
if (!rs.fill && rs.color[3] == 0) return false;
//translucent fill & stroke
if (opacity < 255) return true;
//Composition test
const Paint* target;
@ -82,8 +85,13 @@ struct Shape::Impl
}
RenderData update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag, bool clipper)
{
needComp = needComposition(opacity);
{
if ((needComp = needComposition(opacity))) {
/* Overriding opacity value. If this scene is half-translucent,
It must do intermeidate composition with that opacity value. */
this->opacity = static_cast<uint8_t>(opacity);
opacity = 255;
}
rd = renderer.prepare(rs, rd, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
flag = RenderUpdateFlag::None;