common: refactoring the dash pattern

introdced the length to avoid duplicate among engines
This commit is contained in:
Hermet Park 2025-02-14 01:58:15 +01:00
parent 02a28bf9c3
commit f1e9ce0460
8 changed files with 90 additions and 109 deletions

View file

@ -1507,12 +1507,9 @@ void Stroker::stroke(const RenderShape *rshape, const RenderPath& path)
mStrokeWidth = strokeWidth / mMatrix.e11;
}
const float *patterns = nullptr;
auto offset = 0.0f;
auto patternCnt = rshape->strokeDash(&patterns, &offset);
if (patternCnt == 0) doStroke(path);
else doDashStroke(path, patterns, patternCnt, offset);
auto& dash = rshape->stroke->dash;
if (dash.count == 0) doStroke(path);
else doDashStroke(path, dash.pattern, dash.count, dash.offset, dash.length);
}
@ -1572,14 +1569,14 @@ void Stroker::doStroke(const RenderPath& path)
}
void Stroker::doDashStroke(const RenderPath& path, const float *patterns, uint32_t patternCnt, float offset)
void Stroker::doDashStroke(const RenderPath& path, const float *patterns, uint32_t patternCnt, float offset, float length)
{
RenderPath dpath;
dpath.cmds.reserve(20 * path.cmds.count);
dpath.pts.reserve(20 * path.pts.count);
DashStroke dash(&dpath.cmds, &dpath.pts, patterns, patternCnt, offset);
DashStroke dash(&dpath.cmds, &dpath.pts, patterns, patternCnt, offset, length);
dash.doStroke(path);
doStroke(dpath);
}
@ -1915,18 +1912,13 @@ void Stroker::strokeRound(const Point& p, const Point& outDir)
}
DashStroke::DashStroke(Array<PathCommand> *cmds, Array<Point> *pts, const float *patterns, uint32_t patternCnt, float offset)
DashStroke::DashStroke(Array<PathCommand> *cmds, Array<Point> *pts, const float *patterns, uint32_t patternCnt, float offset, float length)
: mCmds(cmds),
mPts(pts),
mDashPattern(patterns),
mDashCount(patternCnt),
mDashOffset(offset),
mCurrLen(),
mCurrIdx(),
mCurOpGap(false),
mMove(true),
mPtStart(),
mPtCur()
mDashLength(length)
{
}
@ -1937,12 +1929,9 @@ void DashStroke::doStroke(const RenderPath& path)
auto offset = mDashOffset;
bool gap = false;
if (!tvg::zero(mDashOffset)) {
auto len = 0.0f;
for (uint32_t i = 0; i < mDashCount; ++i) len += mDashPattern[i];
if (mDashCount % 2) len *= 2;
offset = fmodf(offset, len);
if (offset < 0) offset += len;
auto length = (mDashCount % 2) ? mDashLength * 2 : mDashLength;
offset = fmodf(offset, length);
if (offset < 0) offset += length;
for (uint32_t i = 0; i < mDashCount * (mDashCount % 2 + 1); ++i, ++idx) {
auto curPattern = mDashPattern[i % mDashCount];

View file

@ -85,7 +85,7 @@ public:
private:
void doStroke(const RenderPath& path);
void doDashStroke(const RenderPath& path, const float* patterns, uint32_t patternCnt, float offset);
void doDashStroke(const RenderPath& path, const float* patterns, uint32_t patternCnt, float offset, float length);
float strokeRadius() const
{
@ -119,8 +119,7 @@ private:
class DashStroke
{
public:
DashStroke(Array<PathCommand>* cmds, Array<Point>* pts, const float* patterns, uint32_t patternCnt, float offset);
~DashStroke() = default;
DashStroke(Array<PathCommand>* cmds, Array<Point>* pts, const float* patterns, uint32_t patternCnt, float offset, float length);
void doStroke(const RenderPath& path);
private:
@ -135,12 +134,13 @@ private:
const float* mDashPattern;
uint32_t mDashCount;
float mDashOffset;
float mCurrLen;
int32_t mCurrIdx;
bool mCurOpGap;
bool mMove;
Point mPtStart;
Point mPtCur;
float mDashLength;
float mCurrLen = 0.0f;
int32_t mCurrIdx = 0;
bool mCurOpGap = false;
bool mMove = true;
Point mPtStart = {};
Point mPtCur = {};
};
class BWTessellator

View file

@ -85,7 +85,7 @@ struct SwShapeTask : SwTask
Additionally, the stroke style should not be dashed. */
bool antialiasing(float strokeWidth)
{
return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->trimpath() || rshape->stroke->color.a < 255;
return strokeWidth < 2.0f || rshape->stroke->dash.count > 0 || rshape->stroke->strokeFirst || rshape->trimpath() || rshape->stroke->color.a < 255;
}
float validStrokeWidth(bool clipper)

View file

@ -244,7 +244,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans
if (trimmed) {
RenderPath trimmedPath;
if (!rshape->stroke->trim.trim(rshape->path, trimmedPath)) return nullptr;
cmds = trimmedCmds = trimmedPath.cmds.data;
cmdCnt = trimmedPath.cmds.count;
pts = trimmedPts = trimmedPath.pts.data;
@ -263,19 +262,19 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
SwDashStroke dash;
auto offset = 0.0f;
dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
dash.pattern = rshape->stroke->dash.pattern;
dash.cnt = rshape->stroke->dash.count;
auto offset = rshape->stroke->dash.offset;
//offset
auto patternLength = 0.0f;
uint32_t offIdx = 0;
if (!tvg::zero(offset)) {
for (size_t i = 0; i < dash.cnt; ++i) patternLength += dash.pattern[i];
auto length = rshape->stroke->dash.length;
bool isOdd = dash.cnt % 2;
if (isOdd) patternLength *= 2;
if (isOdd) length *= 2;
offset = fmodf(offset, patternLength);
if (offset < 0) offset += patternLength;
offset = fmodf(offset, length);
if (offset < 0) offset += length;
for (size_t i = 0; i < dash.cnt * (1 + (size_t)isOdd); ++i, ++offIdx) {
auto curPattern = dash.pattern[i % dash.cnt];
@ -510,7 +509,7 @@ bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix&
auto ret = true;
//Dash style with/without trimming
if (rshape->stroke->dashCnt > 0) {
if (rshape->stroke->dash.count > 0) {
shapeOutline = _genDashOutline(rshape, transform, mpool, tid, rshape->trimpath());
if (!shapeOutline) return false;
dashStroking = true;

View file

@ -127,9 +127,12 @@ struct RenderStroke
float width = 0.0f;
RenderColor color{};
Fill *fill = nullptr;
float* dashPattern = nullptr;
uint32_t dashCnt = 0;
float dashOffset = 0.0f;
struct {
float* pattern = nullptr;
uint32_t count = 0;
float offset = 0.0f;
float length = 0.0f;
} dash;
float miterlimit = 4.0f;
RenderTrimPath trim;
StrokeCap cap = StrokeCap::Square;
@ -145,15 +148,16 @@ struct RenderStroke
if (rhs.fill) fill = rhs.fill->duplicate();
else fill = nullptr;
tvg::free(dashPattern);
if (rhs.dashCnt > 0) {
dashPattern = tvg::malloc<float*>(sizeof(float) * rhs.dashCnt);
memcpy(dashPattern, rhs.dashPattern, sizeof(float) * rhs.dashCnt);
tvg::free(dash.pattern);
if (rhs.dash.count > 0) {
dash.pattern = tvg::malloc<float*>(sizeof(float) * rhs.dash.count);
memcpy(dash.pattern, rhs.dash.pattern, sizeof(float) * rhs.dash.count);
} else {
dashPattern = nullptr;
dash.pattern = nullptr;
}
dashCnt = rhs.dashCnt;
dashOffset = rhs.dashOffset;
dash.count = rhs.dash.count;
dash.offset = rhs.dash.offset;
dash.length = rhs.dash.length;
miterlimit = rhs.miterlimit;
cap = rhs.cap;
join = rhs.join;
@ -163,7 +167,7 @@ struct RenderStroke
~RenderStroke()
{
tvg::free(dashPattern);
tvg::free(dash.pattern);
delete(fill);
}
};
@ -223,9 +227,9 @@ struct RenderShape
uint32_t strokeDash(const float** dashPattern, float* offset) const
{
if (!stroke) return 0;
if (dashPattern) *dashPattern = stroke->dashPattern;
if (offset) *offset = stroke->dashOffset;
return stroke->dashCnt;
if (dashPattern) *dashPattern = stroke->dash.pattern;
if (offset) *offset = stroke->dash.offset;
return stroke->dash.count;
}
StrokeCap strokeCap() const

View file

@ -282,34 +282,28 @@ struct Shape::Impl : Paint::Impl
Result strokeDash(const float* pattern, uint32_t cnt, float offset)
{
if ((cnt == 1) || (!pattern && cnt > 0) || (pattern && cnt == 0)) {
if ((cnt == 1) || (!pattern && cnt > 0) || (pattern && cnt == 0)) return Result::InvalidArguments;
if (!rs.stroke) rs.stroke = new RenderStroke;
//Reset dash
auto& dash = rs.stroke->dash;
if (dash.count != cnt) {
tvg::free(dash.pattern);
dash.pattern = nullptr;
}
if (cnt > 0) {
if (!dash.pattern) dash.pattern = tvg::malloc<float*>(sizeof(float) * cnt);
dash.length = 0.0f;
for (uint32_t i = 0; i < cnt; ++i) {
if (pattern[i] < FLT_EPSILON) {
dash.count = 0;
return Result::InvalidArguments;
}
for (uint32_t i = 0; i < cnt; i++) {
if (pattern[i] < FLOAT_EPSILON) return Result::InvalidArguments;
}
//Reset dash
if (!pattern && cnt == 0) {
tvg::free(rs.stroke->dashPattern);
rs.stroke->dashPattern = nullptr;
} else {
if (!rs.stroke) rs.stroke = new RenderStroke();
if (rs.stroke->dashCnt != cnt) {
tvg::free(rs.stroke->dashPattern);
rs.stroke->dashPattern = nullptr;
}
if (!rs.stroke->dashPattern) {
rs.stroke->dashPattern = tvg::malloc<float*>(sizeof(float) * cnt);
if (!rs.stroke->dashPattern) return Result::FailedAllocation;
}
for (uint32_t i = 0; i < cnt; ++i) {
rs.stroke->dashPattern[i] = pattern[i];
dash.pattern[i] = pattern[i];
dash.length += dash.pattern[i];
}
}
rs.stroke->dashCnt = cnt;
rs.stroke->dashOffset = offset;
rs.stroke->dash.count = cnt;
rs.stroke->dash.offset = offset;
renderFlag |= RenderUpdateFlag::Stroke;
return Result::Success;

View file

@ -353,47 +353,42 @@ struct WgIndexedVertexBuffer
icount += 6;
}
// dash buffer by pattern
void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke)
{
// dashed buffer
dashed->reset(scale);
// ignore single points polyline
if (buff.count < 2) return;
const float* dashPattern = rstroke->dashPattern;
size_t dashCnt = rstroke->dashCnt;
// starting state
uint32_t index_dash = 0;
float len_total = dashPattern[index_dash];
// get dashes length
float dashes_lenth{};
for (uint32_t i = 0; i < dashCnt * (dashCnt % 2 + 1); i++) {
dashes_lenth += dashPattern[i % dashCnt];
}
if (dashes_lenth == 0) return;
auto& dash = rstroke->dash;
if (buff.count < 2 || tvg::zero(dash.length)) return;
uint32_t index = 0;
auto total = dash.pattern[index];
auto length = (dash.count % 2) ? dash.length * 2 : dash.length;
// normalize dash offset
float dashOffset = rstroke->dashOffset;
while(dashOffset < 0) dashOffset += dashes_lenth;
while(dashOffset > dashes_lenth) dashOffset -= dashes_lenth;
auto dashOffset = dash.offset;
while(dashOffset < 0) dashOffset += length;
while(dashOffset > length) dashOffset -= length;
auto gap = false;
// scip dashes by offset
while(len_total <= dashOffset) {
index_dash = (index_dash + 1) % dashCnt;
len_total += dashPattern[index_dash];
while(total <= dashOffset) {
index = (index + 1) % dash.count;
total += dash.pattern[index];
gap = !gap;
}
len_total -= dashOffset;
total -= dashOffset;
// iterate by polyline points
for (uint32_t i = 0; i < buff.count - 1; i++) {
// append current polyline point
if (!gap) dashed->append(buff.data[i]);
// move inside polyline segment
while(len_total < buff.dist[i+1].interval) {
while(total < buff.dist[i+1].interval) {
// get current point
dashed->append(tvg::lerp(buff.data[i], buff.data[i+1], len_total / buff.dist[i+1].interval));
dashed->append(tvg::lerp(buff.data[i], buff.data[i+1], total / buff.dist[i+1].interval));
// update current state
index_dash = (index_dash + 1) % dashCnt;
len_total += dashPattern[index_dash];
index = (index + 1) % dash.count;
total += dash.pattern[index];
// preceed stroke if dash
if (!gap) {
dashed->updateDistances();
@ -403,7 +398,7 @@ struct WgIndexedVertexBuffer
gap = !gap;
}
// update current subline length
len_total -= buff.dist[i+1].interval;
total -= buff.dist[i+1].interval;
}
// draw last subline
if (!gap) {

View file

@ -394,8 +394,8 @@ void WgRenderDataShape::proceedStrokes(WgContext& context, const RenderStroke* r
{
assert(rstroke);
auto strokesGenerator = pool->reqIndexedVertexBuffer(buff.scale);
if (rstroke->dashPattern) strokesGenerator->appendStrokesDashed(buff, rstroke);
else strokesGenerator->appendStrokes(buff, rstroke);
if (rstroke->dash.count == 0) strokesGenerator->appendStrokes(buff, rstroke);
else strokesGenerator->appendStrokesDashed(buff, rstroke);
appendStroke(context, *strokesGenerator);