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

View file

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

View file

@ -85,7 +85,7 @@ struct SwShapeTask : SwTask
Additionally, the stroke style should not be dashed. */ Additionally, the stroke style should not be dashed. */
bool antialiasing(float strokeWidth) 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) float validStrokeWidth(bool clipper)

View file

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

View file

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

View file

@ -282,34 +282,28 @@ struct Shape::Impl : Paint::Impl
Result strokeDash(const float* pattern, uint32_t cnt, float offset) 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; return Result::InvalidArguments;
} }
dash.pattern[i] = pattern[i];
for (uint32_t i = 0; i < cnt; i++) { dash.length += dash.pattern[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];
} }
} }
rs.stroke->dashCnt = cnt; rs.stroke->dash.count = cnt;
rs.stroke->dashOffset = offset; rs.stroke->dash.offset = offset;
renderFlag |= RenderUpdateFlag::Stroke; renderFlag |= RenderUpdateFlag::Stroke;
return Result::Success; return Result::Success;

View file

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

View file

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