From 46ba3352a8313b602c04da9ddcf8dea955c485b6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 30 Apr 2020 00:54:41 +0900 Subject: [PATCH] sw_engine: case cover out of surface boundary. Also added surface boundary test code. Change-Id: Ib4c327d12ce52d506f1b8a566ffa48e5b5b8c03e --- .gitignore | 1 + src/lib/sw_engine/tvgSwCommon.h | 12 ++++-- src/lib/sw_engine/tvgSwRaster.cpp | 3 +- src/lib/sw_engine/tvgSwRenderer.cpp | 5 ++- src/lib/sw_engine/tvgSwRle.cpp | 42 ++++++++++++------ src/lib/sw_engine/tvgSwShape.cpp | 12 +++++- test/makefile | 1 + test/testBoundary.cpp | 86 +++++++++++++++++++++++++++++++++++++ 8 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 test/testBoundary.cpp diff --git a/.gitignore b/.gitignore index a6a008a..bbd3f8e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build testShape testMultiShapes testMergeShapes +testBoundary diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 4b6f820..012f968 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -49,6 +49,11 @@ struct SwPoint } }; +struct SwSize +{ + SwCoord w, h; +}; + struct SwOutline { size_t* cntrs; //the contour end points @@ -63,7 +68,7 @@ struct SwOutline struct SwSpan { - uint16_t x, y; + int16_t x, y; uint16_t len; uint8_t coverage; }; @@ -90,10 +95,9 @@ struct SwShape 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); +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip); bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata); - -SwRleData* rleRender(const SwShape& sdata); +SwRleData* rleRender(const SwShape& sdata, const SwSize& clip); bool rasterShape(Surface& surface, SwShape& sdata, size_t color); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 2e43a44..a71c443 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -23,13 +23,14 @@ bool rasterShape(Surface& surface, SwShape& sdata, size_t color) { SwRleData* rle = sdata.rle; - assert(rle); + if (!rle) return false; auto stride = surface.stride; auto span = rle->spans; for (size_t i = 0; i < rle->size; ++i) { assert(span); +// printf("raster y(%d) x(%d) len(%d)\n", span->y, span->x, span->len); for (auto j = 0; j < span->len; ++j) { surface.buffer[span->y * stride + span->x + j] = color; } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 425afab..ae43735 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -55,7 +55,6 @@ bool SwRenderer::render(const ShapeNode& shape, void *data) //invisible? size_t r, g, b, a; shape.fill(&r, &g, &b, &a); - if (a == 0) return true; //TODO: Threading return rasterShape(surface, *sdata, COLOR(r, g, b, a)); @@ -92,7 +91,9 @@ void* SwRenderer::prepare(const ShapeNode& shape, void* data, UpdateFlag flags) shapeReset(*sdata); if (!shapeGenOutline(shape, *sdata)) return sdata; if (!shapeTransformOutline(shape, *sdata)) return sdata; - if (!shapeGenRle(shape, *sdata)) return sdata; + + SwSize clip = {static_cast(surface.stride), static_cast(surface.height)}; + if (!shapeGenRle(shape, *sdata, clip)) return sdata; } return sdata; diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index f17c684..3991fff 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -84,6 +84,8 @@ struct RleWorker Cell** yCells; SwCoord yCnt; + SwSize clip; + bool invalid; }; @@ -161,6 +163,13 @@ static void _genSpan(SwRleData* rle, SwSpan* spans, size_t count) static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoord acount) { + x += rw.cellMin.x; + y += rw.cellMin.y; + + //Clip Y range + if (y < 0) return; + if (y >= rw.clip.h) return; + /* 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 @@ -176,9 +185,6 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor 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; @@ -197,7 +203,13 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor //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; + + //Clip x range + SwCoord xOver = 0; + if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); + if (x < 0) xOver += x; + + span->len += (acount + xOver) - 1; return; } @@ -211,10 +223,21 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor assert(span); } + //Clip x range + SwCoord xOver = 0; + if (x + acount >= rw.clip.w) xOver -= (x + acount - rw.clip.w); + if (x < 0) { + xOver += x; + x = 0; + } + + //Nothing to draw + if (acount + xOver <= 0) return; + //add a span to the current list span->x = x; span->y = y; - span->len = acount; + span->len = (acount + xOver); span->coverage = coverage; ++rw.spansCnt; } @@ -646,16 +669,13 @@ static bool _genRle(RleWorker& rw) /* External Class Implementation */ /************************************************************************/ -SwRleData* rleRender(const SwShape& sdata) +SwRleData* rleRender(const SwShape& sdata, const SwSize& clip) { constexpr auto RENDER_POOL_SIZE = 16384L; constexpr auto BAND_SIZE = 40; auto outline = sdata.outline; assert(outline); - - if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr; - assert(outline->cntrs && outline->pts); assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); @@ -680,11 +700,10 @@ SwRleData* rleRender(const SwShape& sdata) rw.outline = outline; rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; + rw.clip = clip; rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); assert(rw.rle); - //printf("bufferSize = %d, bbox(%d %d %d %d), exCnt(%f), eyCnt(%f), bandSize(%d)\n", rw.bufferSize, rw.cellMin.x, rw.cellMin.y, rw.cellMax.x, rw.cellMax.y, rw.cellXCnt, rw.cellYCnt, rw.bandSize); - //Generate RLE Band bands[BAND_SIZE]; Band* band; @@ -717,7 +736,6 @@ SwRleData* rleRender(const SwShape& sdata) auto cellEnd = rw.bufferSize; cellEnd -= cellEnd % sizeof(Cell); -//printf("n:%d, cellStart(%d), cellEnd(%d) cellMod(%d)\n", n, cellStart, cellEnd, cellMod); auto cellsMax = reinterpret_cast((char*)rw.buffer + cellEnd); rw.cells = reinterpret_cast((char*)rw.buffer + cellStart); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index e725e30..1f24a63 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -235,11 +235,19 @@ bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata) } -bool shapeGenRle(const ShapeNode& shape, SwShape& sdata) +bool shapeGenRle(const ShapeNode& shape, SwShape& sdata, const SwSize& clip) { + if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) goto end; if (!_updateBBox(sdata)) goto end; - sdata.rle = rleRender(sdata); + + //Check boundary + if ((sdata.bbox.min.x > clip.w || sdata.bbox.min.y > clip.h) || + (sdata.bbox.min.x + sdata.bbox.max.x < 0) || + (sdata.bbox.min.y + sdata.bbox.max.y < 0)) goto end; + + sdata.rle = rleRender(sdata, clip); _deleteOutline(sdata); + end: if (sdata.rle) return true; return false; diff --git a/test/makefile b/test/makefile index bb80729..1bab747 100644 --- a/test/makefile +++ b/test/makefile @@ -2,3 +2,4 @@ all: gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testMultiShapes testMultiShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testMergeShapes testMergeShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp new file mode 100644 index 0000000..473fd59 --- /dev/null +++ b/test/testBoundary.cpp @@ -0,0 +1,86 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 + +static uint32_t buffer[WIDTH * HEIGHT]; + +void tvgtest() +{ + //Initialize TizenVG Engine + tvg::Engine::init(); + + //Create a Canvas + auto canvas = tvg::SwCanvas::gen(buffer, WIDTH, HEIGHT); + canvas->reserve(5); //reserve 5 shape nodes (optional) + + //Prepare Shape1 + auto shape1 = tvg::ShapeNode::gen(); + shape1->appendRect(-100, -100, 1000, 1000, 50); + shape1->fill(255, 255, 255, 255); + canvas->push(move(shape1)); + + //Prepare Shape2 + auto shape2 = tvg::ShapeNode::gen(); + shape2->appendRect(-100, -100, 250, 250, 50); + shape2->fill(0, 0, 255, 255); + canvas->push(move(shape2)); + + //Prepare Shape3 + auto shape3 = tvg::ShapeNode::gen(); + shape3->appendRect(500, 500, 550, 550, 0); + shape3->fill(0, 255, 255, 255); + canvas->push(move(shape3)); + + //Prepare Shape4 + auto shape4 = tvg::ShapeNode::gen(); + shape4->appendCircle(800, 100, 200, 200); + shape4->fill(255, 255, 0, 255); + canvas->push(move(shape4)); + + //Prepare Shape5 + auto shape5 = tvg::ShapeNode::gen(); + shape5->appendCircle(200, 650, 250, 200); + shape5->fill(0, 0, 0, 255); + canvas->push(move(shape5)); + + //Draw the Shapes onto the Canvas + canvas->draw(); + canvas->sync(); + + //Terminate TizenVG Engine + tvg::Engine::term(); +} + +void +win_del(void *data, Evas_Object *o, void *ev) +{ + elm_exit(); +} + +int main(int argc, char **argv) +{ + tvgtest(); + + //Show the result using EFL... + elm_init(argc, argv); + + Eo* win = elm_win_util_standard_add(NULL, "TizenVG Test"); + evas_object_smart_callback_add(win, "delete,request", win_del, 0); + + Eo* img = evas_object_image_filled_add(evas_object_evas_get(win)); + evas_object_image_size_set(img, WIDTH, HEIGHT); + evas_object_image_data_set(img, buffer); + evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(img); + + elm_win_resize_object_add(win, img); + evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT); + evas_object_show(win); + + elm_run(); + elm_shutdown(); +} -- 2.7.4