diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 2c43a85c..e9f49d37 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -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 shape) noexcept; diff --git a/src/lib/gl_engine/tvgGlEngine.cpp b/src/lib/gl_engine/tvgGlEngine.cpp index 9280e347..65a5ce33 100644 --- a/src/lib/gl_engine/tvgGlEngine.cpp +++ b/src/lib/gl_engine/tvgGlEngine.cpp @@ -20,14 +20,29 @@ #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(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(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(RasterMethodInit::inst(engineInit)); } diff --git a/src/lib/gl_engine/tvgGlEngine.h b/src/lib/gl_engine/tvgGlEngine.h index bad52149..ebd1fd54 100644 --- a/src/lib/gl_engine/tvgGlEngine.h +++ b/src/lib/gl_engine/tvgGlEngine.h @@ -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(); diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 576a0b83..4e75e3cd 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -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_ */ diff --git a/src/lib/sw_engine/tvgSwEngine.cpp b/src/lib/sw_engine/tvgSwEngine.cpp index a6ae3e78..683bffad 100644 --- a/src/lib/sw_engine/tvgSwEngine.cpp +++ b/src/lib/sw_engine/tvgSwEngine.cpp @@ -24,13 +24,22 @@ /* 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(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(RasterMethodInit::inst(engineInit)); } diff --git a/src/lib/sw_engine/tvgSwEngine.h b/src/lib/sw_engine/tvgSwEngine.h index 41853525..dd2d4015 100644 --- a/src/lib/sw_engine/tvgSwEngine.h +++ b/src/lib/sw_engine/tvgSwEngine.h @@ -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(); diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index f8292c61..25b9c03a 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -19,6 +19,7 @@ #include #include +#include #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); } - -static void horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount) +/* + * 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) { - //TODO: + 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 _genSpan(SwRleData* rle, SwSpan* spans, size_t count) +{ + 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(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(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(((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(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_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 0f2a6fa4..e725e30c 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -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(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(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,33 +201,17 @@ static bool updateBBox(SwShape& sdata) } -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) +void _deleteRle(SwShape& sdata) { - //TODO: - return true; + if (sdata.rle) { + if (sdata.rle->spans) free(sdata.rle->spans); + free(sdata.rle); + } + sdata.rle = nullptr; } -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); -} - - -void shapeDelOutline(const ShapeNode& shape, SwShape& sdata) +void _deleteOutline(SwShape& sdata) { if (!sdata.outline) return; @@ -240,11 +224,38 @@ void shapeDelOutline(const ShapeNode& shape, SwShape& sdata) sdata.outline = nullptr; } +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) +{ + //TODO: + return true; +} + + +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +{ + if (!_updateBBox(sdata)) goto end; + sdata.rle = rleRender(sdata); + _deleteOutline(sdata); +end: + if (sdata.rle) return true; + return false; +} + + +void shapeReset(SwShape& sdata) +{ + _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; diff --git a/src/lib/tvgCanvasBase.h b/src/lib/tvgCanvasBase.h index f200d29d..3ec6c7ab 100644 --- a/src/lib/tvgCanvasBase.h +++ b/src/lib/tvgCanvasBase.h @@ -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(); diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index e9dc2490..fe2d8e21 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -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; + } + }; } diff --git a/src/lib/tvgSceneNode.cpp b/src/lib/tvgSceneNode.cpp index 7c4bb589..93a9b211 100644 --- a/src/lib/tvgSceneNode.cpp +++ b/src/lib/tvgSceneNode.cpp @@ -58,6 +58,13 @@ int SceneNode :: push(unique_ptr shape) noexcept } +int SceneNode :: dispose(RasterMethod* engine) noexcept +{ + + return 0; +} + + int SceneNode :: update(RasterMethod* engine) noexcept { diff --git a/src/lib/tvgShapeNode.cpp b/src/lib/tvgShapeNode.cpp index 81d97dd5..f17021a2 100644 --- a/src/lib/tvgShapeNode.cpp +++ b/src/lib/tvgShapeNode.cpp @@ -84,6 +84,17 @@ unique_ptr 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(); diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 995dac67..e85275f4 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -89,7 +89,7 @@ SwCanvas::SwCanvas() : pImpl(make_unique()) SwCanvas::~SwCanvas() { - cout << "SwCanvas(" << this << ") destroyed!" << endl; + cout << "SwCanvas(" << this << ") destroyed!" << endl; }