uint32_t ptsCnt; //number of points in the glyph
uint32_t reservedPtsCnt;
uint8_t* types; //curve type
+ bool* closed; //opened or closed path?
FillRule fillRule;
- bool opened; //opened path?
};
struct SwSpan
float sx, sy;
bool firstPt;
- bool openSubPath;
+ bool closedSubPath;
bool handleWideStrokes;
};
image->outline = mpoolReqOutline(mpool, tid);
auto outline = image->outline;
- outline->reservedPtsCnt = 5;
- outline->pts = static_cast<SwPoint*>(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint)));
- outline->types = static_cast<uint8_t*>(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t)));
-
- outline->reservedCntrsCnt = 1;
- outline->cntrs = static_cast<uint32_t*>(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t)));
+ if (outline->reservedPtsCnt < 5) {
+ outline->reservedPtsCnt = 5;
+ outline->pts = static_cast<SwPoint*>(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint)));
+ outline->types = static_cast<uint8_t*>(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t)));
+ }
+
+ if (outline->reservedCntrsCnt < 1) {
+ outline->reservedCntrsCnt = 1;
+ outline->cntrs = static_cast<uint32_t*>(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t)));
+ outline->closed = static_cast<bool*>(realloc(outline->closed, outline->reservedCntrsCnt * sizeof(bool)));
+ outline->closed[0] = true;
+ }
auto w = static_cast<float>(image->w);
auto h = static_cast<float>(image->h);
outline->cntrs[outline->cntrsCnt] = outline->ptsCnt - 1;
++outline->cntrsCnt;
- outline->opened = false;
-
image->outline = outline;
return true;
free(p->types);
p->types = nullptr;
+ free(p->closed);
+ p->closed = nullptr;
+
p->cntrsCnt = p->reservedCntrsCnt = 0;
p->ptsCnt = p->reservedPtsCnt = 0;
free(p->types);
p->types = nullptr;
+ free(p->closed);
+ p->closed = nullptr;
+
p->cntrsCnt = p->reservedCntrsCnt = 0;
p->ptsCnt = p->reservedPtsCnt = 0;
}
}
-static void _growOutlineContour(SwOutline& outline, uint32_t n)
+static bool _growOutlineContour(SwOutline& outline, uint32_t n)
{
- if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
+ if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return false;
outline.reservedCntrsCnt = outline.cntrsCnt + n;
outline.cntrs = static_cast<uint32_t*>(realloc(outline.cntrs, outline.reservedCntrsCnt * sizeof(uint32_t)));
+ return true;
+}
+
+
+static void _growOutlineClose(SwOutline& outline)
+{
+ //Dash outlines are always opened.
+ //Only normal outlines use this information, it sholud be same to their contour counts.
+ outline.closed = static_cast<bool*>(realloc(outline.closed, outline.reservedCntrsCnt * sizeof(bool)));
}
static void _outlineEnd(SwOutline& outline)
{
_growOutlineContour(outline, 1);
+
+ if (outline.closed) {
+ outline.closed[outline.cntrsCnt] = false;
+ }
+
if (outline.ptsCnt > 0) {
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
++outline.cntrsCnt;
//Make sure there is at least one point in the current path
if (outline.ptsCnt == i) {
- outline.opened = true;
+ outline.closed[outline.cntrsCnt] = false;
return;
}
outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
++outline.ptsCnt;
- outline.opened = false;
+ outline.closed[outline.cntrsCnt] = true;
}
//OPTMIZE ME: Use mempool???
dash.pattern = const_cast<float*>(pattern);
dash.outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
- dash.outline->opened = true;
//smart reservation
auto outlinePtsCnt = 0;
++outlinePtsCnt; //for close
++outlineCntrsCnt; //for end
- //Reserve Approximitely 20x...
+ //No idea exact count.... Reserve Approximitely 20x...
_growOutlinePoint(*dash.outline, outlinePtsCnt * 20);
_growOutlineContour(*dash.outline, outlineCntrsCnt * 20);
shape->outline = mpoolReqOutline(mpool, tid);
auto outline = shape->outline;
- outline->opened = true;
_growOutlinePoint(*outline, outlinePtsCnt);
- _growOutlineContour(*outline, outlineCntrsCnt);
- auto closed = false;
+ if (_growOutlineContour(*outline, outlineCntrsCnt)) {
+ _growOutlineClose(*outline);
+ }
//Generate Outlines
while (cmdCnt-- > 0) {
switch(*cmds) {
case PathCommand::Close: {
_outlineClose(*outline);
- closed = true;
break;
}
case PathCommand::MoveTo: {
_outlineEnd(*outline);
- if (closed) outline->opened = false;
-
outline->fillRule = sdata->fillRule();
shape->outline = outline;
if (shapeOutline->cntrs) free(shapeOutline->cntrs);
if (shapeOutline->pts) free(shapeOutline->pts);
if (shapeOutline->types) free(shapeOutline->types);
+ if (shapeOutline->closed) free(shapeOutline->closed);
free(shapeOutline);
}
mpoolRetStrokeOutline(mpool, tid);
if (!shape->stroke->fill) return;
fillFree(shape->stroke->fill);
shape->stroke->fill = nullptr;
-}
\ No newline at end of file
+}
}
-static void _beginSubPath(SwStroke& stroke, const SwPoint& to, bool opened)
+static void _beginSubPath(SwStroke& stroke, const SwPoint& to, bool closed)
{
/* We cannot process the first point because there is not enough
information regarding its corner/cap. Later, it will be processed
stroke.firstPt = true;
stroke.center = to;
- stroke.openSubPath = opened;
+ stroke.closedSubPath = closed;
/* 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.openSubPath && stroke.cap == StrokeCap::Butt))
+ if ((stroke.join != StrokeJoin::Round) || (!stroke.closedSubPath && stroke.cap == StrokeCap::Butt))
stroke.handleWideStrokes = true;
else
stroke.handleWideStrokes = false;
static void _endSubPath(SwStroke& stroke)
{
- if (stroke.openSubPath) {
- auto right = stroke.borders;
-
- /* all right, this is an opened path, we need to add a cap between
- right & left, add the reverse of left, then add a final cap
- between left & right */
- _addCap(stroke, stroke.angleIn, 0);
-
- //add reversed points from 'left' to 'right'
- _addReverseLeft(stroke, true);
-
- //now add the final cap
- stroke.center = stroke.ptStartSubPath;
- _addCap(stroke, stroke.subPathAngle + SW_ANGLE_PI, 0);
-
- /* now end the right subpath accordingly. The left one is rewind
- and deosn't need further processing */
- _borderClose(right, false);
- } else {
-
+ if (stroke.closedSubPath) {
//close the path if needed
if (stroke.center != stroke.ptStartSubPath)
_lineTo(stroke, stroke.ptStartSubPath);
_borderClose(stroke.borders + 0, false);
_borderClose(stroke.borders + 1, true);
+ } else {
+ auto right = stroke.borders;
+
+ /* all right, this is an opened path, we need to add a cap between
+ right & left, add the reverse of left, then add a final cap
+ between left & right */
+ _addCap(stroke, stroke.angleIn, 0);
+
+ //add reversed points from 'left' to 'right'
+ _addReverseLeft(stroke, true);
+
+ //now add the final cap
+ stroke.center = stroke.ptStartSubPath;
+ _addCap(stroke, stroke.subPathAngle + SW_ANGLE_PI, 0);
+
+ /* now end the right subpath accordingly. The left one is rewind
+ and deosn't need further processing */
+ _borderClose(right, false);
}
}
//A contour cannot start with a cubic control point
if (type == SW_CURVE_TYPE_CUBIC) return false;
- _beginSubPath(*stroke, start, outline.opened);
+ auto closed = outline.closed ? outline.closed[i]: false;
+
+ _beginSubPath(*stroke, start, closed);
while (pt < limit) {
++pt;