sw_engine: case cover out of surface boundary. 85/232285/2
authorHermet Park <chuneon.park@samsung.com>
Wed, 29 Apr 2020 15:54:41 +0000 (00:54 +0900)
committerHermet Park <chuneon.park@samsung.com>
Thu, 30 Apr 2020 06:19:46 +0000 (15:19 +0900)
Also added surface boundary test code.

Change-Id: Ib4c327d12ce52d506f1b8a566ffa48e5b5b8c03e

.gitignore
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwRaster.cpp
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRle.cpp
src/lib/sw_engine/tvgSwShape.cpp
test/makefile
test/testBoundary.cpp [new file with mode: 0644]

index a6a008a..bbd3f8e 100644 (file)
@@ -4,3 +4,4 @@ build
 testShape
 testMultiShapes
 testMergeShapes
+testBoundary
index 4b6f820..012f968 100644 (file)
@@ -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);
 
index 2e43a44..a71c443 100644 (file)
 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;
         }
index 425afab..ae43735 100644 (file)
@@ -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<SwCoord>(surface.stride), static_cast<SwCoord>(surface.height)};
+        if (!shapeGenRle(shape, *sdata, clip)) return sdata;
     }
 
     return sdata;
index f17c684..3991fff 100644 (file)
@@ -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<int>(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<SwRleData*>(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<Cell*>((char*)rw.buffer + cellEnd);
             rw.cells = reinterpret_cast<Cell*>((char*)rw.buffer + cellStart);
index e725e30..1f24a63 100644 (file)
@@ -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;
index bb80729..1bab747 100644 (file)
@@ -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 (file)
index 0000000..473fd59
--- /dev/null
@@ -0,0 +1,86 @@
+#include <tizenvg.h>
+#include <Elementary.h>
+
+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();
+}