sw_engine: implement line and curve raster 67/231167/6
authorHermet Park <chuneon.park@samsung.com>
Sat, 18 Apr 2020 04:48:37 +0000 (13:48 +0900)
committerHermet Park <chuneon.park@samsung.com>
Sat, 18 Apr 2020 10:56:10 +0000 (19:56 +0900)
Change-Id: I22a77892544cd510cfe646aee60093cebb848806

13 files changed:
inc/tizenvg.h
src/lib/gl_engine/tvgGlEngine.cpp
src/lib/gl_engine/tvgGlEngine.h
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwEngine.cpp
src/lib/sw_engine/tvgSwEngine.h
src/lib/sw_engine/tvgSwRle.cpp
src/lib/sw_engine/tvgSwShape.cpp
src/lib/tvgCanvasBase.h
src/lib/tvgCommon.h
src/lib/tvgSceneNode.cpp
src/lib/tvgShapeNode.cpp
src/lib/tvgSwCanvas.cpp

index 2c43a85..e9f49d3 100644 (file)
@@ -73,6 +73,7 @@ class TIZENVG_EXPORT PaintNode
 {
 public:
     virtual ~PaintNode() {}
+    virtual int dispose(RasterMethod* engine) = 0;
     virtual int update(RasterMethod* engine) = 0;
 };
 
@@ -90,6 +91,7 @@ class TIZENVG_EXPORT ShapeNode final : public PaintNode
 public:
     ~ShapeNode();
 
+    int dispose(RasterMethod* engine) noexcept override;
     int update(RasterMethod* engine) noexcept override;
     int clear() noexcept;
 
@@ -121,6 +123,7 @@ class TIZENVG_EXPORT SceneNode final : public PaintNode
 public:
     ~SceneNode();
 
+    int dispose(RasterMethod* engine) noexcept override;
     int update(RasterMethod* engine) noexcept override;
 
     int push(std::unique_ptr<ShapeNode> shape) noexcept;
index 9280e34..65a5ce3 100644 (file)
 #include "tvgCommon.h"
 #include "tvgGlEngine.h"
 
+/************************************************************************/
+/* Internal Class Implementation                                        */
+/************************************************************************/
 
-static GlEngine* pInst = nullptr;
+static RasterMethodInit engineInit;
 
 struct GlShape
 {
     //TODO:
 };
 
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+void* GlEngine::dispose(const ShapeNode& shape, void *data)
+{
+    GlShape* sdata = static_cast<GlShape*>(data);
+    if (!sdata) return nullptr;
+    free(sdata);
+    return nullptr;
+}
+
 
 void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
 {
@@ -37,35 +52,37 @@ void* GlEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
         sdata = static_cast<GlShape*>(calloc(1, sizeof(GlShape)));
         assert(sdata);
     }
-
     return sdata;
 }
 
 
 int GlEngine::init()
 {
-    if (pInst) return -1;
-    pInst = new GlEngine();
-    assert(pInst);
-
-    return 0;
+    return RasterMethodInit::init(engineInit, new GlEngine);
 }
 
 
 int GlEngine::term()
 {
-    if (!pInst) return -1;
-    cout << "GlEngine(" << pInst << ") destroyed!" << endl;
-    delete(pInst);
-    pInst = nullptr;
-    return 0;
+    return RasterMethodInit::term(engineInit);
+}
+
+
+size_t GlEngine::unref()
+{
+    return RasterMethodInit::unref(engineInit);
+}
+
+
+size_t GlEngine::ref()
+{
+    return RasterMethodInit::ref(engineInit);
 }
 
 
 GlEngine* GlEngine::inst()
 {
-    assert(pInst);
-    return pInst;
+    return dynamic_cast<GlEngine*>(RasterMethodInit::inst(engineInit));
 }
 
 
index bad5214..ebd1fd5 100644 (file)
@@ -24,6 +24,10 @@ class GlEngine : public RasterMethod
 {
 public:
     void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
+    void* dispose(const ShapeNode& shape, void *data) override;
+    size_t ref() override;
+    size_t unref() override;
+
     static GlEngine* inst();
     static int init();
     static int term();
index 576a0b8..4e75e3c 100644 (file)
@@ -23,6 +23,8 @@ using namespace tvg;
 
 constexpr auto SW_CURVE_TAG_ON = 1;
 constexpr auto SW_CURVE_TAG_CUBIC = 2;
+constexpr auto SW_OUTLINE_FILL_WINDING = 0;
+constexpr auto SW_OUTLINE_FILL_EVEN_ODD = 1;
 
 using SwCoord = signed long;
 
@@ -56,43 +58,41 @@ struct SwOutline
     size_t      ptsCnt;           //number of points in the glyph
     size_t      reservedPtsCnt;
     char*       tags;             //the points flags
-    size_t      flags;            //outline masks
+    uint8_t     fillMode;         //outline fill mode
 };
 
 struct SwSpan
 {
-    size_t x;
-    size_t y;
-    size_t len;
+    uint16_t x, y;
+    uint16_t len;
     uint8_t coverage;
 };
 
 struct SwRleData
 {
+    SwSpan *spans;
     size_t alloc;
     size_t size;
-    SwSpan *spans;
 };
 
 struct SwBBox
 {
-    SwPoint min;
-    SwPoint max;
+    SwPoint min, max;
 };
 
 struct SwShape
 {
     SwOutline*   outline;
-    SwRleData    rle;
+    SwRleData*   rle;
     SwBBox       bbox;
 };
 
+void shapeReset(SwShape& sdata);
 bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
 void shapeDelOutline(const ShapeNode& shape, SwShape& sdata);
 bool shapeGenRle(const ShapeNode& shape, SwShape& sdata);
-void shapeDelRle(const ShapeNode& shape, SwShape& sdata);
 bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata);
 
-bool rleRender(SwShape& sdata);
+SwRleData* rleRender(const SwShape& sdata);
 
 #endif /* _TVG_SW_COMMON_H_ */
index a6ae3e7..683bffa 100644 (file)
 /* Internal Class Implementation                                        */
 /************************************************************************/
 
-static SwEngine* pInst = nullptr;
+static RasterMethodInit engineInit;
 
 
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
 
+void* SwEngine::dispose(const ShapeNode& shape, void *data)
+{
+    SwShape* sdata = static_cast<SwShape*>(data);
+    if (!sdata) return nullptr;
+    shapeReset(*sdata);
+    free(sdata);
+    return nullptr;
+}
+
 void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
 {
     //prepare shape data
@@ -48,11 +57,11 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
     if (alpha == 0) return sdata;
 
     if (flags & UpdateFlag::Path) {
+        shapeReset(*sdata);
         if (!shapeGenOutline(shape, *sdata)) return sdata;
         //TODO: From below sequence starts threading?
         if (!shapeTransformOutline(shape, *sdata)) return sdata;
         if (!shapeGenRle(shape, *sdata)) return sdata;
-        shapeDelOutline(shape, *sdata);
     }
 
     return sdata;
@@ -61,28 +70,31 @@ void* SwEngine::prepare(const ShapeNode& shape, void* data, UpdateFlag flags)
 
 int SwEngine::init()
 {
-    if (pInst) return -1;
-    pInst = new SwEngine();
-    assert(pInst);
-
-    return 0;
+    return RasterMethodInit::init(engineInit, new SwEngine);
 }
 
 
 int SwEngine::term()
 {
-    if (!pInst) return -1;
-    cout << "SwEngine(" << pInst << ") destroyed!" << endl;
-    delete(pInst);
-    pInst = nullptr;
-    return 0;
+    return RasterMethodInit::term(engineInit);
+}
+
+
+size_t SwEngine::unref()
+{
+    return RasterMethodInit::unref(engineInit);
+}
+
+
+size_t SwEngine::ref()
+{
+    return RasterMethodInit::ref(engineInit);
 }
 
 
 SwEngine* SwEngine::inst()
 {
-    assert(pInst);
-    return pInst;
+    return dynamic_cast<SwEngine*>(RasterMethodInit::inst(engineInit));
 }
 
 
index 4185352..dd2d401 100644 (file)
@@ -21,6 +21,10 @@ class SwEngine : public RasterMethod
 {
 public:
     void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) override;
+    void* dispose(const ShapeNode& shape, void *data) override;
+    size_t ref() override;
+    size_t unref() override;
+
     static SwEngine* inst();
     static int init();
     static int term();
index f8292c6..25b9c03 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <setjmp.h>
 #include <limits.h>
+#include <memory.h>
 #include "tvgSwCommon.h"
 
 /************************************************************************/
@@ -29,7 +30,6 @@ constexpr auto MAX_SPANS = 256;
 constexpr auto PIXEL_BITS = 8;   //must be at least 6 bits!
 constexpr auto ONE_PIXEL = (1L << PIXEL_BITS);
 
-
 using Area = long;
 
 struct Band
@@ -47,6 +47,8 @@ struct Cell
 
 struct RleWorker
 {
+    SwRleData* rle;
+
     SwPoint cellPos;
     SwPoint cellMin;
     SwPoint cellMax;
@@ -100,13 +102,19 @@ static inline SwPoint DOWNSCALE(const SwPoint& pt)
 
 static inline SwPoint TRUNC(const SwPoint& pt)
 {
-    return  { pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS };
+    return  {pt.x >> PIXEL_BITS, pt.y >> PIXEL_BITS};
+}
+
+
+static inline SwCoord TRUNC(const SwCoord x)
+{
+    return  x >> PIXEL_BITS;
 }
 
 
 static inline SwPoint SUBPIXELS(const SwPoint& pt)
 {
-    return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS };
+    return {pt.x << PIXEL_BITS, pt.y << PIXEL_BITS};
 }
 
 
@@ -115,20 +123,105 @@ static inline SwCoord SUBPIXELS(const SwCoord x)
     return (x << PIXEL_BITS);
 }
 
+/*
+ *  Approximate sqrt(x*x+y*y) using the `alpha max plus beta min'
+ *  algorithm.  We use alpha = 1, beta = 3/8, giving us results with a
+ *  largest error less than 7% compared to the exact value.
+ */
+static inline SwCoord HYPOT(SwPoint pt)
+{
+    if (pt.x < 0) pt.x = -pt.x;
+    if (pt.y < 0) pt.y = -pt.y;
+    return ((pt.x > pt.y) ? (pt.x + (3 * pt.y >> 3)) : (pt.y + (3 * pt.x >> 3)));
+}
 
-static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
+static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count)
 {
-    //TODO:
+    assert(rle && spans);
+
+    auto newSize = rle->size + count;
+
+    /* allocate enough memory for new spans */
+    /* alloc is required to prevent free and reallocation */
+    /* when the rle needs to be regenerated because of attribute change. */
+    if (rle->alloc < newSize) {
+        rle->spans = static_cast<SwSpan*>(realloc(rle->spans, newSize * sizeof(SwSpan)));
+        assert(rle->spans);
+        rle->alloc = newSize;
+    }
+
+    //copy the new spans to the allocated memory
+    SwSpan* lastSpan = rle->spans + rle->size;
+    assert(lastSpan);
+    memcpy(lastSpan, spans, count * sizeof(SwSpan));
+
+    rle->size = newSize;
 }
 
 
-static void genSpan(RleWorker& rw)
+static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount)
 {
-    //TODO:
+    /* compute the coverage line's coverage, depending on the outline fill rule */
+    /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
+    auto coverage = static_cast<int>(area >> (PIXEL_BITS * 2 + 1 - 8));    //range 0 - 256
+
+    if (coverage < 0) coverage = -coverage;
+
+    if (rw.outline->fillMode == SW_OUTLINE_FILL_EVEN_ODD) {
+        coverage &= 511;
+        if (coverage > 256) coverage = 512 - coverage;
+        else if (coverage == 256) coverage = 255;
+    } else {
+        //normal non-zero winding rule
+        if (coverage >= 256) coverage = 255;
+    }
+
+    x += rw.cellMin.x;
+    y += rw.cellMin.y;
+
+    //span has ushort coordinates. check limit overflow
+    if (x >= SHRT_MAX) {
+        cout << "x(" << x << ") coordinate overflow!" <<  endl;
+        x = SHRT_MAX;
+    }
+    if (y >= SHRT_MAX) {
+        cout << "y(" << y << ") coordinate overflow!" <<  endl;
+        y = SHRT_MAX;
+    }
+
+    if (coverage) {
+        auto count = rw.spansCnt;
+        auto span = rw.spans + count - 1;
+        assert(span);
+
+        //see whether we can add this span to the current list
+        if ((count > 0) && (rw.ySpan == y) &&
+            (span->x + span->len == x) && (span->coverage == coverage)) {
+                span->len = span->len + acount;
+            return;
+        }
+
+        if (count >=  MAX_SPANS) {
+            _genSpan(rw.rle, rw.spans, count);
+            rw.spansCnt = 0;
+            span = rw.spans;
+            assert(span);
+        } else {
+            ++span;
+            assert(span);
+        }
+
+        //add a span to the current list
+        span->x = x;
+        span->y = y;
+        span->len = acount;
+        span->coverage = coverage;
+        ++rw.spansCnt;
+    }
 }
 
 
-static void sweep(RleWorker& rw)
+static void _sweep(RleWorker& rw)
 {
     if (rw.cellsCnt == 0) return;
 
@@ -142,26 +235,26 @@ static void sweep(RleWorker& rw)
 
         while (cell) {
 
-            horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x);
+            _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x);
             cover += cell->cover;
             auto area = cover * (ONE_PIXEL * 2) - cell->area;
 
             if (area != 0 && cell->x >= 0)
-                horizLine(rw, cell->x, y, area, 1);
+                _horizLine(rw, cell->x, y, area, 1);
 
             x = cell->x + 1;
             cell = cell->next;
         }
 
         if (cover != 0)
-            horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
+            _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x);
     }
 
-    if (rw.spansCnt > 0) genSpan(rw);
+    if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt);
 }
 
 
-static Cell* findCell(RleWorker& rw)
+static Cell* _findCell(RleWorker& rw)
 {
     auto x = rw.cellPos.x;
     if (x > rw.cellXCnt) x = rw.cellXCnt;
@@ -190,17 +283,18 @@ static Cell* findCell(RleWorker& rw)
 }
 
 
-static void recordCell(RleWorker& rw)
+static void _recordCell(RleWorker& rw)
 {
     if (rw.area | rw.cover) {
-        auto cell = findCell(rw);
+        auto cell = _findCell(rw);
         assert(cell);
         cell->area += rw.area;
         cell->cover += rw.cover;
     }
 }
 
-static void setCell(RleWorker& rw, SwPoint pos)
+
+static void _setCell(RleWorker& rw, SwPoint pos)
 {
     /* Move the cell pointer to a new position.  We set the `invalid'      */
     /* flag to indicate that the cell isn't part of those we're interested */
@@ -222,7 +316,7 @@ static void setCell(RleWorker& rw, SwPoint pos)
 
     //Are we moving to a different cell?
     if (pos != rw.cellPos) {
-        if (!rw.invalid) recordCell(rw);
+        if (!rw.invalid) _recordCell(rw);
     }
 
     rw.area = 0;
@@ -232,7 +326,7 @@ static void setCell(RleWorker& rw, SwPoint pos)
 }
 
 
-static void startCell(RleWorker& rw, SwPoint pos)
+static void _startCell(RleWorker& rw, SwPoint pos)
 {
     if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
     if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x;
@@ -242,23 +336,23 @@ static void startCell(RleWorker& rw, SwPoint pos)
     rw.cellPos = pos - rw.cellMin;
     rw.invalid = false;
 
-    setCell(rw, pos);
+    _setCell(rw, pos);
 }
 
 
-static void moveTo(RleWorker& rw, const SwPoint& to)
+static void _moveTo(RleWorker& rw, const SwPoint& to)
 {
     //record current cell, if any */
-    if (!rw.invalid) recordCell(rw);
+    if (!rw.invalid) _recordCell(rw);
 
     //start to a new position
-    startCell(rw, TRUNC(to));
+    _startCell(rw, TRUNC(to));
 
     rw.pos = to;
 }
 
 
-static void lineTo(RleWorker& rw, const SwPoint& to)
+static void _lineTo(RleWorker& rw, const SwPoint& to)
 {
 #define SW_UDIV(a, b) \
     static_cast<SwCoord>(((unsigned long)(a) * (unsigned long)(b)) >> \
@@ -284,7 +378,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
     //any horizontal line
     } else if (diff.y == 0) {
         e1.x = e2.x;
-        setCell(rw, e1);
+        _setCell(rw, e1);
     } else if (diff.x == 0) {
         //vertical line up
         if (diff.y > 0) {
@@ -294,7 +388,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
                 rw.area += (f2.y - f1.y) * f1.x * 2;
                 f1.y = 0;
                 ++e1.y;
-                setCell(rw, e1);
+                _setCell(rw, e1);
             } while(e1.y != e2.y);
         //vertical line down
         } else {
@@ -304,7 +398,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
                 rw.area += (f2.y - f1.y) * f1.x * 2;
                 f1.y = ONE_PIXEL;
                 --e1.y;
-                setCell(rw, e1);
+                _setCell(rw, e1);
             } while(e1.y != e2.y);
         }
     //any other line
@@ -357,7 +451,7 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
                 --e1.y;
             }
 
-            setCell(rw, e1);
+            _setCell(rw, e1);
 
         } while(e1 != e2);
     }
@@ -369,21 +463,111 @@ static void lineTo(RleWorker& rw, const SwPoint& to)
 }
 
 
-static bool renderCubic(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
+static void _splitCubic(SwPoint* base)
 {
-    return true;
+    assert(base);
+
+    SwCoord a, b, c, d;
+
+    base[6].x = base[3].x;
+    c = base[1].x;
+    d = base[2].x;
+    base[1].x = a = (base[0].x + c) / 2;
+    base[5].x = b = (base[3].x + d) / 2;
+    c = (c + d) / 2;
+    base[2].x = a = (a + c) / 2;
+    base[4].x = b = (b + c) / 2;
+    base[3].x = (a + b) / 2;
+
+    base[6].y = base[3].y;
+    c = base[1].y;
+    d = base[2].y;
+    base[1].y = a = (base[0].y + c) / 2;
+    base[5].y = b = (base[3].y + d) / 2;
+    c = (c + d) / 2;
+    base[2].y = a = (a + c) / 2;
+    base[4].y = b = (b + c) / 2;
+    base[3].y = (a + b) / 2;
 }
 
 
-static bool cubicTo(RleWorker& rw, SwPoint& ctrl1, SwPoint& ctrl2, SwPoint& to)
+static void _cubicTo(RleWorker& rw, const SwPoint& ctrl1, const SwPoint& ctrl2, const SwPoint& to)
 {
-    return renderCubic(rw, ctrl1, ctrl2, to);
+    auto arc = rw.bezStack;
+    assert(arc);
+
+    arc[0] = to;
+    arc[1] = ctrl2;
+    arc[2] = ctrl1;
+    arc[3] = rw.pos;
+
+    //Short-cut the arc that crosses the current band
+    auto min = arc[0].y;
+    auto max = arc[0].y;
+
+    SwCoord y;
+    for (auto i = 1; i < 4; ++i) {
+        y = arc[i].y;
+        if (y < min) min = y;
+        if (y > max) max = y;
+    }
+
+    if (TRUNC(min) >= rw.cellMax.y || TRUNC(max) < rw.cellMin.y) goto draw;
+
+    /* Decide whether to split or draw. See `Rapid Termination          */
+    /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
+    /* F. Hain, at                                                      */
+    /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
+    while (true) {
+        {
+            //diff is the P0 - P3 chord vector
+            auto diff = arc[3] - arc[0];
+            auto L = HYPOT(diff);
+
+            //avoid possible arithmetic overflow below by splitting
+            if (L > SHRT_MAX) goto split;
+
+            //max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1)
+            auto sLimit = L * (ONE_PIXEL / 6);
+
+            auto diff1 = arc[1] - arc[0];
+            auto s = diff.y * diff1.x - diff.x * diff1.y;
+            if (s < 0) s = -s;
+            if (s > sLimit) goto split;
+
+            //s is L * the perpendicular distance from P2 to the line P0 - P3
+            auto diff2 = arc[2] - arc[0];
+            s = diff.y * diff2.x - diff.x * diff2.y;
+            if (s < 0) s = -s;
+            if (s > sLimit) goto split;
+
+            /* Split super curvy segments where the off points are so far
+            from the chord that the angles P0-P1-P3 or P0-P2-P3 become
+            acute as detected by appropriate dot products */
+            if (diff1.x * (diff1.x - diff.x) + diff1.y * (diff1.y - diff.y) > 0 ||
+                diff2.x * (diff2.x - diff.x) + diff2.y * (diff2.y - diff.y) > 0)
+                goto split;
+
+            //no reason to split
+            goto draw;
+        }
+    split:
+        _splitCubic(arc);
+        arc += 3;
+        continue;
+
+    draw:
+        _lineTo(rw, arc[0]);
+
+        if (arc == rw.bezStack) return;
+
+        arc -= 3;
+    }
 }
 
 
-static bool decomposeOutline(RleWorker& rw)
+static bool _decomposeOutline(RleWorker& rw)
 {
- //   printf("decomposOutline\n");
     auto outline = rw.outline;
     assert(outline);
 
@@ -402,7 +586,7 @@ static bool decomposeOutline(RleWorker& rw)
         /* A contour cannot start with a cubic control point! */
         if (tags[0] == SW_CURVE_TAG_CUBIC) goto invalid_outline;
 
-        moveTo(rw, UPSCALE(outline->pts[first]));
+        _moveTo(rw, UPSCALE(outline->pts[first]));
 
         while (pt < limit) {
             assert(++pt);
@@ -410,7 +594,7 @@ static bool decomposeOutline(RleWorker& rw)
 
             //emit a single line_to
             if (tags[0] == SW_CURVE_TAG_ON) {
-                lineTo(rw, UPSCALE(*pt));
+                _lineTo(rw, UPSCALE(*pt));
             //tag cubic
             } else {
                 if (pt + 1 > limit || tags[1] != SW_CURVE_TAG_CUBIC)
@@ -420,10 +604,10 @@ static bool decomposeOutline(RleWorker& rw)
                 tags += 2;
 
                 if (pt <= limit) {
-                    if (!cubicTo(rw, pt[-2], pt[-1], pt[0])) return false;
+                    _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(pt[0]));
                     continue;
                 }
-                if (!cubicTo(rw, pt[-2], pt[-1], outline->pts[first])) return false;
+                _cubicTo(rw, UPSCALE(pt[-2]), UPSCALE(pt[-1]), UPSCALE(outline->pts[first]));
                 goto close;
             }
         }
@@ -442,13 +626,13 @@ invalid_outline:
 }
 
 
-static bool genRle(RleWorker& rw)
+static bool _genRle(RleWorker& rw)
 {
     bool ret = false;
 
     if (setjmp(rw.jmpBuf) == 0) {
-        ret = decomposeOutline(rw);
-        if (!rw.invalid)  recordCell(rw);
+        ret = _decomposeOutline(rw);
+        if (!rw.invalid) _recordCell(rw);
     } else {
         cout <<  "Memory Overflow" << endl;
     }
@@ -460,7 +644,7 @@ static bool genRle(RleWorker& rw)
 /* External Class Implementation                                        */
 /************************************************************************/
 
-bool rleRender(SwShape& sdata)
+SwRleData* rleRender(const SwShape& sdata)
 {
     constexpr auto RENDER_POOL_SIZE = 16384L;
     constexpr auto BAND_SIZE = 39;
@@ -468,7 +652,7 @@ bool rleRender(SwShape& sdata)
     auto outline = sdata.outline;
     assert(outline);
 
-    if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false;
+    if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr;
 
     assert(outline->cntrs && outline->pts);
     assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
@@ -494,6 +678,9 @@ bool rleRender(SwShape& sdata)
     rw.outline = outline;
     rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8);  //bandSize: 64
     rw.bandShoot = 0;
+    rw.rle = reinterpret_cast<SwRleData*>(calloc(1, sizeof(SwRleData)));
+    assert(rw.rle);
+
     //printf("bufferSize = %d, bbox(%f %f %f %f), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.exMin, rw.eyMin, rw.exMax, rw.eyMax, rw.exCnt, rw.eyCnt, rw.bandSize);
 
     //Generate RLE
@@ -547,9 +734,9 @@ bool rleRender(SwShape& sdata)
             rw.cellMax.y = band->max;
             rw.cellYCnt = band->max - band->min;
 
-            if (!genRle(rw)) return -1;
+            if (!_genRle(rw)) goto error;
 
-            sweep(rw);
+            _sweep(rw);
             --band;
             continue;
 
@@ -561,7 +748,7 @@ bool rleRender(SwShape& sdata)
 
             /* This is too complex for a single scanline; there must
                be some problems */
-            if (middle == bottom) return -1;
+            if (middle == bottom) goto error;
 
             if (bottom - top >= rw.bandSize) ++rw.bandShoot;
 
@@ -576,7 +763,12 @@ bool rleRender(SwShape& sdata)
     if (rw.bandShoot > 8 && rw.bandSize > 16)
         rw.bandSize = (rw.bandSize >> 1);
 
-    return true;
+    return rw.rle;
+
+error:
+    free(rw.rle);
+    rw.rle = nullptr;
+    return nullptr;
 }
 
 #endif /* _TVG_SW_RLE_H_ */
index 0f2a6fa..e725e30 100644 (file)
@@ -29,7 +29,7 @@ static inline SwPoint TO_SWPOINT(const Point* pt)
 }
 
 
-static void growOutlineContour(SwOutline& outline, size_t n)
+static void _growOutlineContour(SwOutline& outline, size_t n)
 {
     if (n == 0) {
         free(outline.cntrs);
@@ -40,14 +40,14 @@ static void growOutlineContour(SwOutline& outline, size_t n)
     }
     if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
 
-    cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
+    //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;;
     outline.reservedCntrsCnt = n;
     outline.cntrs = static_cast<size_t*>(realloc(outline.cntrs, n * sizeof(size_t)));
     assert(outline.cntrs);
 }
 
 
-static void growOutlinePoint(SwOutline& outline, size_t n)
+static void _growOutlinePoint(SwOutline& outline, size_t n)
 {
     if (n == 0) {
         free(outline.pts);
@@ -61,7 +61,7 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
 
     if (outline.reservedPtsCnt >= outline.ptsCnt + n) return;
 
-    cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
+    //cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl;
     outline.reservedPtsCnt = n;
     outline.pts = static_cast<SwPoint*>(realloc(outline.pts, n * sizeof(SwPoint)));
     assert(outline.pts);
@@ -70,9 +70,9 @@ static void growOutlinePoint(SwOutline& outline, size_t n)
 }
 
 
-static void outlineEnd(SwOutline& outline)
+static void _outlineEnd(SwOutline& outline)
 {
-    growOutlineContour(outline, 1);
+    _growOutlineContour(outline, 1);
     if (outline.ptsCnt > 0) {
         outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
         ++outline.cntrsCnt;
@@ -80,17 +80,17 @@ static void outlineEnd(SwOutline& outline)
 }
 
 
-static void outlineMoveTo(SwOutline& outline, const Point* to)
+static void _outlineMoveTo(SwOutline& outline, const Point* to)
 {
     assert(to);
 
-    growOutlinePoint(outline, 1);
+    _growOutlinePoint(outline, 1);
 
     outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
 
     if (outline.ptsCnt > 0) {
-        growOutlineContour(outline, 1);
+        _growOutlineContour(outline, 1);
         outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
         ++outline.cntrsCnt;
     }
@@ -99,11 +99,11 @@ static void outlineMoveTo(SwOutline& outline, const Point* to)
 }
 
 
-static void outlineLineTo(SwOutline& outline, const Point* to)
+static void _outlineLineTo(SwOutline& outline, const Point* to)
 {
     assert(to);
 
-    growOutlinePoint(outline, 1);
+    _growOutlinePoint(outline, 1);
 
     outline.pts[outline.ptsCnt] = TO_SWPOINT(to);
     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
@@ -112,11 +112,11 @@ static void outlineLineTo(SwOutline& outline, const Point* to)
 }
 
 
-static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
+static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to)
 {
     assert(ctrl1 && ctrl2 && to);
 
-    growOutlinePoint(outline, 3);
+    _growOutlinePoint(outline, 3);
 
     outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1);
     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_CUBIC;
@@ -132,7 +132,7 @@ static void outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point*
 }
 
 
-static bool outlineClose(SwOutline& outline)
+static bool _outlineClose(SwOutline& outline)
 {
     size_t i = 0;
 
@@ -146,7 +146,7 @@ static bool outlineClose(SwOutline& outline)
     if (outline.ptsCnt == i) return false;
 
     //Close the path
-    growOutlinePoint(outline, 1);
+    _growOutlinePoint(outline, 1);
 
     outline.pts[outline.ptsCnt] = outline.pts[i];
     outline.tags[outline.ptsCnt] = SW_CURVE_TAG_ON;
@@ -156,14 +156,14 @@ static bool outlineClose(SwOutline& outline)
 }
 
 
-static void initBBox(SwShape& sdata)
+static void _initBBox(SwShape& sdata)
 {
     sdata.bbox.min.x = sdata.bbox.min.y = 0;
     sdata.bbox.max.x = sdata.bbox.max.y = 0;
 }
 
 
-static bool updateBBox(SwShape& sdata)
+static bool _updateBBox(SwShape& sdata)
 {
     auto outline = sdata.outline;
     assert(outline);
@@ -172,7 +172,7 @@ static bool updateBBox(SwShape& sdata)
     assert(pt);
 
     if (outline->ptsCnt <= 0) {
-        initBBox(sdata);
+        _initBBox(sdata);
         return false;
     }
 
@@ -201,6 +201,29 @@ static bool updateBBox(SwShape& sdata)
 }
 
 
+void _deleteRle(SwShape& sdata)
+{
+    if (sdata.rle) {
+        if (sdata.rle->spans) free(sdata.rle->spans);
+        free(sdata.rle);
+    }
+    sdata.rle = nullptr;
+}
+
+
+void _deleteOutline(SwShape& sdata)
+{
+    if (!sdata.outline) return;
+
+    SwOutline* outline = sdata.outline;
+    if (outline->cntrs) free(outline->cntrs);
+    if (outline->pts) free(outline->pts);
+    if (outline->tags) free(outline->tags);
+    free(outline);
+
+    sdata.outline = nullptr;
+}
+
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
@@ -212,39 +235,27 @@ bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata)
 }
 
 
-void shapeDelRle(const ShapeNode& shape, SwShape& sdata)
-{
-    if (sdata.rle.spans) free(sdata.rle.spans);
-    sdata.rle.spans = nullptr;
-}
-
-
 bool shapeGenRle(const ShapeNode& shape, SwShape& sdata)
 {
-    shapeDelRle(shape, sdata);
-    if (!updateBBox(sdata)) return false;
-    return rleRender(sdata);
+    if (!_updateBBox(sdata)) goto end;
+    sdata.rle = rleRender(sdata);
+    _deleteOutline(sdata);
+end:
+    if (sdata.rle) return true;
+    return false;
 }
 
 
-void shapeDelOutline(const ShapeNode& shape, SwShape& sdata)
+void shapeReset(SwShape& sdata)
 {
-    if (!sdata.outline) return;
-
-    SwOutline* outline = sdata.outline;
-    if (outline->cntrs) free(outline->cntrs);
-    if (outline->pts) free(outline->pts);
-    if (outline->tags) free(outline->tags);
-    free(outline);
-
-    sdata.outline = nullptr;
+    _deleteOutline(sdata);
+    _deleteRle(sdata);
+    _initBBox(sdata);
 }
 
 
 bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
 {
-    initBBox(sdata);
-
     const PathCommand* cmds = nullptr;
     auto cmdCnt = shape.pathCommands(&cmds);
 
@@ -257,7 +268,6 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
     //smart reservation
     auto outlinePtsCnt = 0;
     auto outlineCntrsCnt = 0;
-//    auto closed = false;
 
     for (auto i = 0; i < cmdCnt; ++i) {
         switch(*(cmds + i)) {
@@ -294,28 +304,28 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
     }
 
     //TODO: Probabry we can copy pts from shape directly.
-    growOutlinePoint(*outline, outlinePtsCnt);
-    growOutlineContour(*outline, outlineCntrsCnt);
+    _growOutlinePoint(*outline, outlinePtsCnt);
+    _growOutlineContour(*outline, outlineCntrsCnt);
 
     //Generate Outlines
     while (cmdCnt-- > 0) {
         switch(*cmds) {
             case PathCommand::Close: {
-                outlineClose(*outline);
+                _outlineClose(*outline);
                 break;
             }
             case PathCommand::MoveTo: {
-                outlineMoveTo(*outline, pts);
+                _outlineMoveTo(*outline, pts);
                 ++pts;
                 break;
             }
             case PathCommand::LineTo: {
-                outlineLineTo(*outline, pts);
+                _outlineLineTo(*outline, pts);
                 ++pts;
                 break;
             }
             case PathCommand::CubicTo: {
-                outlineCubicTo(*outline, pts, pts + 1, pts + 2);
+                _outlineCubicTo(*outline, pts, pts + 1, pts + 2);
                 pts += 3;
                 break;
             }
@@ -323,7 +333,7 @@ bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata)
         ++cmds;
     }
 
-    outlineEnd(*outline);
+    _outlineEnd(*outline);
 
     //FIXME:
     //outline->flags = SwOutline::FillRule::Winding;
index f200d29..3ec6c7a 100644 (file)
@@ -30,12 +30,13 @@ struct CanvasBase
 
     CanvasBase(RasterMethod *pRaster):raster(pRaster)
     {
-
+        raster->ref();
     }
 
     ~CanvasBase()
     {
        clear();
+       raster->unref();
     }
 
     int reserve(size_t n)
@@ -48,6 +49,7 @@ struct CanvasBase
     int clear()
     {
         for (auto node : nodes) {
+            node->dispose(raster);
             delete(node);
         }
         nodes.clear();
index e9dc249..fe2d8e2 100644 (file)
@@ -35,6 +35,67 @@ public:
     enum UpdateFlag { None = 0, Path = 1, Fill = 2, All = 3 };
     virtual ~RasterMethod() {}
     virtual void* prepare(const ShapeNode& shape, void* data, UpdateFlag flags) = 0;
+    virtual void* dispose(const ShapeNode& shape, void *data) = 0;
+    virtual size_t ref() = 0;
+    virtual size_t unref() = 0;
+};
+
+struct RasterMethodInit
+{
+    RasterMethod* pInst = nullptr;
+    size_t refCnt = 0;
+    bool initted = false;
+
+    static int init(RasterMethodInit& initter, RasterMethod* engine)
+    {
+        assert(engine);
+        if (initter.pInst || initter.refCnt > 0) return -1;
+        initter.pInst = engine;
+        initter.refCnt = 0;
+        initter.initted = true;
+        return 0;
+    }
+
+    static int term(RasterMethodInit& initter)
+    {
+        if (!initter.pInst || !initter.initted) return -1;
+
+        initter.initted = false;
+
+        //Still it's refered....
+        if (initter.refCnt > 0) return  0;
+        delete(initter.pInst);
+        initter.pInst = nullptr;
+
+        return 0;
+    }
+
+    static size_t unref(RasterMethodInit& initter)
+    {
+        assert(initter.refCnt > 0);
+        --initter.refCnt;
+
+        //engine has been requested to termination
+        if (!initter.initted && initter.refCnt == 0) {
+            if (initter.pInst) {
+                delete(initter.pInst);
+                initter.pInst = nullptr;
+            }
+        }
+        return initter.refCnt;
+    }
+
+    static RasterMethod* inst(RasterMethodInit& initter)
+    {
+        assert(initter.pInst);
+        return initter.pInst;
+    }
+
+    static size_t ref(RasterMethodInit& initter)
+    {
+        return ++initter.refCnt;
+    }
+
 };
 
 }
index 7c4bb58..93a9b21 100644 (file)
@@ -58,6 +58,13 @@ int SceneNode :: push(unique_ptr<ShapeNode> shape) noexcept
 }
 
 
+int SceneNode :: dispose(RasterMethod* engine) noexcept
+{
+
+    return 0;
+}
+
+
 int SceneNode :: update(RasterMethod* engine) noexcept
 {
 
index 81d97dd..f17021a 100644 (file)
@@ -84,6 +84,17 @@ unique_ptr<ShapeNode> ShapeNode::gen() noexcept
 }
 
 
+int ShapeNode :: dispose(RasterMethod* engine) noexcept
+{
+    auto impl = pImpl.get();
+    assert(impl);
+
+    impl->edata = engine->dispose(*this, impl->edata);
+    if (impl->edata) return -1;
+    return 0;
+}
+
+
 int ShapeNode :: update(RasterMethod* engine) noexcept
 {
     auto impl = pImpl.get();
index 995dac6..e85275f 100644 (file)
@@ -89,7 +89,7 @@ SwCanvas::SwCanvas() : pImpl(make_unique<Impl>())
 
 SwCanvas::~SwCanvas()
 {
-   cout << "SwCanvas(" << this << ") destroyed!" << endl;
+    cout << "SwCanvas(" << this << ") destroyed!" << endl;
 }