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 //Fill
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
if (visibleFill || clipper) { if (visibleFill || clipper) {
@ -143,7 +139,7 @@ struct SwShapeTask : SwTask
if (auto fill = rshape->fill) { if (auto fill = rshape->fill) {
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
if (ctable) shapeResetFill(&shape); 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 { } else {
shapeDelFill(&shape); shapeDelFill(&shape);
} }
@ -158,7 +154,7 @@ struct SwShapeTask : SwTask
if (auto fill = rshape->strokeFill()) { if (auto fill = rshape->strokeFill()) {
auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false; auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false;
if (ctable) shapeResetStrokeFill(&shape); 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 { } else {
shapeDelStrokeFill(&shape); shapeDelStrokeFill(&shape);
} }
@ -490,30 +486,15 @@ bool SwRenderer::renderShape(RenderData data)
if (task->opacity == 0) return true; 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 //Main raster stage
if (task->rshape->stroke && task->rshape->stroke->strokeFirst) { if (task->rshape->stroke && task->rshape->stroke->strokeFirst) {
_renderStroke(task, surface, opacity); _renderStroke(task, surface, task->opacity);
_renderFill(task, surface, opacity); _renderFill(task, surface, task->opacity);
} else { } else {
_renderFill(task, surface, opacity); _renderFill(task, surface, task->opacity);
_renderStroke(task, surface, opacity); _renderStroke(task, surface, task->opacity);
} }
if (task->cmpStroking) endComposite(cmp);
return true; return true;
} }

View file

@ -63,6 +63,7 @@ struct Scene::Impl
RenderData rd = nullptr; RenderData rd = nullptr;
Scene* scene = nullptr; Scene* scene = nullptr;
uint8_t opacity; //for composition uint8_t opacity; //for composition
bool needComp; //composite or not
Impl(Scene* s) : scene(s) 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) 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, if ((needComp = needComposition(opacity))) {
It must do intermeidate composition with that opacity value. */ /* Overriding opacity value. If this scene is half-translucent,
this->opacity = static_cast<uint8_t>(opacity); It must do intermeidate composition with that opacity value. */
if (needComposition(opacity)) opacity = 255; this->opacity = static_cast<uint8_t>(opacity);
opacity = 255;
}
this->renderer = &renderer; this->renderer = &renderer;
@ -136,7 +139,7 @@ struct Scene::Impl
{ {
Compositor* cmp = nullptr; Compositor* cmp = nullptr;
if (needComposition(opacity)) { if (needComp) {
cmp = renderer.target(bounds(renderer), renderer.colorSpace()); cmp = renderer.target(bounds(renderer), renderer.colorSpace());
renderer.beginComposite(cmp, CompositeMethod::None, opacity); renderer.beginComposite(cmp, CompositeMethod::None, opacity);
} }

View file

@ -36,7 +36,8 @@ struct Shape::Impl
RenderData rd = nullptr; //engine data RenderData rd = nullptr; //engine data
uint32_t flag = RenderUpdateFlag::None; uint32_t flag = RenderUpdateFlag::None;
Shape* shape; Shape* shape;
bool needComp; //for composition uint8_t opacity; //for composition
bool needComp; //composite or not
Impl(Shape* s) : shape(s) Impl(Shape* s) : shape(s)
{ {
@ -56,7 +57,7 @@ struct Shape::Impl
if (needComp) { if (needComp) {
cmp = renderer.target(bounds(renderer), renderer.colorSpace()); cmp = renderer.target(bounds(renderer), renderer.colorSpace());
renderer.beginComposite(cmp, CompositeMethod::None, 255); renderer.beginComposite(cmp, CompositeMethod::None, opacity);
} }
ret = renderer.renderShape(rd); ret = renderer.renderShape(rd);
if (cmp) renderer.endComposite(cmp); if (cmp) renderer.endComposite(cmp);
@ -65,12 +66,14 @@ struct Shape::Impl
bool needComposition(uint32_t opacity) bool needComposition(uint32_t opacity)
{ {
//In this case, paint(shape) would try composition by backends. (See: SwShapeTask::run()) if (opacity == 0) return false;
//TODO: that composition should be moved here?
if (opacity < 255) 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.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 //Composition test
const Paint* target; 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) 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); rd = renderer.prepare(rs, rd, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag), clipper);
flag = RenderUpdateFlag::None; flag = RenderUpdateFlag::None;