mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-27 00:26:51 +00:00
sw_engine: case cover out of surface boundary.
Also added surface boundary test code. Change-Id: Ib4c327d12ce52d506f1b8a566ffa48e5b5b8c03e
This commit is contained in:
parent
5120a7ae12
commit
46ba3352a8
8 changed files with 141 additions and 21 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@ build
|
||||||
testShape
|
testShape
|
||||||
testMultiShapes
|
testMultiShapes
|
||||||
testMergeShapes
|
testMergeShapes
|
||||||
|
testBoundary
|
||||||
|
|
|
@ -49,6 +49,11 @@ struct SwPoint
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SwSize
|
||||||
|
{
|
||||||
|
SwCoord w, h;
|
||||||
|
};
|
||||||
|
|
||||||
struct SwOutline
|
struct SwOutline
|
||||||
{
|
{
|
||||||
size_t* cntrs; //the contour end points
|
size_t* cntrs; //the contour end points
|
||||||
|
@ -63,7 +68,7 @@ struct SwOutline
|
||||||
|
|
||||||
struct SwSpan
|
struct SwSpan
|
||||||
{
|
{
|
||||||
uint16_t x, y;
|
int16_t x, y;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint8_t coverage;
|
uint8_t coverage;
|
||||||
};
|
};
|
||||||
|
@ -90,10 +95,9 @@ struct SwShape
|
||||||
void shapeReset(SwShape& sdata);
|
void shapeReset(SwShape& sdata);
|
||||||
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
|
bool shapeGenOutline(const ShapeNode& shape, SwShape& sdata);
|
||||||
void shapeDelOutline(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);
|
bool shapeTransformOutline(const ShapeNode& shape, SwShape& sdata);
|
||||||
|
SwRleData* rleRender(const SwShape& sdata, const SwSize& clip);
|
||||||
SwRleData* rleRender(const SwShape& sdata);
|
|
||||||
|
|
||||||
bool rasterShape(Surface& surface, SwShape& sdata, size_t color);
|
bool rasterShape(Surface& surface, SwShape& sdata, size_t color);
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,14 @@
|
||||||
bool rasterShape(Surface& surface, SwShape& sdata, size_t color)
|
bool rasterShape(Surface& surface, SwShape& sdata, size_t color)
|
||||||
{
|
{
|
||||||
SwRleData* rle = sdata.rle;
|
SwRleData* rle = sdata.rle;
|
||||||
assert(rle);
|
if (!rle) return false;
|
||||||
|
|
||||||
auto stride = surface.stride;
|
auto stride = surface.stride;
|
||||||
auto span = rle->spans;
|
auto span = rle->spans;
|
||||||
|
|
||||||
for (size_t i = 0; i < rle->size; ++i) {
|
for (size_t i = 0; i < rle->size; ++i) {
|
||||||
assert(span);
|
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) {
|
for (auto j = 0; j < span->len; ++j) {
|
||||||
surface.buffer[span->y * stride + span->x + j] = color;
|
surface.buffer[span->y * stride + span->x + j] = color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,6 @@ bool SwRenderer::render(const ShapeNode& shape, void *data)
|
||||||
//invisible?
|
//invisible?
|
||||||
size_t r, g, b, a;
|
size_t r, g, b, a;
|
||||||
shape.fill(&r, &g, &b, &a);
|
shape.fill(&r, &g, &b, &a);
|
||||||
if (a == 0) return true;
|
|
||||||
|
|
||||||
//TODO: Threading
|
//TODO: Threading
|
||||||
return rasterShape(surface, *sdata, COLOR(r, g, b, a));
|
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);
|
shapeReset(*sdata);
|
||||||
if (!shapeGenOutline(shape, *sdata)) return sdata;
|
if (!shapeGenOutline(shape, *sdata)) return sdata;
|
||||||
if (!shapeTransformOutline(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;
|
return sdata;
|
||||||
|
|
|
@ -84,6 +84,8 @@ struct RleWorker
|
||||||
Cell** yCells;
|
Cell** yCells;
|
||||||
SwCoord yCnt;
|
SwCoord yCnt;
|
||||||
|
|
||||||
|
SwSize clip;
|
||||||
|
|
||||||
bool invalid;
|
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)
|
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 */
|
/* compute the coverage line's coverage, depending on the outline fill rule */
|
||||||
/* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
|
/* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
|
||||||
auto coverage = static_cast<int>(area >> (PIXEL_BITS * 2 + 1 - 8)); //range 0 - 256
|
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;
|
if (coverage >= 256) coverage = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
x += rw.cellMin.x;
|
|
||||||
y += rw.cellMin.y;
|
|
||||||
|
|
||||||
//span has ushort coordinates. check limit overflow
|
//span has ushort coordinates. check limit overflow
|
||||||
if (x >= SHRT_MAX) {
|
if (x >= SHRT_MAX) {
|
||||||
cout << "x(" << x << ") coordinate overflow!" << endl;
|
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
|
//see whether we can add this span to the current list
|
||||||
if ((count > 0) && (rw.ySpan == y) &&
|
if ((count > 0) && (rw.ySpan == y) &&
|
||||||
(span->x + span->len == x) && (span->coverage == coverage)) {
|
(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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,10 +223,21 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
|
||||||
assert(span);
|
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
|
//add a span to the current list
|
||||||
span->x = x;
|
span->x = x;
|
||||||
span->y = y;
|
span->y = y;
|
||||||
span->len = acount;
|
span->len = (acount + xOver);
|
||||||
span->coverage = coverage;
|
span->coverage = coverage;
|
||||||
++rw.spansCnt;
|
++rw.spansCnt;
|
||||||
}
|
}
|
||||||
|
@ -646,16 +669,13 @@ static bool _genRle(RleWorker& rw)
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
SwRleData* rleRender(const SwShape& sdata)
|
SwRleData* rleRender(const SwShape& sdata, const SwSize& clip)
|
||||||
{
|
{
|
||||||
constexpr auto RENDER_POOL_SIZE = 16384L;
|
constexpr auto RENDER_POOL_SIZE = 16384L;
|
||||||
constexpr auto BAND_SIZE = 40;
|
constexpr auto BAND_SIZE = 40;
|
||||||
|
|
||||||
auto outline = sdata.outline;
|
auto outline = sdata.outline;
|
||||||
assert(outline);
|
assert(outline);
|
||||||
|
|
||||||
if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return nullptr;
|
|
||||||
|
|
||||||
assert(outline->cntrs && outline->pts);
|
assert(outline->cntrs && outline->pts);
|
||||||
assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
|
assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1);
|
||||||
|
|
||||||
|
@ -680,11 +700,10 @@ SwRleData* rleRender(const SwShape& sdata)
|
||||||
rw.outline = outline;
|
rw.outline = outline;
|
||||||
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
|
rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64
|
||||||
rw.bandShoot = 0;
|
rw.bandShoot = 0;
|
||||||
|
rw.clip = clip;
|
||||||
rw.rle = reinterpret_cast<SwRleData*>(calloc(1, sizeof(SwRleData)));
|
rw.rle = reinterpret_cast<SwRleData*>(calloc(1, sizeof(SwRleData)));
|
||||||
assert(rw.rle);
|
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
|
//Generate RLE
|
||||||
Band bands[BAND_SIZE];
|
Band bands[BAND_SIZE];
|
||||||
Band* band;
|
Band* band;
|
||||||
|
@ -717,7 +736,6 @@ SwRleData* rleRender(const SwShape& sdata)
|
||||||
|
|
||||||
auto cellEnd = rw.bufferSize;
|
auto cellEnd = rw.bufferSize;
|
||||||
cellEnd -= cellEnd % sizeof(Cell);
|
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);
|
auto cellsMax = reinterpret_cast<Cell*>((char*)rw.buffer + cellEnd);
|
||||||
rw.cells = reinterpret_cast<Cell*>((char*)rw.buffer + cellStart);
|
rw.cells = reinterpret_cast<Cell*>((char*)rw.buffer + cellStart);
|
||||||
|
|
|
@ -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;
|
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);
|
_deleteOutline(sdata);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (sdata.rle) return true;
|
if (sdata.rle) return true;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -2,3 +2,4 @@ all:
|
||||||
gcc -o testShape testShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
|
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 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 testMergeShapes testMergeShapes.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
|
||||||
|
gcc -o testBoundary testBoundary.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
|
||||||
|
|
86
test/testBoundary.cpp
Normal file
86
test/testBoundary.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue