sw_engine: implement stroke rle part 02/235002/9
authorHermet Park <chuneon.park@samsung.com>
Mon, 1 Jun 2020 11:27:43 +0000 (20:27 +0900)
committerHermet Park <chuneon.park@samsung.com>
Tue, 2 Jun 2020 09:46:43 +0000 (18:46 +0900)
Current stroke fails to merged shapes case...

you can test with testStroke example

Change-Id: I488af728949cba1d01b88723eb1dc4c49bac6c9b

src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwMath.cpp
src/lib/sw_engine/tvgSwRaster.cpp
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRle.cpp
src/lib/sw_engine/tvgSwShape.cpp
src/lib/sw_engine/tvgSwStroke.cpp
test/testStroke.cpp

index b942ca1..cfb15bd 100644 (file)
@@ -121,8 +121,6 @@ struct SwStrokeBorder
 
 struct SwStroke
 {
-    SwRleData* rle;
-
     SwFixed angleIn;
     SwFixed angleOut;
     SwPoint center;
@@ -146,8 +144,9 @@ struct SwStroke
 struct SwShape
 {
     SwOutline*   outline;
-    SwRleData*   rle;
     SwStroke*    stroke;
+    SwRleData*   rle;
+    SwRleData*   strokeRle;
     SwBBox       bbox;
 };
 
@@ -196,11 +195,13 @@ void shapeFree(SwShape* sdata);
 
 void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join);
 bool strokeParseOutline(SwStroke& stroke, SwOutline& outline);
+SwOutline* strokeExportOutline(SwStroke& stroke);
 void strokeFree(SwStroke* stroke);
 
-SwRleData* rleRender(const SwShape& sdata, const SwSize& clip);
-SwRleData* rleStrokeRender(const SwShape& sdata);
+SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip);
+void rleFree(SwRleData* rle);
 
 bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
+bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
 
 #endif /* _TVG_SW_COMMON_H_ */
index 919fe1e..d2fcc4e 100644 (file)
@@ -24,7 +24,7 @@
 /* Internal Class Implementation                                        */
 /************************************************************************/
 
-constexpr auto CORDIC_FACTOR = 0xDBD95B16UL;            //the Cordic shrink factor 0.858785336480436 * 2^32
+constexpr SwCoord CORDIC_FACTOR = 0xDBD95B16UL;            //the Cordic shrink factor 0.858785336480436 * 2^32
 
 //this table was generated for SW_FT_PI = 180L << 16, i.e. degrees
 constexpr static auto ATAN_MAX = 23;
@@ -45,15 +45,14 @@ static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n)
 }
 
 
-static SwCoord _downscale(SwCoord x)
+static SwCoord _downscale(SwFixed x)
 {
     //multiply a give value by the CORDIC shrink factor
-
-    abs(x);
-    int64_t t = (x * static_cast<int64_t>(CORDIC_FACTOR)) + 0x100000000UL;
-    x = static_cast<SwFixed>(t >> 32);
-    if (x < 0) x = -x;
-    return x;
+    auto s = abs(x);
+    int64_t t = (s * static_cast<int64_t>(CORDIC_FACTOR)) + 0x100000000UL;
+    s = static_cast<SwFixed>(t >> 32);
+    if (x < 0) s = -s;
+    return s;
 }
 
 
@@ -139,6 +138,47 @@ static void _polarize(SwPoint& pt)
 }
 
 
+static void _rotate(SwPoint& pt, SwFixed theta)
+{
+    auto v = pt;
+
+    //Rotate inside [-PI/4, PI/4] sector
+    while (theta < -ANGLE_PI4) {
+        auto tmp = v.y;
+        v.y = -v.x;
+        v.x = tmp;
+        theta += ANGLE_PI2;
+    }
+
+    while (theta > ANGLE_PI4) {
+        auto tmp = -v.y;
+        v.y = v.x;
+        v.x = tmp;
+        theta -= ANGLE_PI2;
+    }
+
+    auto atan = ATAN_TBL;
+    uint32_t i;
+    SwFixed j;
+
+    for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
+        if (theta < 0) {
+            auto tmp = v.x + ((v.y + j) >> i);
+            v.y = v.y - ((v.x + j) >> i);
+            v.x = tmp;
+            theta += *atan++;
+        }else {
+            auto tmp = v.x - ((v.y + j) >> i);
+            v.y = v.y + ((v.x + j) >> i);
+            v.x = tmp;
+            theta -= *atan++;
+        }
+    }
+
+    pt = v;
+}
+
+
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
@@ -267,57 +307,26 @@ void mathRotate(SwPoint& pt, SwFixed angle)
     auto shift = _normalize(v);
     auto theta = angle;
 
-    //Rotate inside [-PI/4, PI/4] sector
-    while (theta < -ANGLE_PI4) {
-        auto tmp = v.y;
-        v.y = -v.x;
-        v.x = tmp;
-        theta += ANGLE_PI2;
-    }
-
-    while (theta > ANGLE_PI4) {
-        auto tmp = -v.y;
-        v.y = v.x;
-        v.x = tmp;
-        theta -= ANGLE_PI2;
-    }
-
-    auto atan = ATAN_TBL;
-    uint32_t i;
-    SwFixed j;
-
-    for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
-        if (theta < 0) {
-            auto tmp = v.x + ((v.y + j) >> i);
-            v.y = v.y - ((v.x + j) >> i);
-            v.x = tmp;
-            theta += *atan++;
-        }else {
-            auto tmp = v.x - ((v.y + j) >> i);
-            v.y = v.y + ((v.x + j) >> i);
-            v.x = tmp;
-            theta -= *atan++;
-        }
-    }
+    _rotate(v, theta);
 
     v.x = _downscale(v.x);
     v.y = _downscale(v.y);
 
     if (shift > 0) {
         auto half = static_cast<int32_t>(1L << (shift - 1));
-        v.x = (v.x + half + SATURATE(v.x)) >> shift;
-        v.y = (v.y + half + SATURATE(v.y)) >> shift;
+        pt.x = (v.x + half + SATURATE(v.x)) >> shift;
+        pt.y = (v.y + half + SATURATE(v.y)) >> shift;
     } else {
         shift = -shift;
-        v.x = static_cast<SwCoord>((unsigned long)v.x << shift);
-        v.y = static_cast<SwCoord>((unsigned long)v.y << shift);
+        pt.x = static_cast<SwCoord>((unsigned long)v.x << shift);
+        pt.y = static_cast<SwCoord>((unsigned long)v.y << shift);
     }
 }
 
 SwFixed mathTan(SwFixed angle)
 {
     SwPoint v = {CORDIC_FACTOR >> 8, 0};
-    mathRotate(v, angle);
+    _rotate(v, angle);
     return mathDivide(v.y, v.x);
 }
 
@@ -343,7 +352,7 @@ SwFixed mathSin(SwFixed angle)
 SwFixed mathCos(SwFixed angle)
 {
     SwPoint v = {CORDIC_FACTOR >> 8, 0};
-    mathRotate(v, angle);
+    _rotate(v, angle);
     return (v.x + 0x80L) >> 8;
 }
 
index ba7c6a3..78d507b 100644 (file)
@@ -76,18 +76,13 @@ _rasterSolid(uint32_t* dst, uint32_t len, uint32_t color, uint32_t cov)
 }
 
 
-/************************************************************************/
-/* External Class Implementation                                        */
-/************************************************************************/
-
-bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
+static bool
+_rasterRle(Surface& surface, SwRleData* rle, uint32_t color, uint8_t a)
 {
-    SwRleData* rle = sdata.rle;
     if (!rle) return false;
 
     auto span = rle->spans;
     auto stride = surface.stride;
-    auto color = COLOR_ARGB_JOIN(r, g, b, a);
 
     for (uint32_t i = 0; i < rle->size; ++i) {
         assert(span);
@@ -103,4 +98,21 @@ bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t
     return true;
 }
 
+
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+bool rasterShape(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
+{
+    return _rasterRle(surface, sdata.rle, COLOR_ARGB_JOIN(r, g, b, a), a);
+}
+
+
+bool rasterStroke(Surface& surface, SwShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
+{
+    return _rasterRle(surface, sdata.strokeRle, COLOR_ARGB_JOIN(r, g, b, a), a);
+}
+
+
 #endif /* _TVG_SW_RASTER_CPP_ */
\ No newline at end of file
index bf97c9b..3ec882e 100644 (file)
@@ -63,16 +63,14 @@ bool SwRenderer::render(const Shape& shape, void *data)
     if (!sdata) return false;
 
     size_t r, g, b, a;
-    shape.fill(&r, &g, &b, &a);
 
-    size_t sa;
-    shape.strokeColor(nullptr, nullptr, nullptr, &sa);
+    shape.fill(&r, &g, &b, &a);
+    if (a > 0) rasterShape(surface, *sdata, r, g, b, a);
 
-    //invisible?
-    if (a == 0 && sa == 0) return false;
+    shape.strokeColor(&r, &g, &b, &a);
+    if (a > 0) rasterStroke(surface, *sdata, r, g, b, a);
 
-    //TODO: Threading
-    return rasterShape(surface, *sdata, r, g, b, a);
+    return true;
 }
 
 
index 7bbc326..b22b233 100644 (file)
@@ -612,9 +612,7 @@ static bool _decomposeOutline(RleWorker& rw)
                 goto close;
             }
         }
-
-        //FIXME: Close the contour with a line segment?
-        //_lineTo(rw, UPSCALE(outline->pts[first]));
+        _lineTo(rw, UPSCALE(outline->pts[first]));
     close:
        first = last + 1;
     }
@@ -646,13 +644,12 @@ static bool _genRle(RleWorker& rw)
 /* External Class Implementation                                        */
 /************************************************************************/
 
-SwRleData* rleRender(const SwShape& sdata, const SwSize& clip)
+SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip)
 {
     //Please adjust when you out of cell memory (default: 16384L)
     constexpr auto RENDER_POOL_SIZE = 166641L;
     constexpr auto BAND_SIZE = 40;
 
-    auto outline = sdata.outline;
     assert(outline);
     assert(outline->cntrs && outline->pts);
     assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
@@ -671,11 +668,11 @@ SwRleData* rleRender(const SwShape& sdata, const SwSize& clip)
     rw.area = 0;
     rw.cover = 0;
     rw.invalid = true;
-    rw.cellMin = sdata.bbox.min;
-    rw.cellMax = sdata.bbox.max;
+    rw.cellMin = bbox.min;
+    rw.cellMax = bbox.max;
     rw.cellXCnt = rw.cellMax.x - rw.cellMin.x;
     rw.cellYCnt = rw.cellMax.y - rw.cellMin.y;
-    rw.outline = outline;
+    rw.outline = const_cast<SwOutline*>(outline);
     rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8);  //bandSize: 64
     rw.bandShoot = 0;
     rw.clip = clip;
@@ -770,12 +767,13 @@ error:
 }
 
 
-SwRleData* rleStrokeRender(const SwShape& sdata)
+void rleFree(SwRleData* rle)
 {
-    auto stroke = sdata.stroke;
-    assert(stroke);
-
-    return nullptr;
+    if (!rle) return;
+    if (rle->spans) free(rle->spans);
+    free(rle);
 }
 
+
+
 #endif /* _TVG_SW_RLE_H_ */
index f1ab06e..e8e1996 100644 (file)
@@ -64,6 +64,17 @@ static void _growOutlinePoint(SwOutline& outline, uint32_t n)
 }
 
 
+static void _freeOutline(SwOutline* outline)
+{
+    if (!outline) return;
+
+    if (outline->cntrs) free(outline->cntrs);
+    if (outline->pts) free(outline->pts);
+    if (outline->types) free(outline->types);
+    free(outline);
+}
+
+
 static void _outlineEnd(SwOutline& outline)
 {
     _growOutlineContour(outline, 1);
@@ -153,23 +164,22 @@ static void _outlineClose(SwOutline& outline)
 }
 
 
-static void _initBBox(SwShape& sdata)
+static void _initBBox(SwBBox& bbox)
 {
-    sdata.bbox.min.x = sdata.bbox.min.y = 0;
-    sdata.bbox.max.x = sdata.bbox.max.y = 0;
+    bbox.min.x = bbox.min.y = 0;
+    bbox.max.x = bbox.max.y = 0;
 }
 
 
-static bool _updateBBox(SwShape& sdata)
+static bool _updateBBox(SwOutline* outline, SwBBox& bbox)
 {
-    auto outline = sdata.outline;
-    assert(outline);
+    if (!outline) return false;
 
     auto pt = outline->pts;
     assert(pt);
 
     if (outline->ptsCnt <= 0) {
-        _initBBox(sdata);
+        _initBBox(bbox);
         return false;
     }
 
@@ -187,10 +197,10 @@ static bool _updateBBox(SwShape& sdata)
         if (yMin > pt->y) yMin = pt->y;
         if (yMax < pt->y) yMax = pt->y;
     }
-    sdata.bbox.min.x = xMin >> 6;
-    sdata.bbox.max.x = (xMax + 63) >> 6;
-    sdata.bbox.min.y = yMin >> 6;
-    sdata.bbox.max.y = (yMax + 63) >> 6;
+    bbox.min.x = xMin >> 6;
+    bbox.max.x = (xMax + 63) >> 6;
+    bbox.min.y = yMin >> 6;
+    bbox.max.y = (yMax + 63) >> 6;
 
     if (xMax - xMin < 1 || yMax - yMin < 1) return false;
 
@@ -213,16 +223,6 @@ static bool _checkValid(SwShape& sdata, const SwSize& clip)
 }
 
 
-static void _deleteRle(SwShape& sdata)
-{
-    if (!sdata.rle) return;
-    if (sdata.rle->spans) free(sdata.rle->spans);
-    free(sdata.rle);
-    sdata.rle = nullptr;
-}
-
-
-
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
@@ -245,10 +245,10 @@ void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTrans
 
 bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
 {
-    if (!_updateBBox(sdata)) goto end;
+    if (!_updateBBox(sdata.outline, sdata.bbox)) goto end;
     if (!_checkValid(sdata, clip)) goto end;
 
-    sdata.rle = rleRender(sdata, clip);
+    sdata.rle = rleRender(sdata.outline, sdata.bbox, clip);
 
 end:
     if (sdata.rle) return true;
@@ -259,12 +259,7 @@ end:
 void shapeDelOutline(SwShape& sdata)
 {
     auto outline = sdata.outline;
-    if (!outline) return;
-
-    if (outline->cntrs) free(outline->cntrs);
-    if (outline->pts) free(outline->pts);
-    if (outline->types) free(outline->types);
-    free(outline);
+    _freeOutline(outline);
     sdata.outline = nullptr;
 }
 
@@ -272,8 +267,9 @@ void shapeDelOutline(SwShape& sdata)
 void shapeReset(SwShape& sdata)
 {
     shapeDelOutline(sdata);
-    _deleteRle(sdata);
-    _initBBox(sdata);
+    rleFree(sdata.rle);
+    sdata.rle = nullptr;
+    _initBBox(sdata.bbox);
 }
 
 
@@ -366,8 +362,13 @@ void shapeFree(SwShape* sdata)
     assert(sdata);
 
     shapeDelOutline(*sdata);
-    _deleteRle(*sdata);
-    strokeFree(sdata->stroke);
+    rleFree(sdata->rle);
+
+    if (sdata->stroke) {
+        rleFree(sdata->strokeRle);
+        strokeFree(sdata->stroke);
+    }
+
     free(sdata);
 }
 
@@ -377,8 +378,9 @@ void shapeResetStroke(const Shape& shape, SwShape& sdata)
     if (!sdata.stroke) sdata.stroke = static_cast<SwStroke*>(calloc(1, sizeof(SwStroke)));
     auto stroke = sdata.stroke;
     assert(stroke);
-
     strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin());
+    rleFree(sdata.strokeRle);
+    sdata.strokeRle = nullptr;
 }
 
 
@@ -392,6 +394,16 @@ bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip)
 
     if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false;
 
+    auto outline = strokeExportOutline(*sdata.stroke);
+    if (!outline) return false;
+
+    SwBBox bbox;
+    _updateBBox(outline, bbox);
+
+    sdata.strokeRle = rleRender(outline, bbox, clip);
+
+    _freeOutline(outline);
+
     return true;
 }
 
index a0a2573..8477d7c 100644 (file)
@@ -23,7 +23,7 @@
 /************************************************************************/
 /* Internal Class Implementation                                        */
 /************************************************************************/
-static constexpr auto SW_STROKE_TAG_ON = 1;
+static constexpr auto SW_STROKE_TAG_POINT = 1;
 static constexpr auto SW_STROKE_TAG_CUBIC = 2;
 static constexpr auto SW_STROKE_TAG_BEGIN = 4;
 static constexpr auto SW_STROKE_TAG_END = 8;
@@ -36,6 +36,8 @@ static inline SwFixed SIDE_TO_ROTATE(const int32_t s)
 
 static void _growBorder(SwStrokeBorder* border, uint32_t newPts)
 {
+    assert(border);
+
     auto maxOld = border->maxPts;
     auto maxNew = border->ptsCnt + newPts;
 
@@ -53,8 +55,6 @@ static void _growBorder(SwStrokeBorder* border, uint32_t newPts)
     assert(border->tags);
 
     border->maxPts = maxCur;
-
-    printf("realloc border!!! (%u => %u)\n", maxOld, maxCur);
 }
 
 
@@ -111,7 +111,7 @@ static void _borderClose(SwStrokeBorder* border, bool reverse)
 
 static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
 {
-    assert(border->start >= 0);
+    assert(border && border->start >= 0);
 
     _growBorder(border, 3);
 
@@ -124,9 +124,10 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl
 
     tag[0] = SW_STROKE_TAG_CUBIC;
     tag[1] = SW_STROKE_TAG_CUBIC;
-    tag[2] = SW_STROKE_TAG_ON;
+    tag[2] = SW_STROKE_TAG_POINT;
 
     border->ptsCnt += 3;
+
     border->movable = false;
 }
 
@@ -188,13 +189,13 @@ static void _borderLineTo(SwStrokeBorder* border, SwPoint& to, bool movable)
         //move last point
         border->pts[border->ptsCnt - 1] = to;
     } else {
+
         //don't add zero-length line_to
-        auto diff = border->pts[border->ptsCnt - 1] - to;
-        if (border->ptsCnt > 0 && diff.small()) return;
+        if (border->ptsCnt > 0 && (border->pts[border->ptsCnt - 1] - to).small()) return;
 
         _growBorder(border, 1);
         border->pts[border->ptsCnt] = to;
-        border->tags[border->ptsCnt] = SW_STROKE_TAG_ON;
+        border->tags[border->ptsCnt] = SW_STROKE_TAG_POINT;
         border->ptsCnt += 1;
     }
 
@@ -207,8 +208,7 @@ static void _borderMoveTo(SwStrokeBorder* border, SwPoint& to)
     assert(border);
 
     //close current open path if any?
-    if (border->start >= 0)
-        _borderClose(border, false);
+    if (border->start >= 0) _borderClose(border, false);
 
     border->start = border->ptsCnt;
     border->movable = false;
@@ -318,8 +318,11 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength)
         border->movable = false;
     } else {
         //compute median angle
-        delta = {mathDivide(stroke.width, mathCos(theta)), 0};
-        mathRotate(delta, stroke.angleIn + theta + rotate);
+        auto phi = stroke.angleIn + theta;
+        auto thcos = mathCos(theta);
+        auto length = mathDivide(stroke.width, thcos);
+        delta = {length, 0};
+        mathRotate(delta, phi + rotate);
         delta += stroke.center;
     }
 
@@ -652,11 +655,9 @@ static void _addReverseLeft(SwStroke& stroke, bool opened)
 
 static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened)
 {
-    cout << "stroke opened? = " << opened << endl;
-
     /* We cannot process the first point because there is not enought
        information regarding its corner/cap. Later, it will be processed
-       in the _strokeEndSubPath() */
+       in the _endSubPath() */
 
     stroke.firstPt = true;
     stroke.center = to;
@@ -712,13 +713,13 @@ static void _endSubPath(SwStroke& stroke)
         if (turn != 0) {
 
             //when we turn to the right, the inside is 0
-            auto inside = 0;
+            int32_t inside = 0;
 
             //otherwise, the inside is 1
             if (turn < 0) inside = 1;
 
             _inside(stroke, inside, stroke.subPathLineLength);        //inside
-            _inside(stroke, 1 - inside, stroke.subPathLineLength);    //outside
+            _outside(stroke, 1 - inside, stroke.subPathLineLength);   //outside
         }
 
         _borderClose(stroke.borders + 0, false);
@@ -727,14 +728,81 @@ static void _endSubPath(SwStroke& stroke)
 }
 
 
-static void _deleteRle(SwStroke& stroke)
+static void _getCounts(SwStrokeBorder* border, uint32_t& ptsCnt, uint32_t& cntrsCnt)
+{
+    assert(border);
+
+    auto count = border->ptsCnt;
+    auto tags = border->tags;
+    uint32_t _ptsCnt = 0;
+    uint32_t _cntrsCnt = 0;
+    bool inCntr = false;
+
+    while (count > 0) {
+
+        if (tags[0] & SW_STROKE_TAG_BEGIN) {
+            if (inCntr) goto fail;
+            inCntr = true;
+        } else if (!inCntr) goto fail;
+
+        if (tags[0] & SW_STROKE_TAG_END) {
+            inCntr = false;
+            ++_cntrsCnt;
+        }
+        --count;
+        ++_ptsCnt;
+        ++tags;
+    }
+
+    if (inCntr) goto fail;
+    border->valid = true;
+    ptsCnt = _ptsCnt;
+    cntrsCnt = _cntrsCnt;
+
+    return;
+
+fail:
+    ptsCnt = 0;
+    cntrsCnt = 0;
+}
+
+
+static void _exportBorderOutline(SwStroke& stroke, SwOutline* outline, uint32_t side)
 {
-    if (!stroke.rle) return;
-    if (stroke.rle->spans) free(stroke.rle->spans);
-    free(stroke.rle);
-    stroke.rle = nullptr;
+    auto border = stroke.borders + side;
+    assert(border);
+
+    if (!border->valid) return;
+
+    memcpy(outline->pts + outline->ptsCnt, border->pts, border->ptsCnt * sizeof(SwPoint));
+
+    auto cnt = border->ptsCnt;
+    auto src = border->tags;
+    auto tags = outline->types + outline->ptsCnt;
+    auto cntrs = outline->cntrs + outline->cntrsCnt;
+    uint16_t idx = outline->ptsCnt;
+
+    while (cnt > 0) {
+
+        if (*src & SW_STROKE_TAG_POINT) *tags = SW_CURVE_TYPE_POINT;
+        else if (*src & SW_STROKE_TAG_CUBIC) *tags = SW_CURVE_TYPE_CUBIC;
+        else cout << "what type of stroke outline??" << endl;
+
+        if (*src & SW_STROKE_TAG_END) {
+            *cntrs = idx;
+            ++cntrs;
+            ++outline->cntrsCnt;
+        }
+
+        ++src;
+        ++tags;
+        ++idx;
+        --cnt;
+    }
+    outline->ptsCnt = outline->ptsCnt + border->ptsCnt;
 }
 
+
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
@@ -742,16 +810,20 @@ static void _deleteRle(SwStroke& stroke)
 void strokeFree(SwStroke* stroke)
 {
     if (!stroke) return;
-    _deleteRle(*stroke);
+
+    //free borders
+    if (stroke->borders[0].pts) free(stroke->borders[0].pts);
+    if (stroke->borders[0].tags) free(stroke->borders[0].tags);
+    if (stroke->borders[1].pts) free(stroke->borders[1].pts);
+    if (stroke->borders[1].tags) free(stroke->borders[1].tags);
+
     free(stroke);
 }
 
 
 void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join)
 {
-    _deleteRle(stroke);
-
-    stroke.width = TO_SWCOORD(width * 0.5f);
+    stroke.width = TO_SWCOORD(width * 0.5);
     stroke.cap = cap;
 
     //Save line join: it can be temporarily changed when stroking curves...
@@ -826,4 +898,33 @@ bool strokeParseOutline(SwStroke& stroke, SwOutline& outline)
 }
 
 
+SwOutline* strokeExportOutline(SwStroke& stroke)
+{
+    uint32_t count1, count2, count3, count4;
+
+    _getCounts(stroke.borders + 0, count1, count2);
+    _getCounts(stroke.borders + 1, count3, count4);
+
+    auto ptsCnt = count1 + count3;
+    auto cntrsCnt = count2 + count4;
+
+    auto outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
+    assert(outline);
+
+    outline->pts = static_cast<SwPoint*>(malloc(sizeof(SwPoint) * ptsCnt));
+    assert(outline->pts);
+
+    outline->types = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * ptsCnt));
+    assert(outline->types);
+
+    outline->cntrs = static_cast<uint32_t*>(malloc(sizeof(uint32_t) * cntrsCnt));
+    assert(outline->cntrs);
+
+    _exportBorderOutline(stroke, outline, 0);  //left
+    _exportBorderOutline(stroke, outline, 1);  //right
+
+    return outline;
+}
+
+
 #endif /* _TVG_SW_STROKER_H_ */
index 1f865d6..d978b6f 100644 (file)
@@ -23,11 +23,10 @@ void tvgtest()
 
     //Prepare a Shape (Rectangle + Rectangle + Circle + Circle)
     auto shape1 = tvg::Shape::gen();
-    shape1->appendRect(0, 0, 200, 200, 0);          //x, y, w, h, cornerRadius
+    shape1->appendRect(50, 50, 200, 200, 0);        //x, y, w, h, cornerRadius
     shape1->appendRect(100, 100, 300, 300, 100);    //x, y, w, h, cornerRadius
     shape1->appendCircle(400, 400, 100, 100);       //cx, cy, radiusW, radiusH
-    shape1->appendCircle(400, 500, 170, 100);       //cx, cy, radiusW, radiusH
-    shape1->fill(255, 255, 0, 255);                 //r, g, b, a
+    shape1->fill(50, 50, 50, 255);                  //r, g, b, a
 
     //Stroke Style
     shape1->stroke(255, 255, 255, 255);   //color: r, g, b, a