/* Internal Class Implementation */
/************************************************************************/
-static void _growOutlineContour(SwOutline& outline, uint32_t n)
+struct Line
{
- if (n == 0) {
- free(outline.cntrs);
- outline.cntrs = nullptr;
- outline.cntrsCnt = 0;
- outline.reservedCntrsCnt = 0;
- return;
+ Point pt1;
+ Point pt2;
+};
+
+
+struct Bezier
+{
+ Point start;
+ Point ctrl1;
+ Point ctrl2;
+ Point end;
+};
+
+
+static float _lineLength(const Point& pt1, const Point& pt2)
+{
+ /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
+ With alpha = 1, beta = 3/8, giving results with the largest error less
+ than 7% compared to the exact value. */
+ Point diff = {pt2.x - pt1.x, pt2.y - pt1.y};
+ if (diff.x < 0) diff.x = -diff.x;
+ if (diff.y < 0) diff.y = -diff.y;
+ return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f);
+}
+
+
+static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right)
+{
+ auto len = _lineLength(cur.pt1, cur.pt2);
+ auto dx = ((cur.pt2.x - cur.pt1.x) / len) * at;
+ auto dy = ((cur.pt2.y - cur.pt1.y) / len) * at;
+ left.pt1 = cur.pt1;
+ left.pt2.x = left.pt1.x + dx;
+ left.pt2.y = left.pt1.y + dy;
+ right.pt1 = left.pt2;
+ right.pt2 = cur.pt2;
+}
+
+
+static void _bezSplit(const Bezier&cur, Bezier& left, Bezier& right)
+{
+ auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f;
+ left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f;
+ right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f;
+ left.start.x = cur.start.x;
+ right.end.x = cur.end.x;
+ left.ctrl2.x = (left.ctrl1.x + c) * 0.5f;
+ right.ctrl1.x = (right.ctrl2.x + c) * 0.5f;
+ left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f;
+
+ c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f;
+ left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f;
+ right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f;
+ left.start.y = cur.start.y;
+ right.end.y = cur.end.y;
+ left.ctrl2.y = (left.ctrl1.y + c) * 0.5f;
+ right.ctrl1.y = (right.ctrl2.y + c) * 0.5f;
+ left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f;
+}
+
+
+static float _bezLength(const Bezier& cur)
+{
+ Bezier left, right;
+ auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end);
+ auto chord = _lineLength(cur.start, cur.end);
+
+ if (fabs(len - chord) > FLT_EPSILON) {
+ _bezSplit(cur, left, right);
+ return _bezLength(left) + _bezLength(right);
}
- if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
+ return len;
+}
- //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
- outline.reservedCntrsCnt = n;
- outline.cntrs = static_cast<uint32_t*>(realloc(outline.cntrs, n * sizeof(uint32_t)));
- assert(outline.cntrs);
+
+static void _bezSplitLeft(Bezier& cur, float at, Bezier& left)
+{
+ left.start = cur.start;
+
+ left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x);
+ left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y);
+
+ left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot
+ left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot
+
+ cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x);
+ cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y);
+
+ cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x);
+ cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y);
+
+ left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x);
+ left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y);
+
+ left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x);
+ left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y);
}
-static void _growOutlinePoint(SwOutline& outline, uint32_t n)
+static float _bezAt(const Bezier& bz, float at)
{
- if (n == 0) {
- free(outline.pts);
- outline.pts = nullptr;
- free(outline.types);
- outline.types = nullptr;
- outline.reservedPtsCnt = 0;
- outline.ptsCnt = 0;
- return;
+ auto len = _bezLength(bz);
+ auto biggest = 1.0f;
+
+ if (at >= len) return 1.0f;
+
+ at *= 0.5f;
+
+ while (true) {
+ auto right = bz;
+ Bezier left;
+ _bezSplitLeft(right, at, left);
+ auto len2 = _bezLength(left);
+
+ if (fabs(len2 - len) < FLT_EPSILON) break;
+
+ if (len2 < len) {
+ at += (biggest - at) * 0.5f;
+ } else {
+ biggest = at;
+ at -= (at * 0.5f);
+ }
}
+ return at;
+}
- if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
- //cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
- outline.reservedPtsCnt = n;
- outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
+static void _bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right)
+{
+ right = cur;
+ auto t = _bezAt(right, at);
+ _bezSplitLeft(right, t, left);
+}
+
+
+static void _growOutlineContour(SwOutline& outline, uint32_t n)
+{
+ if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
+ outline.reservedCntrsCnt = outline.cntrsCnt + n;
+ outline.cntrs = static_cast<uint32_t*>(realloc(outline.cntrs, outline.reservedCntrsCnt * sizeof(uint32_t)));
+ assert(outline.cntrs);
+}
+
+
+static void _growOutlinePoint(SwOutline& outline, uint32_t n)
+{
+ if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
+ outline.reservedPtsCnt = outline.ptsCnt + n;
+ outline.pts = static_cast<SwPoint*>(realloc(outline.pts, outline.reservedPtsCnt * sizeof(SwPoint)));
assert(outline.pts);
- outline.types = static_cast<uint8_t*>(realloc(outline.types, n * sizeof(uint8_t)));
+ outline.types = static_cast<uint8_t*>(realloc(outline.types, outline.reservedPtsCnt * sizeof(uint8_t)));
assert(outline.types);
}
-static void _freeOutline(SwOutline* outline)
+static void _delOutline(SwOutline* outline)
{
if (!outline) return;
outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
-
++outline.ptsCnt;
}
}
-static bool _checkValid(SwShape& sdata, const SwSize& clip)
+static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip)
{
- assert(sdata.outline);
+ assert(outline);
- if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) return false;
+ if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false;
//Check boundary
- if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) ||
- (sdata.bbox.min.x + sdata.bbox.max.x < 0) ||
- (sdata.bbox.min.y + sdata.bbox.max.y < 0)) return false;
+ if ((bbox.min.x > clip.w || bbox.min.y > clip.h) ||
+ (bbox.min.x + bbox.max.x < 0) ||
+ (bbox.min.y + bbox.max.y < 0)) return false;
return true;
}
-/************************************************************************/
-/* External Class Implementation */
-/************************************************************************/
-
-void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform)
+static void _transformOutline(SwOutline* outline, const RenderTransform* transform)
{
- auto outline = sdata.outline;
assert(outline);
+ if (!transform) return;
+
for(uint32_t i = 0; i < outline->ptsCnt; ++i) {
auto dx = static_cast<float>(outline->pts[i].x >> 6);
auto dy = static_cast<float>(outline->pts[i].y >> 6);
- auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13;
- auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23;
- auto pt = Point{tx + transform.e31, ty + transform.e32};
+ auto tx = dx * transform->e11 + dy * transform->e12 + transform->e13;
+ auto ty = dx * transform->e21 + dy * transform->e22 + transform->e23;
+ auto pt = Point{tx + transform->e31, ty + transform->e32};
outline->pts[i] = TO_SWPOINT(&pt);
}
}
-bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
+static void _dashLineTo(SwDashStroke& dash, const Point* to)
+{
+ _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1);
+ _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1);
+
+ Line cur = {dash.ptCur, *to};
+ auto len = _lineLength(cur.pt1, cur.pt2);
+
+ if (len < dash.curLen) {
+ dash.curLen -= len;
+ if (!dash.curOpGap) {
+ _outlineMoveTo(*dash.outline, &dash.ptCur);
+ _outlineLineTo(*dash.outline, to);
+ }
+ } else {
+ while (len > dash.curLen) {
+ len -= dash.curLen;
+ Line left, right;
+ _lineSplitAt(cur, dash.curLen, left, right);;
+ dash.curIdx = (dash.curIdx + 1) % dash.cnt;
+ if (!dash.curOpGap) {
+ _outlineMoveTo(*dash.outline, &left.pt1);
+ _outlineLineTo(*dash.outline, &left.pt2);
+ }
+ dash.curLen = dash.pattern[dash.curIdx];
+ dash.curOpGap = !dash.curOpGap;
+ cur = right;
+ dash.ptCur = cur.pt1;
+ }
+ //leftovers
+ dash.curLen -= len;
+ if (!dash.curOpGap) {
+ _outlineMoveTo(*dash.outline, &cur.pt1);
+ _outlineLineTo(*dash.outline, &cur.pt2);
+ }
+ if (dash.curLen < 1) {
+ //move to next dash
+ dash.curIdx = (dash.curIdx + 1) % dash.cnt;
+ dash.curLen = dash.pattern[dash.curIdx];
+ dash.curOpGap = !dash.curOpGap;
+ }
+ }
+ dash.ptCur = *to;
+}
+
+
+static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to)
+{
+ _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1);
+ _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1);
+
+ Bezier cur = { dash.ptCur, *ctrl1, *ctrl2, *to};
+ auto len = _bezLength(cur);
+
+ if (len < dash.curLen) {
+ dash.curLen -= len;
+ if (!dash.curOpGap) {
+ _outlineMoveTo(*dash.outline, &dash.ptCur);
+ _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to);
+ }
+ } else {
+ while (len > dash.curLen) {
+ Bezier left, right;
+ len -= dash.curLen;
+ _bezSplitAt(cur, dash.curLen, left, right);
+ dash.curIdx = (dash.curIdx + 1) % dash.cnt;
+ if (!dash.curOpGap) {
+ _outlineMoveTo(*dash.outline, &left.start);
+ _outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end);
+ }
+ dash.curLen = dash.pattern[dash.curIdx];
+ dash.curOpGap = !dash.curOpGap;
+ cur = right;
+ dash.ptCur = right.start;
+ }
+ //leftovers
+ dash.curLen -= len;
+ if (!dash.curOpGap) {
+ _outlineMoveTo(*dash.outline, &cur.start);
+ _outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end);
+ }
+ if (dash.curLen < 1) {
+ //move to next dash
+ dash.curIdx = (dash.curIdx + 1) % dash.cnt;
+ dash.curLen = dash.pattern[dash.curIdx];
+ dash.curOpGap = !dash.curOpGap;
+ }
+ }
+ dash.ptCur = *to;
+}
+
+
+SwOutline* _genDashOutline(const Shape& shape)
{
- /* OPTIMIZE ME: We may avoid this bounding box calculation in this stage
- if this shape has stroke and stroke bbox can be used here... */
- if (!_updateBBox(sdata.outline, sdata.bbox)) goto end;
- if (!_checkValid(sdata, clip)) goto end;
+ const PathCommand* cmds = nullptr;
+ auto cmdCnt = shape.pathCommands(&cmds);
+
+ const Point* pts = nullptr;
+ auto ptsCnt = shape.pathCoords(&pts);
+
+ //No actual shape data
+ if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
+
+ SwDashStroke dash;
+ dash.curIdx = 0;
+ dash.curLen = 0;
+ dash.ptStart = {0, 0};
+ dash.ptCur = {0, 0};
+ dash.curOpGap = false;
+
+ const float* pattern;
+ dash.cnt = shape.strokeDash(&pattern);
+ assert(dash.cnt > 0 && pattern);
+
+ //Is it safe to mutual exclusive?
+ dash.pattern = const_cast<float*>(pattern);
+ dash.outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
+ assert(dash.outline);
+ dash.outline->opened = true;
+
+ //smart reservation
+ auto outlinePtsCnt = 0;
+ auto outlineCntrsCnt = 0;
+
+ for (uint32_t i = 0; i < cmdCnt; ++i) {
+ switch(*(cmds + i)) {
+ case PathCommand::Close: {
+ ++outlinePtsCnt;
+ break;
+ }
+ case PathCommand::MoveTo: {
+ ++outlineCntrsCnt;
+ ++outlinePtsCnt;
+ break;
+ }
+ case PathCommand::LineTo: {
+ ++outlinePtsCnt;
+ break;
+ }
+ case PathCommand::CubicTo: {
+ outlinePtsCnt += 3;
+ break;
+ }
+ }
+ }
- sdata.rle = rleRender(sdata.outline, sdata.bbox, clip);
+ ++outlinePtsCnt; //for close
+ ++outlineCntrsCnt; //for end
+
+ //Reserve Approximitely 20x...
+ _growOutlinePoint(*dash.outline, outlinePtsCnt * 20);
+ _growOutlineContour(*dash.outline, outlineCntrsCnt * 20);
+ while (cmdCnt-- > 0) {
+ switch(*cmds) {
+ case PathCommand::Close: {
+ _dashLineTo(dash, &dash.ptStart);
+ break;
+ }
+ case PathCommand::MoveTo: {
+ //reset the dash
+ dash.curIdx = 0;
+ dash.curLen = *dash.pattern;
+ dash.curOpGap = false;
+ dash.ptStart = dash.ptCur = *pts;
+ ++pts;
+ break;
+ }
+ case PathCommand::LineTo: {
+ _dashLineTo(dash, pts);
+ ++pts;
+ break;
+ }
+ case PathCommand::CubicTo: {
+ _dashCubicTo(dash, pts, pts + 1, pts + 2);
+ pts += 3;
+ break;
+ }
+ }
+ ++cmds;
+ }
+
+ _outlineEnd(*dash.outline);
+
+ return dash.outline;
+}
+
+
+/************************************************************************/
+/* External Class Implementation */
+/************************************************************************/
+
+bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform)
+{
+ if (!shapeGenOutline(shape, sdata)) return false;
+
+ _transformOutline(shape.outline, transform);
+
+ if (!_updateBBox(shape.outline, shape.bbox)) goto end;
+
+ if (!_checkValid(shape.outline, shape.bbox, clip)) goto end;
+
+ shape.rle = rleRender(shape.outline, shape.bbox, clip);
end:
- if (sdata.rle) return true;
+ if (shape.rle) return true;
return false;
}
-void shapeDelOutline(SwShape& sdata)
+void shapeDelOutline(SwShape& shape)
{
- auto outline = sdata.outline;
- _freeOutline(outline);
- sdata.outline = nullptr;
+ auto outline = shape.outline;
+ _delOutline(outline);
+ shape.outline = nullptr;
}
-void shapeReset(SwShape& sdata)
+void shapeReset(SwShape& shape)
{
- shapeDelOutline(sdata);
- rleFree(sdata.rle);
- sdata.rle = nullptr;
- _initBBox(sdata.bbox);
+ shapeDelOutline(shape);
+ rleFree(shape.rle);
+ shape.rle = nullptr;
+ _initBBox(shape.bbox);
}
-bool shapeGenOutline(const Shape& shape, SwShape& sdata)
+bool shapeGenOutline(SwShape& shape, const Shape& sdata)
{
const PathCommand* cmds = nullptr;
- auto cmdCnt = shape.pathCommands(&cmds);
+ auto cmdCnt = sdata.pathCommands(&cmds);
const Point* pts = nullptr;
- auto ptsCnt = shape.pathCoords(&pts);
+ auto ptsCnt = sdata.pathCoords(&pts);
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return false;
++outlinePtsCnt; //for close
++outlineCntrsCnt; //for end
- auto outline = sdata.outline;
+ auto outline = shape.outline;
if (!outline) outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
assert(outline);
outline->opened = true;
//FIXME:
//outline->flags = SwOutline::FillRule::Winding;
- sdata.outline = outline;
+ shape.outline = outline;
return true;
}
}
-void shapeResetStroke(const Shape& shape, SwShape& sdata)
+void shapeResetStroke(SwShape& shape, const Shape& sdata)
{
- if (!sdata.stroke) sdata.stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
- auto stroke = sdata.stroke;
+ if (!shape.stroke) shape.stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
+ auto stroke = shape.stroke;
assert(stroke);
- strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin());
- rleFree(sdata.strokeRle);
- sdata.strokeRle = nullptr;
+
+ strokeReset(*stroke, sdata);
+
+ rleFree(shape.strokeRle);
+ shape.strokeRle = nullptr;
}
-bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
+bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip)
{
- if (!sdata.outline) {
- if (!shapeGenOutline(shape, sdata)) return false;
- }
+ SwOutline* shapeOutline = nullptr;
- if (!_checkValid(sdata, clip)) return false;
+ //Dash Style Stroke
+ if (sdata.strokeDash(nullptr) > 0) {
+ shapeOutline = _genDashOutline(sdata);
+ if (!shapeOutline) return false;
+
+ //Normal Style stroke
+ } else {
+ if (!shape.outline) {
+ if (!shapeGenOutline(shape, sdata)) return false;
+ }
+ shapeOutline = shape.outline;
+ }
- if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false;
+ if (!strokeParseOutline(*shape.stroke, *shapeOutline)) return false;
- auto outline = strokeExportOutline(*sdata.stroke);
- if (!outline) return false;
+ auto strokeOutline = strokeExportOutline(*shape.stroke);
+ if (!strokeOutline) return false;
SwBBox bbox;
- _updateBBox(outline, bbox);
+ _updateBBox(strokeOutline, bbox);
- sdata.strokeRle = rleRender(outline, bbox, clip);
+ if (!_checkValid(strokeOutline, bbox, clip)) return false;
- _freeOutline(outline);
+ shape.strokeRle = rleRender(strokeOutline, bbox, clip);
+
+ _delOutline(strokeOutline);
return true;
}
+
#endif /* _TVG_SW_SHAPE_H_ */
}
-void _subPathStart(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength)
+void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength)
{
SwPoint delta = {stroke.width, 0};
mathRotate(delta, startAngle + ANGLE_PI2);
if (stroke.firstPt) {
/* This is the first segment of a subpath. We need to add a point to each border
at their respective starting point locations. */
- _subPathStart(stroke, angle, lineLength);
+ _firstSubPath(stroke, angle, lineLength);
} else {
//process the current corner
stroke.angleOut = angle;
firstArc = false;
//process corner if necessary
if (stroke.firstPt) {
- _subPathStart(stroke, angleIn, 0);
+ _firstSubPath(stroke, angleIn, 0);
} else {
stroke.angleOut = angleIn;
_processCorner(stroke, 0);
SwPoint delta2 = {stroke.width, 0};
mathRotate(delta2, angle + rotate);
-
delta += stroke.center + delta2;
_borderLineTo(border, delta, false);
stroke.firstPt = true;
stroke.center = to;
- stroke.subPathOpen = opened;
+ stroke.openSubPath = opened;
/* Determine if we need to check whether the border radius is greater
than the radius of curvature of a curve, to handle this case specially.
This is only required if bevel joins or butt caps may be created because
round & miter joins and round & square caps cover the nagative sector
created with wide strokes. */
- if ((stroke.join != StrokeJoin::Round) || (stroke.subPathOpen && stroke.cap == StrokeCap::Butt))
+ if ((stroke.join != StrokeJoin::Round) || (stroke.openSubPath && stroke.cap == StrokeCap::Butt))
stroke.handleWideStrokes = true;
else
stroke.handleWideStrokes = false;
- stroke.subPathStart = to;
+ stroke.ptStartSubPath = to;
stroke.angleIn = 0;
}
static void _endSubPath(SwStroke& stroke)
{
- if (stroke.subPathOpen) {
+ if (stroke.openSubPath) {
auto right = stroke.borders;
assert(right);
_addReverseLeft(stroke, true);
//now add the final cap
- stroke.center = stroke.subPathStart;
+ stroke.center = stroke.ptStartSubPath;
_addCap(stroke, stroke.subPathAngle + ANGLE_PI, 0);
/* now end the right subpath accordingly. The left one is rewind
} else {
//close the path if needed
- if (stroke.center != stroke.subPathStart)
- _lineTo(stroke, stroke.subPathStart);
+ if (stroke.center != stroke.ptStartSubPath)
+ _lineTo(stroke, stroke.ptStartSubPath);
//process the corner
stroke.angleOut = stroke.subPathAngle;
++cntrs;
++outline->cntrsCnt;
}
-
++src;
++tags;
++idx;
}
-void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join)
+void strokeReset(SwStroke& stroke, const Shape& shape)
{
- stroke.width = TO_SWCOORD(width * 0.5);
- stroke.cap = cap;
+ stroke.width = TO_SWCOORD(shape.strokeWidth() * 0.5);
+ stroke.cap = shape.strokeCap();
//Save line join: it can be temporarily changed when stroking curves...
- stroke.joinSaved = stroke.join = join;
+ stroke.joinSaved = stroke.join = shape.strokeJoin();
stroke.borders[0].ptsCnt = 0;
stroke.borders[0].start = -1;
}
-bool strokeParseOutline(SwStroke& stroke, SwOutline& outline)
+bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline)
{
uint32_t first = 0;
return outline;
}
-
#endif /* _TVG_SW_STROKER_H_ */