sw_engine: fix dash offset bug.

The latest offset feature has a missing starting point of the cubic bezier.
This fix addresses the issue.
This commit is contained in:
Hermet Park 2023-08-23 14:04:14 +09:00 committed by Hermet Park
parent 68f4193378
commit f2e755cdd5
2 changed files with 17 additions and 22 deletions

View file

@ -194,14 +194,14 @@ struct SwStroke
struct SwDashStroke struct SwDashStroke
{ {
SwOutline* outline; SwOutline* outline = nullptr;
float curLen; float curLen = 0;
int32_t curIdx; int32_t curIdx = 0;
Point ptStart; Point ptStart = {0, 0};
Point ptCur; Point ptCur = {0, 0};
float* pattern; float* pattern = nullptr;
uint32_t cnt; uint32_t cnt = 0;
bool curOpGap; bool curOpGap = false;
}; };
struct SwShape struct SwShape

View file

@ -169,14 +169,16 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
_outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform); _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform);
} }
} else { } else {
bool begin = true; //starting with move_to
while (len > dash.curLen) { while (len > dash.curLen) {
Bezier left, right; Bezier left, right;
len -= dash.curLen; len -= dash.curLen;
bezSplitAt(cur, dash.curLen, left, right); bezSplitAt(cur, dash.curLen, left, right);
if (!dash.curOpGap) { if (!dash.curOpGap) {
// leftovers from a previous command don't require moveTo // leftovers from a previous command don't require moveTo
if (dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) { if (begin || dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) {
_outlineMoveTo(*dash.outline, &left.start, transform); _outlineMoveTo(*dash.outline, &left.start, transform);
begin = false;
} }
_outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end, transform); _outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end, transform);
} }
@ -215,36 +217,29 @@ 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;
dash.curIdx = 0;
dash.curLen = 0;
dash.ptStart = {0, 0};
dash.ptCur = {0, 0};
dash.curOpGap = false;
const float* pattern;
float offset; float offset;
dash.cnt = rshape->strokeDash(&pattern, &offset); dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
if (dash.cnt == 0) return nullptr; if (dash.cnt == 0) return nullptr;
auto patternLength = 0.0f; auto patternLength = 0.0f;
uint32_t offIdx = 0; uint32_t offIdx = 0;
if (fabsf(offset) > FLT_EPSILON) { if (fabsf(offset) > FLT_EPSILON) {
for (size_t i = 0; i < dash.cnt; ++i) patternLength += pattern[i]; for (size_t i = 0; i < dash.cnt; ++i) patternLength += dash.pattern[i];
bool isOdd = dash.cnt % 2; bool isOdd = dash.cnt % 2;
if (isOdd) patternLength *= 2; if (isOdd) patternLength *= 2;
if (offset < 0) offset = patternLength + fmod(offset, patternLength); offset = fmod(offset, patternLength);
else offset = fmod(offset, patternLength); if (offset < 0) offset += patternLength;
for (size_t i = 0; i < dash.cnt * (1 + isOdd); ++i, ++offIdx) { for (size_t i = 0; i < dash.cnt * (1 + (size_t)isOdd); ++i, ++offIdx) {
auto curPattern = pattern[i % dash.cnt]; auto curPattern = dash.pattern[i % dash.cnt];
if (offset < curPattern) break; if (offset < curPattern) break;
offset -= curPattern; offset -= curPattern;
} }
} }
//OPTMIZE ME: Use mempool??? //OPTMIZE ME: Use mempool???
dash.pattern = const_cast<float*>(pattern);
dash.outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline))); dash.outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
//smart reservation //smart reservation