|
@@ -107,7 +107,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
|
|
if (mathZero(len)) {
|
|
if (mathZero(len)) {
|
|
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
|
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
|
//draw the current line fully
|
|
//draw the current line fully
|
|
- } else if (len < dash.curLen) {
|
|
|
|
|
|
+ } else if (len <= dash.curLen) {
|
|
dash.curLen -= len;
|
|
dash.curLen -= len;
|
|
if (!dash.curOpGap) {
|
|
if (!dash.curOpGap) {
|
|
if (dash.move) {
|
|
if (dash.move) {
|
|
@@ -168,7 +168,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
|
//draw the current line fully
|
|
//draw the current line fully
|
|
if (mathZero(len)) {
|
|
if (mathZero(len)) {
|
|
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
|
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
|
- } else if (len < dash.curLen) {
|
|
|
|
|
|
+ } else if (len <= dash.curLen) {
|
|
dash.curLen -= len;
|
|
dash.curLen -= len;
|
|
if (!dash.curOpGap) {
|
|
if (!dash.curOpGap) {
|
|
if (dash.move) {
|
|
if (dash.move) {
|
|
@@ -245,7 +245,86 @@ static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, float length, SwMpool* mpool, unsigned tid)
|
|
|
|
|
|
+static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length)
|
|
|
|
+{
|
|
|
|
+ auto begin = length * rshape->stroke->trim.begin;
|
|
|
|
+ auto end = length * rshape->stroke->trim.end;
|
|
|
|
+
|
|
|
|
+ //default
|
|
|
|
+ if (end > begin) {
|
|
|
|
+ if (begin > 0.0f) dash->cnt = 4;
|
|
|
|
+ else dash->cnt = 2;
|
|
|
|
+ //looping
|
|
|
|
+ } else dash->cnt = 3;
|
|
|
|
+
|
|
|
|
+ if (dash->cnt == 2) {
|
|
|
|
+ dash->pattern[0] = end - begin;
|
|
|
|
+ dash->pattern[1] = length - (end - begin);
|
|
|
|
+ } else if (dash->cnt == 3) {
|
|
|
|
+ dash->pattern[0] = end;
|
|
|
|
+ dash->pattern[1] = (begin - end);
|
|
|
|
+ dash->pattern[2] = length - begin;
|
|
|
|
+ } else {
|
|
|
|
+ dash->pattern[0] = 0; //zero dash to start with a space.
|
|
|
|
+ dash->pattern[1] = begin;
|
|
|
|
+ dash->pattern[2] = end - begin;
|
|
|
|
+ dash->pattern[3] = length - end;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static float _outlineLength(const RenderShape* rshape, uint32_t shiftPts, uint32_t shiftCmds, bool subpath)
|
|
|
|
+{
|
|
|
|
+ const PathCommand* cmds = rshape->path.cmds.data + shiftCmds;
|
|
|
|
+ auto cmdCnt = rshape->path.cmds.count - shiftCmds;
|
|
|
|
+ const Point* pts = rshape->path.pts.data + shiftPts;
|
|
|
|
+ auto ptsCnt = rshape->path.pts.count - shiftPts;
|
|
|
|
+
|
|
|
|
+ //No actual shape data
|
|
|
|
+ if (cmdCnt <= 0 || ptsCnt <= 0) return 0.0f;
|
|
|
|
+
|
|
|
|
+ const Point* close = nullptr;
|
|
|
|
+ auto length = 0.0f;
|
|
|
|
+
|
|
|
|
+ //must begin with moveTo
|
|
|
|
+ if (cmds[0] == PathCommand::MoveTo) {
|
|
|
|
+ close = pts;
|
|
|
|
+ cmds++;
|
|
|
|
+ pts++;
|
|
|
|
+ cmdCnt--;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (cmdCnt-- > 0) {
|
|
|
|
+ switch (*cmds) {
|
|
|
|
+ case PathCommand::Close: {
|
|
|
|
+ length += mathLength(pts - 1, close);
|
|
|
|
+ if (subpath) return length;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case PathCommand::MoveTo: {
|
|
|
|
+ if (subpath) return length;
|
|
|
|
+ close = pts;
|
|
|
|
+ ++pts;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case PathCommand::LineTo: {
|
|
|
|
+ length += mathLength(pts - 1, pts);
|
|
|
|
+ ++pts;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case PathCommand::CubicTo: {
|
|
|
|
+ length += bezLength({*(pts - 1), *pts, *(pts + 1), *(pts + 2)});
|
|
|
|
+ pts += 3;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ ++cmds;
|
|
|
|
+ }
|
|
|
|
+ return length;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, bool trimmed, SwMpool* mpool, unsigned tid)
|
|
{
|
|
{
|
|
const PathCommand* cmds = rshape->path.cmds.data;
|
|
const PathCommand* cmds = rshape->path.cmds.data;
|
|
auto cmdCnt = rshape->path.cmds.count;
|
|
auto cmdCnt = rshape->path.cmds.count;
|
|
@@ -255,49 +334,23 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|
//No actual shape data
|
|
//No actual shape data
|
|
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
|
|
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
|
|
|
|
|
|
|
|
+ auto startPts = pts;
|
|
|
|
+ auto startCmds = cmds;
|
|
|
|
+
|
|
SwDashStroke dash;
|
|
SwDashStroke dash;
|
|
auto offset = 0.0f;
|
|
auto offset = 0.0f;
|
|
- auto trimmed = false;
|
|
|
|
-
|
|
|
|
dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
|
|
dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
|
|
|
|
+ auto simultaneous = rshape->stroke->trim.simultaneous;
|
|
|
|
|
|
- //dash by trimming.
|
|
|
|
- if (length > 0.0f && dash.cnt == 0) {
|
|
|
|
- auto begin = length * rshape->stroke->trim.begin;
|
|
|
|
- auto end = length * rshape->stroke->trim.end;
|
|
|
|
-
|
|
|
|
- //TODO: mix trimming + dash style
|
|
|
|
-
|
|
|
|
- //default
|
|
|
|
- if (end > begin) {
|
|
|
|
- if (begin > 0.0f) dash.cnt += 4;
|
|
|
|
- else dash.cnt += 2;
|
|
|
|
- //looping
|
|
|
|
- } else dash.cnt += 3;
|
|
|
|
-
|
|
|
|
- dash.pattern = (float*)malloc(sizeof(float) * dash.cnt);
|
|
|
|
-
|
|
|
|
- if (dash.cnt == 2) {
|
|
|
|
- dash.pattern[0] = end - begin;
|
|
|
|
- dash.pattern[1] = length - (end - begin);
|
|
|
|
- } else if (dash.cnt == 3) {
|
|
|
|
- dash.pattern[0] = end;
|
|
|
|
- dash.pattern[1] = (begin - end);
|
|
|
|
- dash.pattern[2] = length - begin;
|
|
|
|
- } else {
|
|
|
|
- dash.pattern[0] = 0; //zero dash to start with a space.
|
|
|
|
- dash.pattern[1] = begin;
|
|
|
|
- dash.pattern[2] = end - begin;
|
|
|
|
- dash.pattern[3] = length - end;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- trimmed = true;
|
|
|
|
- //just a dasy style.
|
|
|
|
|
|
+ if (dash.cnt == 0) {
|
|
|
|
+ if (trimmed) dash.pattern = (float*)malloc(sizeof(float) * 4);
|
|
|
|
+ else return nullptr;
|
|
} else {
|
|
} else {
|
|
- if (dash.cnt == 0) return nullptr;
|
|
|
|
|
|
+ //TODO: handle dash + trim - for now trimming ignoring is forced
|
|
|
|
+ trimmed = false;
|
|
}
|
|
}
|
|
|
|
|
|
- //offset?
|
|
|
|
|
|
+ //offset
|
|
auto patternLength = 0.0f;
|
|
auto patternLength = 0.0f;
|
|
uint32_t offIdx = 0;
|
|
uint32_t offIdx = 0;
|
|
if (!mathZero(offset)) {
|
|
if (!mathZero(offset)) {
|
|
@@ -319,6 +372,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|
|
|
|
|
//must begin with moveTo
|
|
//must begin with moveTo
|
|
if (cmds[0] == PathCommand::MoveTo) {
|
|
if (cmds[0] == PathCommand::MoveTo) {
|
|
|
|
+ if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous));
|
|
_dashMoveTo(dash, offIdx, offset, pts);
|
|
_dashMoveTo(dash, offIdx, offset, pts);
|
|
cmds++;
|
|
cmds++;
|
|
pts++;
|
|
pts++;
|
|
@@ -331,8 +385,12 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case PathCommand::MoveTo: {
|
|
case PathCommand::MoveTo: {
|
|
- if (rshape->stroke->trim.individual) _dashMoveTo(dash, pts);
|
|
|
|
- else _dashMoveTo(dash, offIdx, offset, pts);
|
|
|
|
|
|
+ if (trimmed) {
|
|
|
|
+ if (simultaneous) {
|
|
|
|
+ _trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true));
|
|
|
|
+ _dashMoveTo(dash, offIdx, offset, pts);
|
|
|
|
+ } else _dashMoveTo(dash, pts);
|
|
|
|
+ } else _dashMoveTo(dash, offIdx, offset, pts);
|
|
++pts;
|
|
++pts;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -358,56 +416,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static float _outlineLength(const RenderShape* rshape)
|
|
|
|
-{
|
|
|
|
- const PathCommand* cmds = rshape->path.cmds.data;
|
|
|
|
- auto cmdCnt = rshape->path.cmds.count;
|
|
|
|
- const Point* pts = rshape->path.pts.data;
|
|
|
|
- auto ptsCnt = rshape->path.pts.count;
|
|
|
|
-
|
|
|
|
- //No actual shape data
|
|
|
|
- if (cmdCnt == 0 || ptsCnt == 0) return 0.0f;
|
|
|
|
-
|
|
|
|
- const Point* close = nullptr;
|
|
|
|
- auto length = 0.0f;
|
|
|
|
- auto slength = -1.0f;
|
|
|
|
- auto simultaneous = !rshape->stroke->trim.individual;
|
|
|
|
-
|
|
|
|
- //Compute the whole length
|
|
|
|
- while (cmdCnt-- > 0) {
|
|
|
|
- switch (*cmds) {
|
|
|
|
- case PathCommand::Close: {
|
|
|
|
- length += mathLength(pts - 1, close);
|
|
|
|
- //retrieve the max length of the shape if the simultaneous mode.
|
|
|
|
- if (simultaneous) {
|
|
|
|
- if (slength < length) slength = length;
|
|
|
|
- length = 0.0f;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case PathCommand::MoveTo: {
|
|
|
|
- close = pts;
|
|
|
|
- ++pts;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case PathCommand::LineTo: {
|
|
|
|
- length += mathLength(pts - 1, pts);
|
|
|
|
- ++pts;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case PathCommand::CubicTo: {
|
|
|
|
- length += bezLength({*(pts - 1), *pts, *(pts + 1), *(pts + 2)});
|
|
|
|
- pts += 3;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- ++cmds;
|
|
|
|
- }
|
|
|
|
- if (simultaneous && slength > length) return slength;
|
|
|
|
- else return length;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
static bool _axisAlignedRect(const SwOutline* outline)
|
|
static bool _axisAlignedRect(const SwOutline* outline)
|
|
{
|
|
{
|
|
//Fast Track: axis-aligned rectangle?
|
|
//Fast Track: axis-aligned rectangle?
|
|
@@ -584,11 +592,10 @@ bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix*
|
|
auto dashStroking = false;
|
|
auto dashStroking = false;
|
|
auto ret = true;
|
|
auto ret = true;
|
|
|
|
|
|
- auto length = rshape->strokeTrim() ? _outlineLength(rshape) : 0.0f;
|
|
|
|
-
|
|
|
|
//Dash style (+trimming)
|
|
//Dash style (+trimming)
|
|
- if (rshape->stroke->dashCnt > 0 || length > 0) {
|
|
|
|
- shapeOutline = _genDashOutline(rshape, transform, length, mpool, tid);
|
|
|
|
|
|
+ auto trimmed = rshape->strokeTrim();
|
|
|
|
+ if (rshape->stroke->dashCnt > 0 || trimmed) {
|
|
|
|
+ shapeOutline = _genDashOutline(rshape, transform, trimmed, mpool, tid);
|
|
if (!shapeOutline) return false;
|
|
if (!shapeOutline) return false;
|
|
dashStroking = true;
|
|
dashStroking = true;
|
|
//Normal style
|
|
//Normal style
|