Also added surface boundary test code.
Change-Id: Ib4c327d12ce52d506f1b8a566ffa48e5b5b8c03e
testShape
testMultiShapes
testMergeShapes
+testBoundary
}
};
+struct SwSize
+{
+ SwCoord w, h;
+};
+
struct SwOutline
{
size_t* cntrs; //the contour end points
struct SwSpan
{
- uint16_t x, y;
+ int16_t x, y;
uint16_t len;
uint8_t coverage;
};
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);
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;
}
//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));
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;
Cell** yCells;
SwCoord yCnt;
+ SwSize clip;
+
bool invalid;
};
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
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;
//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;
}
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;
}
/* 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);
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;
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);
}
-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;
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`
--- /dev/null
+#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();
+}