From ef9f31577e0fbf94a0135b827e84750be5673f2b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 2 Jun 2020 20:58:50 +0900 Subject: [PATCH 01/16] common stroke: retype the stroke width from size_t to float Change-Id: I812d06d2037d66408c41d50f7c1ff7ba605558bd --- inc/tizenvg.h | 4 ++-- src/lib/tvgShape.cpp | 6 +++--- src/lib/tvgShapeImpl.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 05f1927..c113975 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -141,7 +141,7 @@ public: int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; //Stroke - int stroke(size_t width) noexcept; + int stroke(float width) noexcept; int stroke(size_t r, size_t g, size_t b, size_t a) noexcept; int stroke(const size_t* dashPattern, size_t cnt) noexcept; int stroke(StrokeCap cap) noexcept; @@ -161,7 +161,7 @@ public: int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; int bounds(float* x, float* y, float* w, float* h) const noexcept override; - size_t strokeWidth() const noexcept; + float strokeWidth() const noexcept; int strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; size_t strokeDash(const size_t** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index a17c53b..fe95eac 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -280,7 +280,7 @@ int Shape::bounds(float* x, float* y, float* w, float* h) const noexcept } -int Shape::stroke(size_t width) noexcept +int Shape::stroke(float width) noexcept { auto impl = pImpl.get(); assert(impl); @@ -291,12 +291,12 @@ int Shape::stroke(size_t width) noexcept } -size_t Shape::strokeWidth() const noexcept +float Shape::strokeWidth() const noexcept { auto impl = pImpl.get(); assert(impl); - if (!impl->stroke) return -1; + if (!impl->stroke) return 0; return impl->stroke->width; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 682c29b..05be16d 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -30,7 +30,7 @@ struct ShapeFill struct ShapeStroke { - size_t width = 0; + float width = 0; size_t color[4] = {0, 0, 0, 0}; size_t* dashPattern = nullptr; size_t dashCnt = 0; @@ -153,7 +153,7 @@ struct Shape::Impl return 0; } - bool strokeWidth(size_t width) + bool strokeWidth(float width) { //TODO: Size Exception? -- 2.7.4 From 7ee25cd78334a24bb6b465ae5db46bb4dbf403cb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:15:40 +0900 Subject: [PATCH 02/16] sw_engine: fix mistached c style alloc/free these are allocated by c style mem alloc. Thus, they should be freed with free() Change-Id: I320fff4d5a5bce2374ace6495a9f96c3e1034cfc --- src/lib/sw_engine/tvgSwStroke.cpp | 1 + src/lib/tvgShapePath.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index e048ff5..be18e05 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -838,6 +838,7 @@ void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) stroke.borders[1].valid = false; } + bool strokeParseOutline(SwStroke& stroke, SwOutline& outline) { uint32_t first = 0; diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 68205f4..7e020e8 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -36,8 +36,8 @@ struct ShapePath ~ShapePath() { - if (cmds) delete(cmds); - if (pts) delete(pts); + if (cmds) free(cmds); + if (pts) free(pts); } void reserveCmd(size_t cmdCnt) -- 2.7.4 From 3bb272877a273c01cde42c35f313128a538642dd Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:27:34 +0900 Subject: [PATCH 03/16] sw_engine: fix a missing of variable initializing. Change-Id: I6451b07709fbc56441363e8f0ee0f4647404ae10 --- src/lib/sw_engine/tvgSwRle.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index b22b233..1d5577b 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -672,6 +672,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.cellMax = bbox.max; rw.cellXCnt = rw.cellMax.x - rw.cellMin.x; rw.cellYCnt = rw.cellMax.y - rw.cellMin.y; + rw.ySpan = 0; rw.outline = const_cast(outline); rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; -- 2.7.4 From 2b53b8018a0275e55f1caca48ab36db66ad3f291 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:35:03 +0900 Subject: [PATCH 04/16] test stroke: remove duplicated engine initialize call. Change-Id: Ia592a45581eae4fd5c85e6ba4d9d0eef835b14c1 --- test/testStroke.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/testStroke.cpp b/test/testStroke.cpp index a4678dc..b17c3a1 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -14,9 +14,6 @@ void tvgtest() //Initialize TizenVG Engine tvg::Engine::init(); - //Initialize TizenVG Engine - tvg::Engine::init(); - //Create a Canvas auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); -- 2.7.4 From ad6b74dd1392a2272f71e63e3fba7ede8c5fd83e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 11:41:40 +0900 Subject: [PATCH 05/16] test scene: remove duplicated engine initialization. Change-Id: I5a2f972544e47578552b0c49367749ce2d01c5f2 --- test/testSceneTransform.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 38bfb0f..a66996a 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -13,9 +13,6 @@ tvg::Scene* pScene2 = nullptr; void tvgtest() { - //Initialize TizenVG Engine - tvg::Engine::init(); - //Create a Canvas canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); @@ -96,9 +93,6 @@ void tvgtest() canvas->draw(); canvas->sync(); - - //Terminate TizenVG Engine - tvg::Engine::term(); } void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progress) -- 2.7.4 From 01b550497c1121d88831d844302ecf6eda1b92d1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 2 Jun 2020 21:00:50 +0900 Subject: [PATCH 06/16] sw_engine: support stroke transformation properly. also updated transform test cases. Yet, this engine is not well optimized, If they are too mch sluggish, you can use ELM_FPS envrionment lowing down the fps when you launch test cases... ex) $ELM_FPS=30 ./testSceneTransform Change-Id: I1871d5bedee010d5d6a3d877d95e257120796e8b --- src/lib/sw_engine/tvgSwRenderer.cpp | 33 +++++++++++++++++++-------------- test/testDirectUpdate.cpp | 3 +++ test/testSceneTransform.cpp | 12 ++++++++---- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 3ec882e..91c0013 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -93,29 +93,34 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* if (flags == RenderUpdateFlag::None) return sdata; - //invisible? - size_t a, sa; - shape.fill(nullptr, nullptr, nullptr, &a); - shape.strokeColor(nullptr, nullptr, nullptr, &sa); - if (a == 0 && sa == 0) return sdata; - //TODO: Threading SwSize clip = {static_cast(surface.w), static_cast(surface.h)}; //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - shapeReset(*sdata); - if (!shapeGenOutline(shape, *sdata)) return sdata; - if (transform) shapeTransformOutline(shape, *sdata, *transform); - if (!shapeGenRle(shape, *sdata, clip)) return sdata; + + size_t alpha = 0; + shape.fill(nullptr, nullptr, nullptr, &alpha); + + if (alpha > 0) { + shapeReset(*sdata); + if (!shapeGenOutline(shape, *sdata)) return sdata; + if (transform) shapeTransformOutline(shape, *sdata, *transform); + if (!shapeGenRle(shape, *sdata, clip)) return sdata; + } } //Stroke - if (flags & RenderUpdateFlag::Stroke) { - shapeResetStroke(shape, *sdata); - if (shape.strokeWidth() > 0.01) { - if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; + if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { + + if (shape.strokeWidth() > 0.5) { + shapeResetStroke(shape, *sdata); + size_t alpha = 0; + shape.strokeColor(nullptr, nullptr, nullptr, &alpha); + if (alpha > 0) { + if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; + } } } diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 799d135..e1a4c60 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -27,6 +27,8 @@ void tvgtest() //fill property will be retained shape->fill(127, 255, 255, 255); + shape->stroke(0, 0, 255, 255); + shape->stroke(1); canvas->push(move(shape)); @@ -44,6 +46,7 @@ void transit_cb(Elm_Transit_Effect *effect, Elm_Transit* transit, double progres pShape->reset(); //reset path pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + pShape->stroke(30 * progress); //Update shape for drawing (this may work asynchronously) canvas->update(pShape); diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index a66996a..975f4fa 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -25,19 +25,21 @@ void tvgtest() //Prepare Round Rectangle (Scene1) auto shape1 = tvg::Shape::gen(); shape1->appendRect(-235, -250, 400, 400, 50); //x, y, w, h, cornerRadius - shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->fill(0, 255, 0, 255); //r, g, b, a + shape1->stroke(5); //width + shape1->stroke(255, 255, 255, 255); //r, g, b, a scene->push(move(shape1)); //Prepare Circle (Scene1) auto shape2 = tvg::Shape::gen(); shape2->appendCircle(-165, -150, 200, 200); //cx, cy, radiusW, radiusH - shape2->fill(255, 255, 0, 255); //r, g, b, a + shape2->fill(255, 255, 0, 255); //r, g, b, a scene->push(move(shape2)); //Prepare Ellipse (Scene1) auto shape3 = tvg::Shape::gen(); - shape3->appendCircle(265, 250, 150, 100); //cx, cy, radiusW, radiusH - shape3->fill(0, 255, 255, 255); //r, g, b, a + shape3->appendCircle(265, 250, 150, 100); //cx, cy, radiusW, radiusH + shape3->fill(0, 255, 255, 255); //r, g, b, a scene->push(move(shape3)); scene->translate(350, 350); @@ -64,6 +66,8 @@ void tvgtest() shape4->lineTo(-53, -5.5); shape4->close(); shape4->fill(0, 0, 127, 127); + shape4->stroke(3); //width + shape4->stroke(0, 0, 255, 255); //r, g, b, a scene2->push(move(shape4)); //Circle (Scene2) -- 2.7.4 From f335779ce52f39755828fe70d6996fa087803b06 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 19:08:18 +0900 Subject: [PATCH 07/16] sw_engine stroke: stabilizing line drawing. Also added StrokeLine test Change-Id: I91143039823d744bf9287534227927556a2f51e1 --- .gitignore | 1 + src/lib/sw_engine/tvgSwRle.cpp | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 1 + src/lib/sw_engine/tvgSwStroke.cpp | 9 ++-- test/makefile | 1 + test/testStrokeLine.cpp | 101 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 test/testStrokeLine.cpp diff --git a/.gitignore b/.gitignore index 1353d08..ba439cb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ testScene testTransform testSceneTransform testStroke +testStrokeLine diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 1d5577b..2757c0d 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -612,7 +612,7 @@ static bool _decomposeOutline(RleWorker& rw) goto close; } } - _lineTo(rw, UPSCALE(outline->pts[first])); + _lineTo(rw, start); close: first = last + 1; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index e8e1996..a4fa7fb 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -316,6 +316,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) auto outline = sdata.outline; if (!outline) outline = static_cast(calloc(1, sizeof(SwOutline))); assert(outline); + outline->opened = true; _growOutlinePoint(*outline, outlinePtsCnt); _growOutlineContour(*outline, outlineCntrsCnt); diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index be18e05..06ec989 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -635,15 +635,14 @@ static void _addReverseLeft(SwStroke& stroke, bool opened) } else { //switch begin/end tags if necessary auto ttag = dstTag[0] & (SW_STROKE_TAG_BEGIN | SW_STROKE_TAG_END); - if (ttag == (SW_STROKE_TAG_BEGIN || SW_STROKE_TAG_END)) { - dstTag[0] ^= (SW_STROKE_TAG_BEGIN || SW_STROKE_TAG_END); - } + if (ttag == SW_STROKE_TAG_BEGIN || ttag == SW_STROKE_TAG_END) + dstTag[0] ^= (SW_STROKE_TAG_BEGIN | SW_STROKE_TAG_END); } --srcPt; --srcTag; - --dstPt; - --dstTag; + ++dstPt; + ++dstTag; } left->ptsCnt = left->start; diff --git a/test/makefile b/test/makefile index 3f314e8..2aba05d 100644 --- a/test/makefile +++ b/test/makefile @@ -11,3 +11,4 @@ all: gcc -o testTransform testTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp new file mode 100644 index 0000000..8687b85 --- /dev/null +++ b/test/testStrokeLine.cpp @@ -0,0 +1,101 @@ +#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(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + + for (int i = 0; i < 10; ++i) { + auto shape = tvg::Shape::gen(); + shape->moveTo(50, 50 + (25 * i)); + shape->lineTo(750, 50 + (25 * i)); + shape->stroke(255, 255, 255, 255); //color: r, g, b, a + shape->stroke(i + 1); //stroke width + shape->stroke(tvg::StrokeCap::Round); //default is Square + canvas->push(move(shape)); + } + + auto shape1 = tvg::Shape::gen(); + shape1->moveTo(20, 350); + shape1->lineTo(250, 350); + shape1->lineTo(220, 500); + shape1->lineTo(70, 470); + shape1->lineTo(70, 330); + shape1->stroke(255, 0, 0, 255); + shape1->stroke(10); + shape1->stroke(tvg::StrokeJoin::Round); + shape1->stroke(tvg::StrokeCap::Round); + canvas->push(move(shape1)); + + auto shape2 = tvg::Shape::gen(); + shape2->moveTo(270, 350); + shape2->lineTo(500, 350); + shape2->lineTo(470, 500); + shape2->lineTo(320, 470); + shape2->lineTo(320, 330); + shape2->stroke(255, 255, 0, 255); + shape2->stroke(10); + shape2->stroke(tvg::StrokeJoin::Bevel); + shape2->stroke(tvg::StrokeCap::Square); + canvas->push(move(shape2)); + + auto shape3 = tvg::Shape::gen(); + shape3->moveTo(520, 350); + shape3->lineTo(750, 350); + shape3->lineTo(720, 500); + shape3->lineTo(570, 470); + shape3->lineTo(570, 330); + shape3->stroke(0, 255, 0, 255); + shape3->stroke(10); + shape3->stroke(tvg::StrokeJoin::Miter); + shape3->stroke(tvg::StrokeCap::Butt); + canvas->push(move(shape3)); + + 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 From 98edb4112bf586a66f9bb095360eae1e9836adc8 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 19:16:44 +0900 Subject: [PATCH 08/16] sw_engine shape: ++ comment for later optimization Change-Id: Ie6cd622748b88e2bce0c9d9a79cc4528a95c9c5c --- src/lib/sw_engine/tvgSwShape.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index a4fa7fb..30b79c8 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -245,6 +245,8 @@ void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTrans bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) { + /* OPTIMIZE ME: We may avoid this bounding box calculation in this stage + if this shape has stroke and stroke bbox can be used here... */ if (!_updateBBox(sdata.outline, sdata.bbox)) goto end; if (!_checkValid(sdata, clip)) goto end; -- 2.7.4 From dc5f9f7430df751f8f65755afe020d24149b74a9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 4 Jun 2020 17:49:10 +0900 Subject: [PATCH 09/16] common: retyped the color value size_t -> uint8_t since it's range is 0 - 255. Change-Id: I16e0569341c4a94acab9488d076f235bf90ff4db --- inc/tizenvg.h | 8 ++++---- src/lib/sw_engine/tvgSwRenderer.cpp | 6 +++--- src/lib/tvgShape.cpp | 8 ++++---- src/lib/tvgShapeImpl.h | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index c113975..905c3f0 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -142,13 +142,13 @@ public: //Stroke int stroke(float width) noexcept; - int stroke(size_t r, size_t g, size_t b, size_t a) noexcept; + int stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; int stroke(const size_t* dashPattern, size_t cnt) noexcept; int stroke(StrokeCap cap) noexcept; int stroke(StrokeJoin join) noexcept; //Fill - int fill(size_t r, size_t g, size_t b, size_t a) noexcept; + int fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; //Transform int rotate(float degree) noexcept override; @@ -158,11 +158,11 @@ public: //Getters size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; - int fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + int fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; int bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; - int strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept; + int strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; size_t strokeDash(const size_t** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 91c0013..38ac674 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -62,7 +62,7 @@ bool SwRenderer::render(const Shape& shape, void *data) SwShape* sdata = static_cast(data); if (!sdata) return false; - size_t r, g, b, a; + uint8_t r, g, b, a; shape.fill(&r, &g, &b, &a); if (a > 0) rasterShape(surface, *sdata, r, g, b, a); @@ -100,7 +100,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - size_t alpha = 0; + uint8_t alpha = 0; shape.fill(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { @@ -116,7 +116,7 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* if (shape.strokeWidth() > 0.5) { shapeResetStroke(shape, *sdata); - size_t alpha = 0; + uint8_t alpha = 0; shape.strokeColor(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index fe95eac..828e251 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -213,7 +213,7 @@ int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) no } -int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept +int Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -228,7 +228,7 @@ int Shape::fill(size_t r, size_t g, size_t b, size_t a) noexcept } -int Shape::fill(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); @@ -301,7 +301,7 @@ float Shape::strokeWidth() const noexcept } -int Shape::stroke(size_t r, size_t g, size_t b, size_t a) noexcept +int Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); assert(impl); @@ -312,7 +312,7 @@ int Shape::stroke(size_t r, size_t g, size_t b, size_t a) noexcept } -int Shape::strokeColor(size_t* r, size_t* g, size_t* b, size_t* a) const noexcept +int Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 05be16d..e1a4e9f 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -31,7 +31,7 @@ struct ShapeFill struct ShapeStroke { float width = 0; - size_t color[4] = {0, 0, 0, 0}; + uint8_t color[4] = {0, 0, 0, 0}; size_t* dashPattern = nullptr; size_t dashCnt = 0; StrokeCap cap = StrokeCap::Square; @@ -188,7 +188,7 @@ struct Shape::Impl return 0; } - bool strokeColor(size_t r, size_t g, size_t b, size_t a) + bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { if (!stroke) stroke = new ShapeStroke(); assert(stroke); -- 2.7.4 From 9aa2566b45f57c742f134a6e7f4597c7011406fc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 3 Jun 2020 20:50:13 +0900 Subject: [PATCH 10/16] sw_engine: support stroke dash feature Change-Id: Ibed8bcb6a07952a059bb9a7355f7c43db97aa672 --- inc/tizenvg.h | 4 +- src/lib/sw_engine/tvgSwCommon.h | 40 +-- src/lib/sw_engine/tvgSwMath.cpp | 33 +-- src/lib/sw_engine/tvgSwRenderer.cpp | 37 ++- src/lib/sw_engine/tvgSwShape.cpp | 482 ++++++++++++++++++++++++++++++------ src/lib/sw_engine/tvgSwStroke.cpp | 33 ++- src/lib/tvgShape.cpp | 4 +- src/lib/tvgShapeImpl.h | 11 +- test/testStrokeLine.cpp | 49 ++++ 9 files changed, 533 insertions(+), 160 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 905c3f0..18db842 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -143,7 +143,7 @@ public: //Stroke int stroke(float width) noexcept; int stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; - int stroke(const size_t* dashPattern, size_t cnt) noexcept; + int stroke(const float* dashPattern, size_t cnt) noexcept; int stroke(StrokeCap cap) noexcept; int stroke(StrokeJoin join) noexcept; @@ -163,7 +163,7 @@ public: float strokeWidth() const noexcept; int strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; - size_t strokeDash(const size_t** dashPattern) const noexcept; + size_t strokeDash(const float** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index cfb15bd..16d4c1e 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -125,7 +125,8 @@ struct SwStroke SwFixed angleOut; SwPoint center; SwFixed lineLength; - SwPoint subPathStart; + SwFixed subPathAngle; + SwPoint ptStartSubPath; SwFixed subPathLineLength; SwFixed width; @@ -136,11 +137,22 @@ struct SwStroke SwStrokeBorder borders[2]; bool firstPt; - bool subPathOpen; - bool subPathAngle; + bool openSubPath; bool handleWideStrokes; }; +struct SwDashStroke +{ + SwOutline* outline; + int32_t curLen; + int32_t curIdx; + Point ptStart; + Point ptCur; + float* pattern; + size_t cnt; + bool curOpGap; +}; + struct SwShape { SwOutline* outline; @@ -183,18 +195,16 @@ SwFixed mathLength(SwPoint& pt); bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); SwFixed mathMean(SwFixed angle1, SwFixed angle2); -void shapeReset(SwShape& sdata); -bool shapeGenOutline(const Shape& shape, SwShape& sdata); -bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -void shapeDelOutline(SwShape& sdata); -void shapeResetStroke(const Shape& shape, SwShape& sdata); -bool shapeGenStrokeOutline(const Shape& shape, SwShape& sdata); -bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip); -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform); -void shapeFree(SwShape* sdata); - -void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join); -bool strokeParseOutline(SwStroke& stroke, SwOutline& outline); +void shapeReset(SwShape& shape); +bool shapeGenOutline(SwShape& shape, const Shape& sdata); +bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform); +void shapeDelOutline(SwShape& shape); +void shapeResetStroke(SwShape& shape, const Shape& sdata); +bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip); +void shapeFree(SwShape* shape); + +void strokeReset(SwStroke& stroke, const Shape& shape); +bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 80c7f8e..a0a0ea1 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -140,20 +140,21 @@ static void _polarize(SwPoint& pt) static void _rotate(SwPoint& pt, SwFixed theta) { - auto v = pt; + SwFixed x = pt.x; + SwFixed y = pt.y; //Rotate inside [-PI/4, PI/4] sector while (theta < -ANGLE_PI4) { - auto tmp = v.y; - v.y = -v.x; - v.x = tmp; + auto tmp = y; + y = -x; + x = tmp; theta += ANGLE_PI2; } while (theta > ANGLE_PI4) { - auto tmp = -v.y; - v.y = v.x; - v.x = tmp; + auto tmp = -y; + y = x; + x = tmp; theta -= ANGLE_PI2; } @@ -163,19 +164,19 @@ static void _rotate(SwPoint& pt, SwFixed theta) for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { if (theta < 0) { - auto tmp = v.x + ((v.y + j) >> i); - v.y = v.y - ((v.x + j) >> i); - v.x = tmp; + auto tmp = x + ((y + j) >> i); + y = y - ((x + j) >> i); + x = tmp; theta += *atan++; }else { - auto tmp = v.x - ((v.y + j) >> i); - v.y = v.y + ((v.x + j) >> i); - v.x = tmp; + auto tmp = x - ((y + j) >> i); + y = y + ((x + j) >> i); + x = tmp; theta -= *atan++; } } - pt = v; + pt = {x, y}; } @@ -305,9 +306,9 @@ void mathRotate(SwPoint& pt, SwFixed angle) auto v = pt; auto shift = _normalize(v); - auto theta = angle; - _rotate(v, theta); + auto theta = angle; + _rotate(v, theta); v.x = _downscale(v.x); v.y = _downscale(v.y); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 38ac674..5461abe 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -82,16 +82,16 @@ bool SwRenderer::dispose(const Shape& shape, void *data) return true; } -void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) +void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { //prepare shape data - SwShape* sdata = static_cast(data); - if (!sdata) { - sdata = static_cast(calloc(1, sizeof(SwShape))); - assert(sdata); + auto shape = static_cast(data); + if (!shape) { + shape = static_cast(calloc(1, sizeof(SwShape))); + assert(shape); } - if (flags == RenderUpdateFlag::None) return sdata; + if (flags == RenderUpdateFlag::None) return shape; //TODO: Threading @@ -99,34 +99,29 @@ void* SwRenderer::prepare(const Shape& shape, void* data, const RenderTransform* //Shape if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - + shapeReset(*shape); uint8_t alpha = 0; - shape.fill(nullptr, nullptr, nullptr, &alpha); - + sdata.fill(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { - shapeReset(*sdata); - if (!shapeGenOutline(shape, *sdata)) return sdata; - if (transform) shapeTransformOutline(shape, *sdata, *transform); - if (!shapeGenRle(shape, *sdata, clip)) return sdata; + if (!shapeGenRle(*shape, sdata, clip, transform)) return shape; } } //Stroke if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - - if (shape.strokeWidth() > 0.5) { - shapeResetStroke(shape, *sdata); + if (sdata.strokeWidth() > 0.5) { + shapeResetStroke(*shape, sdata); uint8_t alpha = 0; - shape.strokeColor(nullptr, nullptr, nullptr, &alpha); + sdata.strokeColor(nullptr, nullptr, nullptr, &alpha); if (alpha > 0) { - if (!shapeGenStrokeRle(shape, *sdata, clip)) return sdata; + if (!shapeGenStrokeRle(*shape, sdata, clip)) return shape; } } } - shapeDelOutline(*sdata); + shapeDelOutline(*shape); - return sdata; + return shape; } @@ -159,4 +154,4 @@ SwRenderer* SwRenderer::inst() return dynamic_cast(RenderInitializer::inst(renderInit)); } -#endif /* _TVG_SW_RENDERER_CPP_ */ \ No newline at end of file +#endif /* _TVG_SW_RENDERER_CPP_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 30b79c8..dcb57c7 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -23,48 +23,164 @@ /* Internal Class Implementation */ /************************************************************************/ -static void _growOutlineContour(SwOutline& outline, uint32_t n) +struct Line { - if (n == 0) { - free(outline.cntrs); - outline.cntrs = nullptr; - outline.cntrsCnt = 0; - outline.reservedCntrsCnt = 0; - return; + Point pt1; + Point pt2; +}; + + +struct Bezier +{ + Point start; + Point ctrl1; + Point ctrl2; + Point end; +}; + + +static float _lineLength(const Point& pt1, const Point& pt2) +{ + /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. + With alpha = 1, beta = 3/8, giving results with the largest error less + than 7% compared to the exact value. */ + Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; + if (diff.x < 0) diff.x = -diff.x; + if (diff.y < 0) diff.y = -diff.y; + return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f); +} + + +static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right) +{ + auto len = _lineLength(cur.pt1, cur.pt2); + auto dx = ((cur.pt2.x - cur.pt1.x) / len) * at; + auto dy = ((cur.pt2.y - cur.pt1.y) / len) * at; + left.pt1 = cur.pt1; + left.pt2.x = left.pt1.x + dx; + left.pt2.y = left.pt1.y + dy; + right.pt1 = left.pt2; + right.pt2 = cur.pt2; +} + + +static void _bezSplit(const Bezier&cur, Bezier& left, Bezier& right) +{ + auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; + left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; + right.ctrl2.x = (cur.ctrl2.x + cur.end.x) * 0.5f; + left.start.x = cur.start.x; + right.end.x = cur.end.x; + left.ctrl2.x = (left.ctrl1.x + c) * 0.5f; + right.ctrl1.x = (right.ctrl2.x + c) * 0.5f; + left.end.x = right.start.x = (left.ctrl2.x + right.ctrl1.x) * 0.5f; + + c = (cur.ctrl1.y + cur.ctrl2.y) * 0.5f; + left.ctrl1.y = (cur.start.y + cur.ctrl1.y) * 0.5f; + right.ctrl2.y = (cur.ctrl2.y + cur.end.y) * 0.5f; + left.start.y = cur.start.y; + right.end.y = cur.end.y; + left.ctrl2.y = (left.ctrl1.y + c) * 0.5f; + right.ctrl1.y = (right.ctrl2.y + c) * 0.5f; + left.end.y = right.start.y = (left.ctrl2.y + right.ctrl1.y) * 0.5f; +} + + +static float _bezLength(const Bezier& cur) +{ + Bezier left, right; + auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); + auto chord = _lineLength(cur.start, cur.end); + + if (fabs(len - chord) > FLT_EPSILON) { + _bezSplit(cur, left, right); + return _bezLength(left) + _bezLength(right); } - if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; + return len; +} - //cout << "Grow Cntrs: " << outline.reservedCntrsCnt << " -> " << outline.cntrsCnt + n << endl;; - outline.reservedCntrsCnt = n; - outline.cntrs = static_cast(realloc(outline.cntrs, n * sizeof(uint32_t))); - assert(outline.cntrs); + +static void _bezSplitLeft(Bezier& cur, float at, Bezier& left) +{ + left.start = cur.start; + + left.ctrl1.x = cur.start.x + at * (cur.ctrl1.x - cur.start.x); + left.ctrl1.y = cur.start.y + at * (cur.ctrl1.y - cur.start.y); + + left.ctrl2.x = cur.ctrl1.x + at * (cur.ctrl2.x - cur.ctrl1.x); // temporary holding spot + left.ctrl2.y = cur.ctrl1.y + at * (cur.ctrl2.y - cur.ctrl1.y); // temporary holding spot + + cur.ctrl2.x = cur.ctrl2.x + at * (cur.end.x - cur.ctrl2.x); + cur.ctrl2.y = cur.ctrl2.y + at * (cur.end.y - cur.ctrl2.y); + + cur.ctrl1.x = left.ctrl2.x + at * (cur.ctrl2.x - left.ctrl2.x); + cur.ctrl1.y = left.ctrl2.y + at * (cur.ctrl2.y - left.ctrl2.y); + + left.ctrl2.x = left.ctrl1.x + at * (left.ctrl2.x - left.ctrl1.x); + left.ctrl2.y = left.ctrl1.y + at * (left.ctrl2.y - left.ctrl1.y); + + left.end.x = cur.start.x = left.ctrl2.x + at * (cur.ctrl1.x - left.ctrl2.x); + left.end.y = cur.start.y = left.ctrl2.y + at * (cur.ctrl1.y - left.ctrl2.y); } -static void _growOutlinePoint(SwOutline& outline, uint32_t n) +static float _bezAt(const Bezier& bz, float at) { - if (n == 0) { - free(outline.pts); - outline.pts = nullptr; - free(outline.types); - outline.types = nullptr; - outline.reservedPtsCnt = 0; - outline.ptsCnt = 0; - return; + auto len = _bezLength(bz); + auto biggest = 1.0f; + + if (at >= len) return 1.0f; + + at *= 0.5f; + + while (true) { + auto right = bz; + Bezier left; + _bezSplitLeft(right, at, left); + auto len2 = _bezLength(left); + + if (fabs(len2 - len) < FLT_EPSILON) break; + + if (len2 < len) { + at += (biggest - at) * 0.5f; + } else { + biggest = at; + at -= (at * 0.5f); + } } + return at; +} - if (outline.reservedPtsCnt >= outline.ptsCnt + n) return; - //cout << "Grow Pts: " << outline.reservedPtsCnt << " -> " << outline.ptsCnt + n << endl; - outline.reservedPtsCnt = n; - outline.pts = static_cast(realloc(outline.pts, n * sizeof(SwPoint))); +static void _bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right) +{ + right = cur; + auto t = _bezAt(right, at); + _bezSplitLeft(right, t, left); +} + + +static void _growOutlineContour(SwOutline& outline, uint32_t n) +{ + if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return; + outline.reservedCntrsCnt = outline.cntrsCnt + n; + outline.cntrs = static_cast(realloc(outline.cntrs, outline.reservedCntrsCnt * sizeof(uint32_t))); + assert(outline.cntrs); +} + + +static void _growOutlinePoint(SwOutline& outline, uint32_t n) +{ + if (outline.reservedPtsCnt >= outline.ptsCnt + n) return; + outline.reservedPtsCnt = outline.ptsCnt + n; + outline.pts = static_cast(realloc(outline.pts, outline.reservedPtsCnt * sizeof(SwPoint))); assert(outline.pts); - outline.types = static_cast(realloc(outline.types, n * sizeof(uint8_t))); + outline.types = static_cast(realloc(outline.types, outline.reservedPtsCnt * sizeof(uint8_t))); assert(outline.types); } -static void _freeOutline(SwOutline* outline) +static void _delOutline(SwOutline* outline) { if (!outline) return; @@ -112,7 +228,6 @@ static void _outlineLineTo(SwOutline& outline, const Point* to) outline.pts[outline.ptsCnt] = TO_SWPOINT(to); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; - ++outline.ptsCnt; } @@ -208,80 +323,271 @@ static bool _updateBBox(SwOutline* outline, SwBBox& bbox) } -static bool _checkValid(SwShape& sdata, const SwSize& clip) +static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) { - assert(sdata.outline); + assert(outline); - if (sdata.outline->ptsCnt == 0 || sdata.outline->cntrsCnt <= 0) return false; + if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) return false; //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)) return false; + if ((bbox.min.x > clip.w || bbox.min.y > clip.h) || + (bbox.min.x + bbox.max.x < 0) || + (bbox.min.y + bbox.max.y < 0)) return false; return true; } -/************************************************************************/ -/* External Class Implementation */ -/************************************************************************/ - -void shapeTransformOutline(const Shape& shape, SwShape& sdata, const RenderTransform& transform) +static void _transformOutline(SwOutline* outline, const RenderTransform* transform) { - auto outline = sdata.outline; assert(outline); + if (!transform) return; + for(uint32_t i = 0; i < outline->ptsCnt; ++i) { auto dx = static_cast(outline->pts[i].x >> 6); auto dy = static_cast(outline->pts[i].y >> 6); - auto tx = dx * transform.e11 + dy * transform.e12 + transform.e13; - auto ty = dx * transform.e21 + dy * transform.e22 + transform.e23; - auto pt = Point{tx + transform.e31, ty + transform.e32}; + auto tx = dx * transform->e11 + dy * transform->e12 + transform->e13; + auto ty = dx * transform->e21 + dy * transform->e22 + transform->e23; + auto pt = Point{tx + transform->e31, ty + transform->e32}; outline->pts[i] = TO_SWPOINT(&pt); } } -bool shapeGenRle(const Shape& shape, SwShape& sdata, const SwSize& clip) +static void _dashLineTo(SwDashStroke& dash, const Point* to) +{ + _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); + _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); + + Line cur = {dash.ptCur, *to}; + auto len = _lineLength(cur.pt1, cur.pt2); + + if (len < dash.curLen) { + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &dash.ptCur); + _outlineLineTo(*dash.outline, to); + } + } else { + while (len > dash.curLen) { + len -= dash.curLen; + Line left, right; + _lineSplitAt(cur, dash.curLen, left, right);; + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &left.pt1); + _outlineLineTo(*dash.outline, &left.pt2); + } + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + cur = right; + dash.ptCur = cur.pt1; + } + //leftovers + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &cur.pt1); + _outlineLineTo(*dash.outline, &cur.pt2); + } + if (dash.curLen < 1) { + //move to next dash + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + } + } + dash.ptCur = *to; +} + + +static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to) +{ + _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); + _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); + + Bezier cur = { dash.ptCur, *ctrl1, *ctrl2, *to}; + auto len = _bezLength(cur); + + if (len < dash.curLen) { + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &dash.ptCur); + _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to); + } + } else { + while (len > dash.curLen) { + Bezier left, right; + len -= dash.curLen; + _bezSplitAt(cur, dash.curLen, left, right); + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &left.start); + _outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end); + } + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + cur = right; + dash.ptCur = right.start; + } + //leftovers + dash.curLen -= len; + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &cur.start); + _outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end); + } + if (dash.curLen < 1) { + //move to next dash + dash.curIdx = (dash.curIdx + 1) % dash.cnt; + dash.curLen = dash.pattern[dash.curIdx]; + dash.curOpGap = !dash.curOpGap; + } + } + dash.ptCur = *to; +} + + +SwOutline* _genDashOutline(const Shape& shape) { - /* OPTIMIZE ME: We may avoid this bounding box calculation in this stage - if this shape has stroke and stroke bbox can be used here... */ - if (!_updateBBox(sdata.outline, sdata.bbox)) goto end; - if (!_checkValid(sdata, clip)) goto end; + const PathCommand* cmds = nullptr; + auto cmdCnt = shape.pathCommands(&cmds); + + const Point* pts = nullptr; + auto ptsCnt = shape.pathCoords(&pts); + + //No actual shape data + if (cmdCnt == 0 || ptsCnt == 0) return nullptr; + + SwDashStroke dash; + dash.curIdx = 0; + dash.curLen = 0; + dash.ptStart = {0, 0}; + dash.ptCur = {0, 0}; + dash.curOpGap = false; + + const float* pattern; + dash.cnt = shape.strokeDash(&pattern); + assert(dash.cnt > 0 && pattern); + + //Is it safe to mutual exclusive? + dash.pattern = const_cast(pattern); + dash.outline = static_cast(calloc(1, sizeof(SwOutline))); + assert(dash.outline); + dash.outline->opened = true; + + //smart reservation + auto outlinePtsCnt = 0; + auto outlineCntrsCnt = 0; + + for (uint32_t i = 0; i < cmdCnt; ++i) { + switch(*(cmds + i)) { + case PathCommand::Close: { + ++outlinePtsCnt; + break; + } + case PathCommand::MoveTo: { + ++outlineCntrsCnt; + ++outlinePtsCnt; + break; + } + case PathCommand::LineTo: { + ++outlinePtsCnt; + break; + } + case PathCommand::CubicTo: { + outlinePtsCnt += 3; + break; + } + } + } - sdata.rle = rleRender(sdata.outline, sdata.bbox, clip); + ++outlinePtsCnt; //for close + ++outlineCntrsCnt; //for end + + //Reserve Approximitely 20x... + _growOutlinePoint(*dash.outline, outlinePtsCnt * 20); + _growOutlineContour(*dash.outline, outlineCntrsCnt * 20); + while (cmdCnt-- > 0) { + switch(*cmds) { + case PathCommand::Close: { + _dashLineTo(dash, &dash.ptStart); + break; + } + case PathCommand::MoveTo: { + //reset the dash + dash.curIdx = 0; + dash.curLen = *dash.pattern; + dash.curOpGap = false; + dash.ptStart = dash.ptCur = *pts; + ++pts; + break; + } + case PathCommand::LineTo: { + _dashLineTo(dash, pts); + ++pts; + break; + } + case PathCommand::CubicTo: { + _dashCubicTo(dash, pts, pts + 1, pts + 2); + pts += 3; + break; + } + } + ++cmds; + } + + _outlineEnd(*dash.outline); + + return dash.outline; +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +bool shapeGenRle(SwShape& shape, const Shape& sdata, const SwSize& clip, const RenderTransform* transform) +{ + if (!shapeGenOutline(shape, sdata)) return false; + + _transformOutline(shape.outline, transform); + + if (!_updateBBox(shape.outline, shape.bbox)) goto end; + + if (!_checkValid(shape.outline, shape.bbox, clip)) goto end; + + shape.rle = rleRender(shape.outline, shape.bbox, clip); end: - if (sdata.rle) return true; + if (shape.rle) return true; return false; } -void shapeDelOutline(SwShape& sdata) +void shapeDelOutline(SwShape& shape) { - auto outline = sdata.outline; - _freeOutline(outline); - sdata.outline = nullptr; + auto outline = shape.outline; + _delOutline(outline); + shape.outline = nullptr; } -void shapeReset(SwShape& sdata) +void shapeReset(SwShape& shape) { - shapeDelOutline(sdata); - rleFree(sdata.rle); - sdata.rle = nullptr; - _initBBox(sdata.bbox); + shapeDelOutline(shape); + rleFree(shape.rle); + shape.rle = nullptr; + _initBBox(shape.bbox); } -bool shapeGenOutline(const Shape& shape, SwShape& sdata) +bool shapeGenOutline(SwShape& shape, const Shape& sdata) { const PathCommand* cmds = nullptr; - auto cmdCnt = shape.pathCommands(&cmds); + auto cmdCnt = sdata.pathCommands(&cmds); const Point* pts = nullptr; - auto ptsCnt = shape.pathCoords(&pts); + auto ptsCnt = sdata.pathCoords(&pts); //No actual shape data if (cmdCnt == 0 || ptsCnt == 0) return false; @@ -315,7 +621,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) ++outlinePtsCnt; //for close ++outlineCntrsCnt; //for end - auto outline = sdata.outline; + auto outline = shape.outline; if (!outline) outline = static_cast(calloc(1, sizeof(SwOutline))); assert(outline); outline->opened = true; @@ -354,7 +660,7 @@ bool shapeGenOutline(const Shape& shape, SwShape& sdata) //FIXME: //outline->flags = SwOutline::FillRule::Winding; - sdata.outline = outline; + shape.outline = outline; return true; } @@ -376,38 +682,52 @@ void shapeFree(SwShape* sdata) } -void shapeResetStroke(const Shape& shape, SwShape& sdata) +void shapeResetStroke(SwShape& shape, const Shape& sdata) { - if (!sdata.stroke) sdata.stroke = static_cast(calloc(1, sizeof(SwStroke))); - auto stroke = sdata.stroke; + if (!shape.stroke) shape.stroke = static_cast(calloc(1, sizeof(SwStroke))); + auto stroke = shape.stroke; assert(stroke); - strokeReset(*stroke, shape.strokeWidth(), shape.strokeCap(), shape.strokeJoin()); - rleFree(sdata.strokeRle); - sdata.strokeRle = nullptr; + + strokeReset(*stroke, sdata); + + rleFree(shape.strokeRle); + shape.strokeRle = nullptr; } -bool shapeGenStrokeRle(const Shape& shape, SwShape& sdata, const SwSize& clip) +bool shapeGenStrokeRle(SwShape& shape, const Shape& sdata, const SwSize& clip) { - if (!sdata.outline) { - if (!shapeGenOutline(shape, sdata)) return false; - } + SwOutline* shapeOutline = nullptr; - if (!_checkValid(sdata, clip)) return false; + //Dash Style Stroke + if (sdata.strokeDash(nullptr) > 0) { + shapeOutline = _genDashOutline(sdata); + if (!shapeOutline) return false; + + //Normal Style stroke + } else { + if (!shape.outline) { + if (!shapeGenOutline(shape, sdata)) return false; + } + shapeOutline = shape.outline; + } - if (!strokeParseOutline(*sdata.stroke, *sdata.outline)) return false; + if (!strokeParseOutline(*shape.stroke, *shapeOutline)) return false; - auto outline = strokeExportOutline(*sdata.stroke); - if (!outline) return false; + auto strokeOutline = strokeExportOutline(*shape.stroke); + if (!strokeOutline) return false; SwBBox bbox; - _updateBBox(outline, bbox); + _updateBBox(strokeOutline, bbox); - sdata.strokeRle = rleRender(outline, bbox, clip); + if (!_checkValid(strokeOutline, bbox, clip)) return false; - _freeOutline(outline); + shape.strokeRle = rleRender(strokeOutline, bbox, clip); + + _delOutline(strokeOutline); return true; } + #endif /* _TVG_SW_SHAPE_H_ */ diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 06ec989..fdc8cae 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -351,7 +351,7 @@ void _processCorner(SwStroke& stroke, SwFixed lineLength) } -void _subPathStart(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) +void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) { SwPoint delta = {stroke.width, 0}; mathRotate(delta, startAngle + ANGLE_PI2); @@ -390,7 +390,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) if (stroke.firstPt) { /* This is the first segment of a subpath. We need to add a point to each border at their respective starting point locations. */ - _subPathStart(stroke, angle, lineLength); + _firstSubPath(stroke, angle, lineLength); } else { //process the current corner stroke.angleOut = angle; @@ -455,7 +455,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl firstArc = false; //process corner if necessary if (stroke.firstPt) { - _subPathStart(stroke, angleIn, 0); + _firstSubPath(stroke, angleIn, 0); } else { stroke.angleOut = angleIn; _processCorner(stroke, 0); @@ -566,7 +566,6 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) SwPoint delta2 = {stroke.width, 0}; mathRotate(delta2, angle + rotate); - delta += stroke.center + delta2; _borderLineTo(border, delta, false); @@ -660,26 +659,26 @@ static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened) stroke.firstPt = true; stroke.center = to; - stroke.subPathOpen = opened; + stroke.openSubPath = opened; /* Determine if we need to check whether the border radius is greater than the radius of curvature of a curve, to handle this case specially. This is only required if bevel joins or butt caps may be created because round & miter joins and round & square caps cover the nagative sector created with wide strokes. */ - if ((stroke.join != StrokeJoin::Round) || (stroke.subPathOpen && stroke.cap == StrokeCap::Butt)) + if ((stroke.join != StrokeJoin::Round) || (stroke.openSubPath && stroke.cap == StrokeCap::Butt)) stroke.handleWideStrokes = true; else stroke.handleWideStrokes = false; - stroke.subPathStart = to; + stroke.ptStartSubPath = to; stroke.angleIn = 0; } static void _endSubPath(SwStroke& stroke) { - if (stroke.subPathOpen) { + if (stroke.openSubPath) { auto right = stroke.borders; assert(right); @@ -692,7 +691,7 @@ static void _endSubPath(SwStroke& stroke) _addReverseLeft(stroke, true); //now add the final cap - stroke.center = stroke.subPathStart; + stroke.center = stroke.ptStartSubPath; _addCap(stroke, stroke.subPathAngle + ANGLE_PI, 0); /* now end the right subpath accordingly. The left one is rewind @@ -701,8 +700,8 @@ static void _endSubPath(SwStroke& stroke) } else { //close the path if needed - if (stroke.center != stroke.subPathStart) - _lineTo(stroke, stroke.subPathStart); + if (stroke.center != stroke.ptStartSubPath) + _lineTo(stroke, stroke.ptStartSubPath); //process the corner stroke.angleOut = stroke.subPathAngle; @@ -792,7 +791,6 @@ static void _exportBorderOutline(SwStroke& stroke, SwOutline* outline, uint32_t ++cntrs; ++outline->cntrsCnt; } - ++src; ++tags; ++idx; @@ -820,13 +818,13 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) +void strokeReset(SwStroke& stroke, const Shape& shape) { - stroke.width = TO_SWCOORD(width * 0.5); - stroke.cap = cap; + stroke.width = TO_SWCOORD(shape.strokeWidth() * 0.5); + stroke.cap = shape.strokeCap(); //Save line join: it can be temporarily changed when stroking curves... - stroke.joinSaved = stroke.join = join; + stroke.joinSaved = stroke.join = shape.strokeJoin(); stroke.borders[0].ptsCnt = 0; stroke.borders[0].start = -1; @@ -838,7 +836,7 @@ void strokeReset(SwStroke& stroke, float width, StrokeCap cap, StrokeJoin join) } -bool strokeParseOutline(SwStroke& stroke, SwOutline& outline) +bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline) { uint32_t first = 0; @@ -926,5 +924,4 @@ SwOutline* strokeExportOutline(SwStroke& stroke) return outline; } - #endif /* _TVG_SW_STROKER_H_ */ diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 828e251..67d5ab7 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -328,7 +328,7 @@ int Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noe } -int Shape::stroke(const size_t* dashPattern, size_t cnt) noexcept +int Shape::stroke(const float* dashPattern, size_t cnt) noexcept { if (cnt < 2 || !dashPattern) return -1; @@ -341,7 +341,7 @@ int Shape::stroke(const size_t* dashPattern, size_t cnt) noexcept } -size_t Shape::strokeDash(const size_t** dashPattern) const noexcept +size_t Shape::strokeDash(const float** dashPattern) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index e1a4e9f..09956be 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -32,7 +32,7 @@ struct ShapeStroke { float width = 0; uint8_t color[4] = {0, 0, 0, 0}; - size_t* dashPattern = nullptr; + float* dashPattern = nullptr; size_t dashCnt = 0; StrokeCap cap = StrokeCap::Square; StrokeJoin join = StrokeJoin::Bevel; @@ -203,7 +203,7 @@ struct Shape::Impl return 0; } - bool strokeDash(const size_t* pattern, size_t cnt) + bool strokeDash(const float* pattern, size_t cnt) { assert(pattern); @@ -215,12 +215,13 @@ struct Shape::Impl stroke->dashPattern = nullptr; } - if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(size_t) * cnt)); + if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(float) * cnt)); assert(stroke->dashPattern); - memcpy(stroke->dashPattern, pattern, cnt); - stroke->dashCnt = cnt; + for (size_t i = 0; i < cnt; ++i) + stroke->dashPattern[i] = pattern[i]; + stroke->dashCnt = cnt; flag |= RenderUpdateFlag::Stroke; return 0; diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 8687b85..1288c07 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -17,6 +17,7 @@ void tvgtest() auto canvas = tvg::SwCanvas::gen(); canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + //Test for Stroke Width for (int i = 0; i < 10; ++i) { auto shape = tvg::Shape::gen(); shape->moveTo(50, 50 + (25 * i)); @@ -27,6 +28,8 @@ void tvgtest() canvas->push(move(shape)); } + + //Test for StrokeJoin & StrokeCap auto shape1 = tvg::Shape::gen(); shape1->moveTo(20, 350); shape1->lineTo(250, 350); @@ -63,6 +66,52 @@ void tvgtest() shape3->stroke(tvg::StrokeCap::Butt); canvas->push(move(shape3)); + //Test for Stroke Dash + auto shape4 = tvg::Shape::gen(); + shape4->moveTo(20, 600); + shape4->lineTo(250, 600); + shape4->lineTo(220, 750); + shape4->lineTo(70, 720); + shape4->lineTo(70, 580); + shape4->stroke(255, 0, 0, 255); + shape4->stroke(5); + shape4->stroke(tvg::StrokeJoin::Round); + shape4->stroke(tvg::StrokeCap::Round); + + float dashPattern1[2] = {10, 10}; + shape4->stroke(dashPattern1, 2); + canvas->push(move(shape4)); + + auto shape5 = tvg::Shape::gen(); + shape5->moveTo(270, 600); + shape5->lineTo(500, 600); + shape5->lineTo(470, 750); + shape5->lineTo(320, 720); + shape5->lineTo(320, 580); + shape5->stroke(255, 255, 0, 255); + shape5->stroke(5); + shape5->stroke(tvg::StrokeJoin::Bevel); + shape5->stroke(tvg::StrokeCap::Butt); + + float dashPattern2[4] = {10, 10}; + shape5->stroke(dashPattern2, 4); + canvas->push(move(shape5)); + + auto shape6 = tvg::Shape::gen(); + shape6->moveTo(520, 600); + shape6->lineTo(750, 600); + shape6->lineTo(720, 750); + shape6->lineTo(570, 720); + shape6->lineTo(570, 580); + shape6->stroke(255, 255, 255, 255); + shape6->stroke(5); + shape6->stroke(tvg::StrokeJoin::Miter); + shape6->stroke(tvg::StrokeCap::Square); + + float dashPattern3[2] = {10, 10}; + shape6->stroke(dashPattern3, 2); + canvas->push(move(shape6)); + canvas->draw(); canvas->sync(); -- 2.7.4 From 4e3f8284e8c02ba83587f16385e93ccce5a5439f Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 11:02:51 +0900 Subject: [PATCH 11/16] sw_engine: grow cell memory buffer up to allow larger shapes Change-Id: I7a8feaa11d3dad81dd1004782e07a8ac4a768d91 --- src/lib/sw_engine/tvgSwRle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 2757c0d..cab5463 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -633,7 +633,7 @@ static bool _genRle(RleWorker& rw) ret = _decomposeOutline(rw); if (!rw.invalid) _recordCell(rw); } else { - cout << "Memory Overflow" << endl; + cout << "Lack of Cell Memory" << endl; } return ret; } @@ -647,7 +647,7 @@ static bool _genRle(RleWorker& rw) SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) { //Please adjust when you out of cell memory (default: 16384L) - constexpr auto RENDER_POOL_SIZE = 166641L; + constexpr auto RENDER_POOL_SIZE = 163840L * 2; constexpr auto BAND_SIZE = 40; assert(outline); -- 2.7.4 From 33e1d4b170a52e07517d6e95791da5c30eb59044 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 14:18:58 +0900 Subject: [PATCH 12/16] common interface: concrete return type. Introduce Result type for notifying caller more detailed info. We should implement the result values for each apis, with practical values. Change-Id: Ia47abcb56a8efca7094ac3eed0178aeac8aa2910 --- inc/tizenvg.h | 87 ++++++++++---------- src/lib/sw_engine/tvgSwRenderer.cpp | 4 +- src/lib/tvgCanvas.cpp | 27 +++---- src/lib/tvgCanvasImpl.h | 36 ++++----- src/lib/tvgEngine.cpp | 8 +- src/lib/tvgGlCanvas.cpp | 12 +-- src/lib/tvgScene.cpp | 46 ++++++----- src/lib/tvgSceneImpl.h | 26 +++--- src/lib/tvgShape.cpp | 155 +++++++++++++++++++----------------- src/lib/tvgShapeImpl.h | 49 ++++++------ src/lib/tvgSwCanvas.cpp | 12 +-- 11 files changed, 238 insertions(+), 224 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 18db842..16e60f0 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -53,6 +53,7 @@ protected: \ namespace tvg { +enum class TIZENVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; enum class TIZENVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TIZENVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TIZENVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; @@ -79,11 +80,11 @@ class TIZENVG_EXPORT Paint public: virtual ~Paint() {} - virtual int rotate(float degree) = 0; - virtual int scale(float factor) = 0; - virtual int translate(float x, float y) = 0; + virtual Result rotate(float degree) = 0; + virtual Result scale(float factor) = 0; + virtual Result translate(float x, float y) = 0; - virtual int bounds(float* x, float* y, float* w, float* h) const = 0; + virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; }; @@ -101,13 +102,13 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); - int reserve(size_t n) noexcept; - virtual int push(std::unique_ptr paint) noexcept; - virtual int clear() noexcept; - virtual int update() noexcept; - virtual int update(Paint* paint) noexcept; - virtual int draw(bool async = true) noexcept; - virtual int sync() = 0; + Result reserve(size_t n) noexcept; + virtual Result push(std::unique_ptr paint) noexcept; + virtual Result clear() noexcept; + virtual Result update() noexcept; + virtual Result update(Paint* paint) noexcept; + virtual Result draw(bool async = true) noexcept; + virtual Result sync() = 0; _TIZENVG_DECLARE_ACCESSOR(Scene); _TIZENVG_DECLARE_PRIVATE(Canvas); @@ -127,42 +128,42 @@ class TIZENVG_EXPORT Shape final : public Paint public: ~Shape(); - int reset() noexcept; + Result reset() noexcept; //Path - int moveTo(float x, float y) noexcept; - int lineTo(float x, float y) noexcept; - int cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept; - int close() noexcept; + Result moveTo(float x, float y) noexcept; + Result lineTo(float x, float y) noexcept; + Result cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept; + Result close() noexcept; //Shape - int appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; - int appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; - int appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; + Result appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; + Result appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; + Result appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; //Stroke - int stroke(float width) noexcept; - int stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; - int stroke(const float* dashPattern, size_t cnt) noexcept; - int stroke(StrokeCap cap) noexcept; - int stroke(StrokeJoin join) noexcept; + Result stroke(float width) noexcept; + Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; + Result stroke(const float* dashPattern, size_t cnt) noexcept; + Result stroke(StrokeCap cap) noexcept; + Result stroke(StrokeJoin join) noexcept; //Fill - int fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; + Result fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; //Transform - int rotate(float degree) noexcept override; - int scale(float factor) noexcept override; - int translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept override; + Result scale(float factor) noexcept override; + Result translate(float x, float y) noexcept override; //Getters size_t pathCommands(const PathCommand** cmds) const noexcept; size_t pathCoords(const Point** pts) const noexcept; - int fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; - int bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; + Result bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; - int strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; + Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; size_t strokeDash(const float** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; @@ -188,14 +189,14 @@ class TIZENVG_EXPORT Scene final : public Paint public: ~Scene(); - int push(std::unique_ptr shape) noexcept; - int reserve(size_t size) noexcept; + Result push(std::unique_ptr shape) noexcept; + Result reserve(size_t size) noexcept; - int rotate(float degree) noexcept override; - int scale(float factor) noexcept override; - int translate(float x, float y) noexcept override; + Result rotate(float degree) noexcept override; + Result scale(float factor) noexcept override; + Result translate(float x, float y) noexcept override; - int bounds(float* x, float* y, float* w, float* h) const noexcept override; + Result bounds(float* x, float* y, float* w, float* h) const noexcept override; static std::unique_ptr gen() noexcept; @@ -217,8 +218,8 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; - int sync() noexcept override; + Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result sync() noexcept override; static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(SwCanvas); @@ -240,8 +241,8 @@ public: //TODO: Gl Specific methods. Need gl backend configuration methods as well. - int target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; - int sync() noexcept override; + Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result sync() noexcept override; static std::unique_ptr gen() noexcept; _TIZENVG_DECLARE_PRIVATE(GlCanvas); @@ -270,8 +271,8 @@ public: * * @see ... */ - static int init() noexcept; - static int term() noexcept; + static Result init() noexcept; + static Result term() noexcept; _TIZENVG_DISABLE_CTOR(Engine); }; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 5461abe..60c3a6d 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -47,7 +47,7 @@ bool SwRenderer::clear() bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) { - assert(buffer && stride > 0 && w > 0 && h > 0); + if (!buffer || stride == 0 || w == 0 || h == 0) return false; surface.buffer = buffer; surface.stride = stride; @@ -77,7 +77,7 @@ bool SwRenderer::render(const Shape& shape, void *data) bool SwRenderer::dispose(const Shape& shape, void *data) { auto sdata = static_cast(data); - if (!sdata) return false; + if (!sdata) return true; shapeFree(sdata); return true; } diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index f31373e..79057c7 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -34,52 +34,51 @@ Canvas::~Canvas() } -int Canvas::reserve(size_t n) noexcept +Result Canvas::reserve(size_t n) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; impl->paints.reserve(n); - return 0; + return Result::Success; } -int Canvas::push(unique_ptr paint) noexcept +Result Canvas::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); - assert(impl); - + if (!impl) return Result::MemoryCorruption; return impl->push(move(paint)); } -int Canvas::clear() noexcept +Result Canvas::clear() noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->clear(); } -int Canvas::draw(bool async) noexcept +Result Canvas::draw(bool async) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->draw(); } -int Canvas::update() noexcept +Result Canvas::update() noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->update(); } -int Canvas::update(Paint* paint) noexcept +Result Canvas::update(Paint* paint) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; return impl->update(paint); } diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index afa2a0b..782dd94 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -39,7 +39,7 @@ struct Canvas::Impl renderer->unref(); } - int push(unique_ptr paint) + Result push(unique_ptr paint) { auto p = paint.release(); assert(p); @@ -48,64 +48,64 @@ struct Canvas::Impl return update(p); } - int clear() + Result clear() { assert(renderer); for (auto paint : paints) { if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->clear(*renderer)) return -1; + if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->dispose(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->dispose(*shape, *renderer)) return Result::InsufficientCondition; } delete(paint); } paints.clear(); - return 0; + return Result::Success; } - int update() + Result update() { assert(renderer); for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->update(*renderer, nullptr)) return -1; + if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return -1; + if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return Result::InsufficientCondition; } } - return 0; + return Result::Success; } - int update(Paint* paint) + Result update(Paint* paint) { assert(renderer); if (auto scene = dynamic_cast(paint)) { - if (!SCENE_IMPL->update(*renderer)) return -1; + if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if (!SHAPE_IMPL->update(*shape, *renderer)) return -1; + if (!SHAPE_IMPL->update(*shape, *renderer)) return Result::InsufficientCondition; } - return 0; + return Result::Success; } - int draw() + Result draw() { assert(renderer); //Clear render target before drawing - if (!renderer->clear()) return -1; + if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { - if(!SCENE_IMPL->render(*renderer)) return -1; + if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; } else if (auto shape = dynamic_cast(paint)) { - if(!SHAPE_IMPL->render(*shape, *renderer)) return -1; + if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition; } } - return 0; + return Result::Success; } }; diff --git a/src/lib/tvgEngine.cpp b/src/lib/tvgEngine.cpp index fa005dc..40b1308 100644 --- a/src/lib/tvgEngine.cpp +++ b/src/lib/tvgEngine.cpp @@ -30,7 +30,7 @@ /* External Class Implementation */ /************************************************************************/ -int Engine::init() noexcept +Result Engine::init() noexcept { //TODO: Initialize Raster engines by configuration. @@ -38,17 +38,17 @@ int Engine::init() noexcept ret |= SwRenderer::init(); ret |= GlRenderer::init(); - return ret; + return Result::Success; } -int Engine::term() noexcept +Result Engine::term() noexcept { int ret = 0; ret |= SwRenderer::term(); ret |= GlRenderer::term(); - return ret; + return Result::Success; } #endif /* _TVG_ENGINE_CPP_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index c1b7aeb..2bf3868 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -45,20 +45,20 @@ GlCanvas::~GlCanvas() } -int GlCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result GlCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); - assert(renderer); + if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return -1; + if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; - return 0; + return Result::Success; } -int GlCanvas::sync() noexcept +Result GlCanvas::sync() noexcept { - return 0; + return Result::Success; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 93a64b1..12b96ec 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -40,65 +40,71 @@ unique_ptr Scene::gen() noexcept } -int Scene::push(unique_ptr paint) noexcept +Result Scene::push(unique_ptr paint) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; auto p = paint.release(); - assert(p); + if (!p) return Result::MemoryCorruption; impl->paints.push_back(p); - return 0; + return Result::Success; } -int Scene::reserve(size_t size) noexcept +Result Scene::reserve(size_t size) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; impl->paints.reserve(size); - return 0; + return Result::Success; } -int Scene::scale(float factor) noexcept +Result Scene::scale(float factor) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->scale(factor); + if (!impl->scale(factor)) return Result::FailedAllocation; + + return Result::Success; } -int Scene::rotate(float degree) noexcept +Result Scene::rotate(float degree) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; + + if (!impl->rotate(degree)) return Result::FailedAllocation; - return impl->rotate(degree); + return Result::Success; } -int Scene::translate(float x, float y) noexcept +Result Scene::translate(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; + + if (!impl->translate(x, y)) return Result::FailedAllocation; - return impl->translate(x, y); + return Result::Success; } -int Scene::bounds(float* x, float* y, float* w, float* h) const noexcept +Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->bounds(x, y, w, h)) return -1; + if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - return 0; + return Result::Success; } #endif /* _TVG_SCENE_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 9064b53..a08afc6 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -66,7 +66,7 @@ struct Scene::Impl bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { - assert(transform); + if (!transform) return false; if (!transform->update()) { delete(transform); transform = nullptr; @@ -137,47 +137,47 @@ struct Scene::Impl bool scale(float factor) { if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return -1; + if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; } else { - if (fabsf(factor) <= FLT_EPSILON) return -1; + if (fabsf(factor) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->factor = factor; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool rotate(float degree) { if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return -1; + if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; } else { - if (fabsf(degree) <= FLT_EPSILON) return -1; + if (fabsf(degree) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->degree = degree; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool translate(float x, float y) { if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return -1; + if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return -1; + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->x = x; transform->y = y; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } }; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 67d5ab7..c41c6b1 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -46,23 +46,25 @@ unique_ptr Shape::gen() noexcept } -int Shape::reset() noexcept +Result Shape::reset() noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->reset(); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } size_t Shape::pathCommands(const PathCommand** cmds) const noexcept { + if (!cmds) return 0; + auto impl = pImpl.get(); - assert(impl && impl->path && cmds); + if (!impl || !impl->path) return 0; *cmds = impl->path->cmds; @@ -72,8 +74,10 @@ size_t Shape::pathCommands(const PathCommand** cmds) const noexcept size_t Shape::pathCoords(const Point** pts) const noexcept { + if (!pts) return 0; + auto impl = pImpl.get(); - assert(impl && impl->path && pts); + if (!impl || !impl->path) return 0; *pts = impl->path->pts; @@ -81,79 +85,78 @@ size_t Shape::pathCoords(const Point** pts) const noexcept } -int Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +Result Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept { - if (cmdCnt < 0 || ptsCnt < 0) return -1; - assert(cmds && pts); + if (cmdCnt < 0 || ptsCnt < 0 || !pts || !ptsCnt) return Result::InvalidArguments; auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->grow(cmdCnt, ptsCnt); impl->path->append(cmds, cmdCnt, pts, ptsCnt); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::moveTo(float x, float y) noexcept +Result Shape::moveTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->moveTo(x, y); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::lineTo(float x, float y) noexcept +Result Shape::lineTo(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->lineTo(x, y); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept +Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->cubicTo(cx1, cy1, cx2, cy2, x, y); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::close() noexcept +Result Shape::close() noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; impl->path->close(); impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept +Result Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; auto halfKappaW = radiusW * PATH_KAPPA; auto halfKappaH = radiusH * PATH_KAPPA; @@ -168,14 +171,14 @@ int Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexce impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept +Result Shape::appendRect(float x, float y, float w, float h, float cornerRadius) noexcept { auto impl = pImpl.get(); - assert(impl && impl->path); + if (!impl || !impl->path) return Result::MemoryCorruption; //clamping cornerRadius by minimum size auto min = (w < h ? w : h) * 0.5f; @@ -209,14 +212,14 @@ int Shape::appendRect(float x, float y, float w, float h, float cornerRadius) no impl->flag |= RenderUpdateFlag::Path; - return 0; + return Result::Success; } -int Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept +Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; impl->color[0] = r; impl->color[1] = g; @@ -224,120 +227,126 @@ int Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept impl->color[3] = a; impl->flag |= RenderUpdateFlag::Fill; - return 0; + return Result::Success; } -int Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept +Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; if (r) *r = impl->color[0]; if (g) *g = impl->color[1]; if (b) *b = impl->color[2]; if (a) *a = impl->color[3]; - return 0; + return Result::Success; } -int Shape::scale(float factor) noexcept +Result Shape::scale(float factor) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->scale(factor); + if (!impl->scale(factor)) return Result::FailedAllocation; + + return Result::Success; } -int Shape::rotate(float degree) noexcept +Result Shape::rotate(float degree) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->rotate(degree); + if (!impl->rotate(degree)) return Result::FailedAllocation; + + return Result::Success; } -int Shape::translate(float x, float y) noexcept +Result Shape::translate(float x, float y) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - return impl->translate(x, y); + impl->translate(x, y); + + return Result::Success; } -int Shape::bounds(float* x, float* y, float* w, float* h) const noexcept +Result Shape::bounds(float* x, float* y, float* w, float* h) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->bounds(x, y, w, h)) return -1; + if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - return 0; + return Result::Success; } -int Shape::stroke(float width) noexcept +Result Shape::stroke(float width) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeWidth(width)) return -1; + if (!impl->strokeWidth(width)) return Result::FailedAllocation; - return 0; + return Result::Success; } float Shape::strokeWidth() const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return 0; if (!impl->stroke) return 0; return impl->stroke->width; } -int Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept +Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeColor(r, g, b, a)) return -1; + if (!impl->strokeColor(r, g, b, a)) return Result::FailedAllocation; - return 0; + return Result::Success; } -int Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept +Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->stroke) return -1; + if (!impl->stroke) return Result::InsufficientCondition; if (r) *r = impl->stroke->color[0]; if (g) *g = impl->stroke->color[1]; if (b) *b = impl->stroke->color[2]; if (a) *a = impl->stroke->color[3]; - return 0; + return Result::Success; } -int Shape::stroke(const float* dashPattern, size_t cnt) noexcept +Result Shape::stroke(const float* dashPattern, size_t cnt) noexcept { - if (cnt < 2 || !dashPattern) return -1; + if (cnt < 2 || !dashPattern) return Result::InvalidArguments; auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeDash(dashPattern, cnt)) return -1; + if (!impl->strokeDash(dashPattern, cnt)) return Result::FailedAllocation; - return 0; + return Result::Success; } @@ -353,25 +362,25 @@ size_t Shape::strokeDash(const float** dashPattern) const noexcept } -int Shape::stroke(StrokeCap cap) noexcept +Result Shape::stroke(StrokeCap cap) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeCap(cap)) return -1; + if (!impl->strokeCap(cap)) return Result::FailedAllocation; - return 0; + return Result::Success; } -int Shape::stroke(StrokeJoin join) noexcept +Result Shape::stroke(StrokeJoin join) noexcept { auto impl = pImpl.get(); - assert(impl); + if (!impl) return Result::MemoryCorruption; - if (!impl->strokeJoin(join)) return -1; + if (!impl->strokeJoin(join)) return Result::FailedAllocation; - return 0; + return Result::Success; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 09956be..9218417 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -80,7 +80,7 @@ struct Shape::Impl bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { - assert(transform); + if (!transform) return false; if (!transform->update()) { delete(transform); transform = nullptr; @@ -103,54 +103,54 @@ struct Shape::Impl bool bounds(float* x, float* y, float* w, float* h) { - assert(path); + if (!path) return false; return path->bounds(x, y, w, h); } bool scale(float factor) { if (transform) { - if (fabsf(factor - transform->factor) <= FLT_EPSILON) return -1; + if (fabsf(factor - transform->factor) <= FLT_EPSILON) return true; } else { - if (fabsf(factor) <= FLT_EPSILON) return -1; + if (fabsf(factor) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->factor = factor; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool rotate(float degree) { if (transform) { - if (fabsf(degree - transform->degree) <= FLT_EPSILON) return -1; + if (fabsf(degree - transform->degree) <= FLT_EPSILON) return true; } else { - if (fabsf(degree) <= FLT_EPSILON) return -1; + if (fabsf(degree) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->degree = degree; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool translate(float x, float y) { if (transform) { - if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return -1; + if (fabsf(x - transform->x) <= FLT_EPSILON && fabsf(y - transform->y) <= FLT_EPSILON) return true; } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return -1; + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; transform = new RenderTransform(); - assert(transform); + if (!transform) return false; } transform->x = x; transform->y = y; flag |= RenderUpdateFlag::Transform; - return 0; + return true; } bool strokeWidth(float width) @@ -158,40 +158,40 @@ struct Shape::Impl //TODO: Size Exception? if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->width = width; flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeCap(StrokeCap cap) { if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->cap = cap; flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeJoin(StrokeJoin join) { if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->join = join; flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; stroke->color[0] = r; stroke->color[1] = g; @@ -200,7 +200,7 @@ struct Shape::Impl flag |= RenderUpdateFlag::Stroke; - return 0; + return true; } bool strokeDash(const float* pattern, size_t cnt) @@ -208,7 +208,7 @@ struct Shape::Impl assert(pattern); if (!stroke) stroke = new ShapeStroke(); - assert(stroke); + if (!stroke) return false; if (stroke->dashCnt != cnt) { if (stroke->dashPattern) free(stroke->dashPattern); @@ -224,8 +224,7 @@ struct Shape::Impl stroke->dashCnt = cnt; flag |= RenderUpdateFlag::Stroke; - return 0; - + return true; } }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index ea95e98..ec18dbf 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,20 +45,20 @@ SwCanvas::~SwCanvas() { } -int SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); - assert(renderer); + if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return -1; + if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; - return 0; + return Result::Success; } -int SwCanvas::sync() noexcept +Result SwCanvas::sync() noexcept { - return 0; + return Result::Success; } -- 2.7.4 From 58de99aea32d76242e4f875918c0608848aac233 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 15:22:33 +0900 Subject: [PATCH 13/16] common interface: replace arguements size_t to uint32_t We prefer to build up a tiny compact engine at memory rather than compatibility, this engine is not considerd for end-users but designed for middle-level framework and some low-level users. Thus, we won't consider 64bits data size, use explicit 32 bits data until coming next upgrade... Change-Id: I0704d5f1e0eb909cccc10922bc5972e115fbbcc0 --- inc/tizenvg.h | 18 +++++++++--------- src/lib/gl_engine/tvgGlGpuBuffer.h | 4 ++-- src/lib/gl_engine/tvgGlRenderer.cpp | 4 ++-- src/lib/gl_engine/tvgGlRenderer.h | 6 +++--- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwRenderer.cpp | 6 +++--- src/lib/sw_engine/tvgSwRenderer.h | 6 +++--- src/lib/tvgCanvas.cpp | 2 +- src/lib/tvgGlCanvas.cpp | 2 +- src/lib/tvgRenderCommon.h | 14 +++++++------- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 6 +++--- src/lib/tvgShape.cpp | 10 +++++----- src/lib/tvgShapeImpl.h | 10 +++++----- src/lib/tvgShapePath.h | 18 +++++++++--------- src/lib/tvgSwCanvas.cpp | 2 +- 16 files changed, 56 insertions(+), 56 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 16e60f0..88abfdd 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -102,7 +102,7 @@ public: Canvas(RenderMethod*); virtual ~Canvas(); - Result reserve(size_t n) noexcept; + Result reserve(uint32_t n) noexcept; virtual Result push(std::unique_ptr paint) noexcept; virtual Result clear() noexcept; virtual Result update() noexcept; @@ -139,12 +139,12 @@ public: //Shape Result appendRect(float x, float y, float w, float h, float cornerRadius) noexcept; Result appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept; - Result appendPath(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept; + Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept; //Stroke Result stroke(float width) noexcept; Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; - Result stroke(const float* dashPattern, size_t cnt) noexcept; + Result stroke(const float* dashPattern, uint32_t cnt) noexcept; Result stroke(StrokeCap cap) noexcept; Result stroke(StrokeJoin join) noexcept; @@ -157,14 +157,14 @@ public: Result translate(float x, float y) noexcept override; //Getters - size_t pathCommands(const PathCommand** cmds) const noexcept; - size_t pathCoords(const Point** pts) const noexcept; + uint32_t pathCommands(const PathCommand** cmds) const noexcept; + uint32_t pathCoords(const Point** pts) const noexcept; Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; Result bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; - size_t strokeDash(const float** dashPattern) const noexcept; + uint32_t strokeDash(const float** dashPattern) const noexcept; StrokeCap strokeCap() const noexcept; StrokeJoin strokeJoin() const noexcept; @@ -190,7 +190,7 @@ public: ~Scene(); Result push(std::unique_ptr shape) noexcept; - Result reserve(size_t size) noexcept; + Result reserve(uint32_t size) noexcept; Result rotate(float degree) noexcept override; Result scale(float factor) noexcept override; @@ -218,7 +218,7 @@ class TIZENVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; static std::unique_ptr gen() noexcept; @@ -241,7 +241,7 @@ public: //TODO: Gl Specific methods. Need gl backend configuration methods as well. - Result target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept; + Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; static std::unique_ptr gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h index fd7086a..79dd26d 100644 --- a/src/lib/gl_engine/tvgGlGpuBuffer.h +++ b/src/lib/gl_engine/tvgGlGpuBuffer.h @@ -2,7 +2,7 @@ #define _TVG_GL_GPU_BUFFER_H_ #include -#include +#include class GlGpuBuffer { @@ -15,7 +15,7 @@ public: GlGpuBuffer(); ~GlGpuBuffer(); - void updateBufferData(Target target, size_t size, void* data); + void updateBufferData(Target target, uint32_t size, void* data); private: uint32_t mGlBufferId = 0; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 0eb9beb..14bdbaa 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -95,13 +95,13 @@ int GlRenderer::term() } -size_t GlRenderer::unref() +uint32_t GlRenderer::unref() { return RenderInitializer::unref(renderInit); } -size_t GlRenderer::ref() +uint32_t GlRenderer::ref() { return RenderInitializer::ref(renderInit); } diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index fcde08f..3ef0ee9 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -30,13 +30,13 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, size_t stride, size_t w, size_t h) + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) { return 0; }; bool clear() override; - size_t ref() override; - size_t unref() override; + uint32_t ref() override; + uint32_t unref() override; static GlRenderer* inst(); static int init(); diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 16d4c1e..e6f432d 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -149,7 +149,7 @@ struct SwDashStroke Point ptStart; Point ptCur; float* pattern; - size_t cnt; + uint32_t cnt; bool curOpGap; }; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 60c3a6d..d2143fe 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -45,7 +45,7 @@ bool SwRenderer::clear() return true; } -bool SwRenderer::target(uint32_t* buffer, size_t stride, size_t w, size_t h) +bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) { if (!buffer || stride == 0 || w == 0 || h == 0) return false; @@ -137,13 +137,13 @@ int SwRenderer::term() } -size_t SwRenderer::unref() +uint32_t SwRenderer::unref() { return RenderInitializer::unref(renderInit); } -size_t SwRenderer::ref() +uint32_t SwRenderer::ref() { return RenderInitializer::ref(renderInit); } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 3dfb076..4a4fafd 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -25,10 +25,10 @@ public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, size_t stride, size_t w, size_t h); + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool clear() override; - size_t ref() override; - size_t unref() override; + uint32_t ref() override; + uint32_t unref() override; static SwRenderer* inst(); static int init(); diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index 79057c7..dc05d66 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -34,7 +34,7 @@ Canvas::~Canvas() } -Result Canvas::reserve(size_t n) noexcept +Result Canvas::reserve(uint32_t n) noexcept { auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 2bf3868..024fed5 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -45,7 +45,7 @@ GlCanvas::~GlCanvas() } -Result GlCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 61cd655..0e98e17 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -24,8 +24,8 @@ struct Surface { //TODO: Union for multiple types uint32_t* buffer; - size_t stride; - size_t w, h; + uint32_t stride; + uint32_t w, h; }; enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Stroke = 4, Transform = 8, All = 16}; @@ -126,14 +126,14 @@ public: virtual bool dispose(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0; virtual bool clear() = 0; - virtual size_t ref() = 0; - virtual size_t unref() = 0; + virtual uint32_t ref() = 0; + virtual uint32_t unref() = 0; }; struct RenderInitializer { RenderMethod* pInst = nullptr; - size_t refCnt = 0; + uint32_t refCnt = 0; bool initialized = false; static int init(RenderInitializer& renderInit, RenderMethod* engine) @@ -160,7 +160,7 @@ struct RenderInitializer return 0; } - static size_t unref(RenderInitializer& renderInit) + static uint32_t unref(RenderInitializer& renderInit) { assert(renderInit.refCnt > 0); --renderInit.refCnt; @@ -181,7 +181,7 @@ struct RenderInitializer return renderInit.pInst; } - static size_t ref(RenderInitializer& renderInit) + static uint32_t ref(RenderInitializer& renderInit) { return ++renderInit.refCnt; } diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 12b96ec..75e2720 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -53,7 +53,7 @@ Result Scene::push(unique_ptr paint) noexcept } -Result Scene::reserve(size_t size) noexcept +Result Scene::reserve(uint32_t size) noexcept { auto impl = pImpl.get(); if (!impl) return Result::MemoryCorruption; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index a08afc6..edaa6d8 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -27,7 +27,7 @@ struct Scene::Impl { vector paints; RenderTransform *transform = nullptr; - size_t flag = RenderUpdateFlag::None; + uint32_t flag = RenderUpdateFlag::None; ~Impl() { @@ -51,7 +51,7 @@ struct Scene::Impl return true; } - bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, size_t flag) + bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { if (auto scene = dynamic_cast(paint)) { @@ -63,7 +63,7 @@ struct Scene::Impl return true; } - bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) + bool update(RenderMethod &renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { if (!transform) return false; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index c41c6b1..ad1736b 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -59,7 +59,7 @@ Result Shape::reset() noexcept } -size_t Shape::pathCommands(const PathCommand** cmds) const noexcept +uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept { if (!cmds) return 0; @@ -72,7 +72,7 @@ size_t Shape::pathCommands(const PathCommand** cmds) const noexcept } -size_t Shape::pathCoords(const Point** pts) const noexcept +uint32_t Shape::pathCoords(const Point** pts) const noexcept { if (!pts) return 0; @@ -85,7 +85,7 @@ size_t Shape::pathCoords(const Point** pts) const noexcept } -Result Shape::appendPath(const PathCommand *cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) noexcept +Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept { if (cmdCnt < 0 || ptsCnt < 0 || !pts || !ptsCnt) return Result::InvalidArguments; @@ -337,7 +337,7 @@ Result Shape::strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const } -Result Shape::stroke(const float* dashPattern, size_t cnt) noexcept +Result Shape::stroke(const float* dashPattern, uint32_t cnt) noexcept { if (cnt < 2 || !dashPattern) return Result::InvalidArguments; @@ -350,7 +350,7 @@ Result Shape::stroke(const float* dashPattern, size_t cnt) noexcept } -size_t Shape::strokeDash(const float** dashPattern) const noexcept +uint32_t Shape::strokeDash(const float** dashPattern) const noexcept { auto impl = pImpl.get(); assert(impl); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 9218417..08acb36 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -33,7 +33,7 @@ struct ShapeStroke float width = 0; uint8_t color[4] = {0, 0, 0, 0}; float* dashPattern = nullptr; - size_t dashCnt = 0; + uint32_t dashCnt = 0; StrokeCap cap = StrokeCap::Square; StrokeJoin join = StrokeJoin::Bevel; @@ -51,7 +51,7 @@ struct Shape::Impl ShapePath *path = nullptr; RenderTransform *transform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a - size_t flag = RenderUpdateFlag::None; + uint32_t flag = RenderUpdateFlag::None; void *edata = nullptr; //engine data @@ -77,7 +77,7 @@ struct Shape::Impl return renderer.render(shape, edata); } - bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, size_t pFlag = 0) + bool update(Shape& shape, RenderMethod& renderer, const RenderTransform* pTransform = nullptr, uint32_t pFlag = 0) { if (flag & RenderUpdateFlag::Transform) { if (!transform) return false; @@ -203,7 +203,7 @@ struct Shape::Impl return true; } - bool strokeDash(const float* pattern, size_t cnt) + bool strokeDash(const float* pattern, uint32_t cnt) { assert(pattern); @@ -218,7 +218,7 @@ struct Shape::Impl if (!stroke->dashPattern) stroke->dashPattern = static_cast(malloc(sizeof(float) * cnt)); assert(stroke->dashPattern); - for (size_t i = 0; i < cnt; ++i) + for (uint32_t i = 0; i < cnt; ++i) stroke->dashPattern[i] = pattern[i]; stroke->dashCnt = cnt; diff --git a/src/lib/tvgShapePath.h b/src/lib/tvgShapePath.h index 7e020e8..38ed3eb 100644 --- a/src/lib/tvgShapePath.h +++ b/src/lib/tvgShapePath.h @@ -26,12 +26,12 @@ struct ShapePath { PathCommand* cmds = nullptr; - size_t cmdCnt = 0; - size_t reservedCmdCnt = 0; + uint32_t cmdCnt = 0; + uint32_t reservedCmdCnt = 0; Point *pts = nullptr; - size_t ptsCnt = 0; - size_t reservedPtsCnt = 0; + uint32_t ptsCnt = 0; + uint32_t reservedPtsCnt = 0; ~ShapePath() @@ -40,7 +40,7 @@ struct ShapePath if (pts) free(pts); } - void reserveCmd(size_t cmdCnt) + void reserveCmd(uint32_t cmdCnt) { if (cmdCnt <= reservedCmdCnt) return; reservedCmdCnt = cmdCnt; @@ -48,7 +48,7 @@ struct ShapePath assert(cmds); } - void reservePts(size_t ptsCnt) + void reservePts(uint32_t ptsCnt) { if (ptsCnt <= reservedPtsCnt) return; reservedPtsCnt = ptsCnt; @@ -56,7 +56,7 @@ struct ShapePath assert(pts); } - void grow(size_t cmdCnt, size_t ptsCnt) + void grow(uint32_t cmdCnt, uint32_t ptsCnt) { reserveCmd(this->cmdCnt + cmdCnt); reservePts(this->ptsCnt + ptsCnt); @@ -68,7 +68,7 @@ struct ShapePath ptsCnt = 0; } - void append(const PathCommand* cmds, size_t cmdCnt, const Point* pts, size_t ptsCnt) + void append(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) { memcpy(this->cmds + this->cmdCnt, cmds, sizeof(PathCommand) * cmdCnt); memcpy(this->pts + this->ptsCnt, pts, sizeof(Point) * ptsCnt); @@ -120,7 +120,7 @@ struct ShapePath Point min = { pts[0].x, pts[0].y }; Point max = { pts[0].x, pts[0].y }; - for(size_t i = 1; i < ptsCnt; ++i) { + for(uint32_t i = 1; i < ptsCnt; ++i) { if (pts[i].x < min.x) min.x = pts[i].x; if (pts[i].y < min.y) min.y = pts[i].y; if (pts[i].x > max.x) max.x = pts[i].x; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index ec18dbf..560a975 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -45,7 +45,7 @@ SwCanvas::~SwCanvas() { } -Result SwCanvas::target(uint32_t* buffer, size_t stride, size_t w, size_t h) noexcept +Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; -- 2.7.4 From 498a024df8a48ea5caf96722a7781906909310be Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 20:17:39 +0900 Subject: [PATCH 14/16] common: ++optimization replace dynamic_cast to static_cast, This can be a controversial choice between optmization and clean code. Obviously we know the converting types, try avoiding a bit heavier casting some cases. Change-Id: Id763e6d1db449a229a492ab5b1a901a195936152 --- inc/tizenvg.h | 15 +++++++++++++-- src/lib/gl_engine/tvgGlRenderer.cpp | 3 ++- src/lib/sw_engine/tvgSwRenderer.cpp | 3 ++- src/lib/tvgCanvasImpl.h | 28 ++++++++++++++++++++-------- src/lib/tvgCommon.h | 3 +++ src/lib/tvgGlCanvas.cpp | 3 ++- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 28 ++++++++++++++++++++-------- src/lib/tvgShape.cpp | 1 + src/lib/tvgSwCanvas.cpp | 3 ++- 10 files changed, 66 insertions(+), 23 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 88abfdd..309badd 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -50,16 +50,23 @@ protected: \ A() = delete; \ ~A() = delete +#define _TIZENVG_IDENTIFIER(A) \ +protected: \ + unsigned A##_Id + namespace tvg { +class RenderMethod; +class Scene; +class Canvas; + + enum class TIZENVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; enum class TIZENVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; enum class TIZENVG_EXPORT StrokeCap { Square = 0, Round, Butt }; enum class TIZENVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; -class RenderMethod; -class Scene; struct Point { @@ -85,6 +92,10 @@ public: virtual Result translate(float x, float y) = 0; virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; + + _TIZENVG_IDENTIFIER(Paint); + _TIZENVG_DECLARE_ACCESSOR(Scene); + _TIZENVG_DECLARE_ACCESSOR(Canvas); }; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 14bdbaa..1ca9588 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -109,7 +109,8 @@ uint32_t GlRenderer::ref() GlRenderer* GlRenderer::inst() { - return dynamic_cast(RenderInitializer::inst(renderInit)); + //We know renderer type, avoid dynamic_cast for performance. + return static_cast(RenderInitializer::inst(renderInit)); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index d2143fe..59c4910 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -151,7 +151,8 @@ uint32_t SwRenderer::ref() SwRenderer* SwRenderer::inst() { - return dynamic_cast(RenderInitializer::inst(renderInit)); + //We know renderer type, avoid dynamic_cast for performance. + return static_cast(RenderInitializer::inst(renderInit)); } #endif /* _TVG_SW_RENDERER_CPP_ */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 782dd94..078385a 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -53,9 +53,12 @@ struct Canvas::Impl assert(renderer); for (auto paint : paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->dispose(*shape, *renderer)) return Result::InsufficientCondition; } delete(paint); @@ -70,9 +73,12 @@ struct Canvas::Impl assert(renderer); for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->update(*shape, *renderer, nullptr)) return Result::InsufficientCondition; } } @@ -83,9 +89,12 @@ struct Canvas::Impl { assert(renderer); - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->update(*shape, *renderer)) return Result::InsufficientCondition; } return Result::Success; @@ -99,9 +108,12 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition; } } diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index c404f1f..ca18cca 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -31,6 +31,9 @@ using namespace tvg; #define SCENE_IMPL scene->pImpl.get() #define SHAPE_IMPL shape->pImpl.get() +#define PAINT_ID_SHAPE 0 +#define PAINT_ID_SCENE 1 + #include "tvgRenderCommon.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 024fed5..7d3903c 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -47,7 +47,8 @@ GlCanvas::~GlCanvas() Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { - auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); + //We know renderer type, avoid dynamic_cast for performance. + auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 75e2720..a1c7a7f 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,7 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - + Paint_Id = PAINT_ID_SCENE; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index edaa6d8..1f1fa14 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -39,9 +39,12 @@ struct Scene::Impl bool clear(RenderMethod& renderer) { for (auto paint : paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->clear(renderer)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->dispose(*shape, renderer)) return false; } delete(paint); @@ -54,9 +57,12 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->update(renderer, transform, flag)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->update(*shape, renderer, transform, flag)) return false; } } @@ -91,9 +97,12 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if(!SCENE_IMPL->render(renderer)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if(!SHAPE_IMPL->render(*shape, renderer)) return false; } } @@ -113,9 +122,12 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (auto scene = dynamic_cast(paint)) { + if (paint->Paint_Id == PAINT_ID_SCENE) { + //We know renderer type, avoid dynamic_cast for performance. + auto scene = static_cast(paint); if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; - } else if (auto shape = dynamic_cast(paint)) { + } else { + auto shape = static_cast(paint); if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; } diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index ad1736b..5119ac8 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -32,6 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { + Paint_Id = PAINT_ID_SHAPE; } diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 560a975..780e463 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -47,7 +47,8 @@ SwCanvas::~SwCanvas() Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept { - auto renderer = dynamic_cast(Canvas::pImpl.get()->renderer); + //We know renderer type, avoid dynamic_cast for performance. + auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; -- 2.7.4 From c75cca5a134116f374edcb6375f9319db14e62e6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 20:43:38 +0900 Subject: [PATCH 15/16] common: code refacatoring. shorter prefix for better neat code. it's just a preference. Change-Id: I30998476a92bc971193e9a5b4436687e48e4d19a --- inc/tizenvg.h | 64 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/inc/tizenvg.h b/inc/tizenvg.h index 309badd..a2d245d 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -19,23 +19,23 @@ #include -#ifdef TIZENVG_BUILD - #define TIZENVG_EXPORT __attribute__ ((visibility ("default"))) +#ifdef TVG_BUILD + #define TVG_EXPORT __attribute__ ((visibility ("default"))) #else - #define TIZENVG_EXPORT + #define TVG_EXPORT #endif #ifdef LOG_TAG #undef LOG_TAG #endif -#define LOG_TAG "TIZENVG" +#define LOG_TAG "TVG" #ifdef __cplusplus extern "C" { #endif -#define _TIZENVG_DECLARE_PRIVATE(A) \ +#define _TVG_DECLARE_PRIVATE(A) \ protected: \ struct Impl; \ std::unique_ptr pImpl; \ @@ -43,14 +43,14 @@ protected: \ const A& operator=(const A&) = delete; \ A() -#define _TIZENVG_DECLARE_ACCESSOR(A) \ +#define _TVG_DECLARE_ACCESSOR(A) \ friend A -#define _TIZENVG_DISABLE_CTOR(A) \ +#define _TVG_DISABLE_CTOR(A) \ A() = delete; \ ~A() = delete -#define _TIZENVG_IDENTIFIER(A) \ +#define _TVG_DECALRE_IDENTIFIER(A) \ protected: \ unsigned A##_Id @@ -62,10 +62,10 @@ class Scene; class Canvas; -enum class TIZENVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; -enum class TIZENVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; -enum class TIZENVG_EXPORT StrokeCap { Square = 0, Round, Butt }; -enum class TIZENVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; +enum class TVG_EXPORT Result { Success = 0, InvalidArguments, InsufficientCondition, FailedAllocation, MemoryCorruption, Unknown }; +enum class TVG_EXPORT PathCommand { Close = 0, MoveTo, LineTo, CubicTo }; +enum class TVG_EXPORT StrokeCap { Square = 0, Round, Butt }; +enum class TVG_EXPORT StrokeJoin { Bevel = 0, Round, Miter }; struct Point @@ -82,7 +82,7 @@ struct Point * @brief description... * */ -class TIZENVG_EXPORT Paint +class TVG_EXPORT Paint { public: virtual ~Paint() {} @@ -93,9 +93,9 @@ public: virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; - _TIZENVG_IDENTIFIER(Paint); - _TIZENVG_DECLARE_ACCESSOR(Scene); - _TIZENVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECALRE_IDENTIFIER(Paint); + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_ACCESSOR(Canvas); }; @@ -107,7 +107,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Canvas +class TVG_EXPORT Canvas { public: Canvas(RenderMethod*); @@ -121,8 +121,8 @@ public: virtual Result draw(bool async = true) noexcept; virtual Result sync() = 0; - _TIZENVG_DECLARE_ACCESSOR(Scene); - _TIZENVG_DECLARE_PRIVATE(Canvas); + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_PRIVATE(Canvas); }; @@ -134,7 +134,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Shape final : public Paint +class TVG_EXPORT Shape final : public Paint { public: ~Shape(); @@ -181,9 +181,9 @@ public: static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_ACCESSOR(Scene); - _TIZENVG_DECLARE_ACCESSOR(Canvas); - _TIZENVG_DECLARE_PRIVATE(Shape); + _TVG_DECLARE_ACCESSOR(Scene); + _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_PRIVATE(Shape); }; @@ -195,7 +195,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Scene final : public Paint +class TVG_EXPORT Scene final : public Paint { public: ~Scene(); @@ -211,8 +211,8 @@ public: static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(Scene); - _TIZENVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_PRIVATE(Scene); + _TVG_DECLARE_ACCESSOR(Canvas); }; @@ -224,7 +224,7 @@ public: @brief description... * */ -class TIZENVG_EXPORT SwCanvas final : public Canvas +class TVG_EXPORT SwCanvas final : public Canvas { public: ~SwCanvas(); @@ -233,7 +233,7 @@ public: Result sync() noexcept override; static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(SwCanvas); + _TVG_DECLARE_PRIVATE(SwCanvas); }; @@ -245,7 +245,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT GlCanvas final : public Canvas +class TVG_EXPORT GlCanvas final : public Canvas { public: ~GlCanvas(); @@ -256,7 +256,7 @@ public: Result sync() noexcept override; static std::unique_ptr gen() noexcept; - _TIZENVG_DECLARE_PRIVATE(GlCanvas); + _TVG_DECLARE_PRIVATE(GlCanvas); }; @@ -268,7 +268,7 @@ public: * @brief description... * */ -class TIZENVG_EXPORT Engine final +class TVG_EXPORT Engine final { public: /** @@ -285,7 +285,7 @@ public: static Result init() noexcept; static Result term() noexcept; - _TIZENVG_DISABLE_CTOR(Engine); + _TVG_DISABLE_CTOR(Engine); }; } //namespace -- 2.7.4 From c36f23e80d243946bed1010f3ef7b36b67fda080 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jun 2020 15:40:13 +0900 Subject: [PATCH 16/16] common gradient: implement linear/radial gradient interfaces. Change-Id: Ica9c54e662e73592d3fddcabed09b1605b3a5a4f --- .gitignore | 1 + inc/tizenvg.h | 101 ++++++++++++++++++++++++++++++++++----- src/lib/gl_engine/meson.build | 6 +-- src/lib/meson.build | 13 +++-- src/lib/tvgCanvasImpl.h | 8 ++-- src/lib/tvgCommon.h | 3 ++ src/lib/tvgFill.cpp | 88 ++++++++++++++++++++++++++++++++++ src/lib/tvgLinearGradient.cpp | 86 +++++++++++++++++++++++++++++++++ src/lib/tvgRadialGradient.cpp | 84 +++++++++++++++++++++++++++++++++ src/lib/tvgRenderCommon.h | 2 +- src/lib/tvgScene.cpp | 2 +- src/lib/tvgSceneImpl.h | 8 ++-- src/lib/tvgShape.cpp | 34 +++++++++++++- src/lib/tvgShapeImpl.h | 11 ++--- src/meson.build | 2 +- test/makefile | 1 + test/testLinearGradient.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++ 17 files changed, 517 insertions(+), 40 deletions(-) create mode 100644 src/lib/tvgFill.cpp create mode 100644 src/lib/tvgLinearGradient.cpp create mode 100644 src/lib/tvgRadialGradient.cpp create mode 100644 test/testLinearGradient.cpp diff --git a/.gitignore b/.gitignore index ba439cb..b9cdf24 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ testTransform testSceneTransform testStroke testStrokeLine +testLinearGradient diff --git a/inc/tizenvg.h b/inc/tizenvg.h index a2d245d..b089387 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -35,6 +35,7 @@ extern "C" { #endif + #define _TVG_DECLARE_PRIVATE(A) \ protected: \ struct Impl; \ @@ -43,16 +44,21 @@ protected: \ const A& operator=(const A&) = delete; \ A() -#define _TVG_DECLARE_ACCESSOR(A) \ - friend A - #define _TVG_DISABLE_CTOR(A) \ A() = delete; \ ~A() = delete -#define _TVG_DECALRE_IDENTIFIER(A) \ +#define _TVG_DECLARE_ACCESSOR(A) \ + friend A + +#define _TVG_DECLARE_ACCESSORS(A, B) \ + friend A; \ + friend B + +#define _TVG_DECALRE_IDENTIFIER() \ protected: \ - unsigned A##_Id + unsigned id + namespace tvg { @@ -93,9 +99,79 @@ public: virtual Result bounds(float* x, float* y, float* w, float* h) const = 0; - _TVG_DECALRE_IDENTIFIER(Paint); - _TVG_DECLARE_ACCESSOR(Scene); - _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECALRE_IDENTIFIER(); + _TVG_DECLARE_ACCESSORS(Canvas, Scene); +}; + + +/** + * @class Fill + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT Fill +{ +public: + struct ColorStop + { + float pos; + uint8_t r, g, b, a; + }; + + virtual ~Fill(); + + Result colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept; + uint32_t colorStops(const ColorStop** colorStops) const noexcept; + + _TVG_DECALRE_IDENTIFIER(); + _TVG_DECLARE_PRIVATE(Fill); +}; + + +/** + * @class LinearGradient + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT LinearGradient final : public Fill +{ +public: + ~LinearGradient(); + + Result linear(float x1, float y1, float x2, float y2) noexcept; + Result linear(float* x1, float* y1, float* x2, float* y2) const noexcept; + + static std::unique_ptr gen() noexcept; + + _TVG_DECLARE_PRIVATE(LinearGradient); +}; + + +/** + * @class RadialGradient + * + * @ingroup TizenVG + * + * @brief description... + * + */ +class TVG_EXPORT RadialGradient final : public Fill +{ +public: + ~RadialGradient(); + + Result radial(float cx, float cy, float radius) noexcept; + Result radial(float* cx, float* cy, float* radius) const noexcept; + + static std::unique_ptr gen() noexcept; + + _TVG_DECLARE_PRIVATE(RadialGradient); }; @@ -161,6 +237,7 @@ public: //Fill Result fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept; + Result fill(std::unique_ptr f) noexcept; //Transform Result rotate(float degree) noexcept override; @@ -171,6 +248,7 @@ public: uint32_t pathCommands(const PathCommand** cmds) const noexcept; uint32_t pathCoords(const Point** pts) const noexcept; Result fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; + const Fill* fill() const noexcept; Result bounds(float* x, float* y, float* w, float* h) const noexcept override; float strokeWidth() const noexcept; @@ -181,9 +259,8 @@ public: static std::unique_ptr gen() noexcept; - _TVG_DECLARE_ACCESSOR(Scene); - _TVG_DECLARE_ACCESSOR(Canvas); _TVG_DECLARE_PRIVATE(Shape); + _TVG_DECLARE_ACCESSORS(Canvas, Scene); }; @@ -211,8 +288,8 @@ public: static std::unique_ptr gen() noexcept; - _TVG_DECLARE_PRIVATE(Scene); _TVG_DECLARE_ACCESSOR(Canvas); + _TVG_DECLARE_PRIVATE(Scene); }; @@ -231,6 +308,7 @@ public: Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; + static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(SwCanvas); @@ -254,6 +332,7 @@ public: Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; Result sync() noexcept override; + static std::unique_ptr gen() noexcept; _TVG_DECLARE_PRIVATE(GlCanvas); diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 41a25e0..5494f69 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -1,12 +1,12 @@ source_file = [ 'tvgGlCommon.h', + 'tvgGlGeometry.h', 'tvgGlGpuBuffer.h', 'tvgGlProgram.h', - 'tvgGlRenderer.cpp', 'tvgGlRenderer.h', 'tvgGlShader.h', - 'tvgGlGeometry.h', - ] + 'tvgGlRenderer.cpp', +] glraster_dep = declare_dependency( include_directories : include_directories('.'), diff --git a/src/lib/meson.build b/src/lib/meson.build index 0a56f0d..5aba9bb 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -2,18 +2,21 @@ subdir('sw_engine') subdir('gl_engine') source_file = [ + 'tvgCanvasImpl.h', 'tvgCommon.h', 'tvgRenderCommon.h', + 'tvgSceneImpl.h', 'tvgShapePath.h', 'tvgShapeImpl.h', - 'tvgCanvasImpl.h', - 'tvgSceneImpl.h', - 'tvgEngine.cpp', 'tvgCanvas.cpp', - 'tvgSwCanvas.cpp', + 'tvgEngine.cpp', + 'tvgFill.cpp', 'tvgGlCanvas.cpp', + 'tvgLinearGradient.cpp', + 'tvgRadialGradient.cpp', 'tvgScene.cpp', - 'tvgShape.cpp' + 'tvgShape.cpp', + 'tvgSwCanvas.cpp', ] src_dep = declare_dependency( diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 078385a..c6dc073 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -53,7 +53,7 @@ struct Canvas::Impl assert(renderer); for (auto paint : paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(*renderer)) return Result::InsufficientCondition; @@ -73,7 +73,7 @@ struct Canvas::Impl assert(renderer); for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer, nullptr)) return Result::InsufficientCondition; @@ -89,7 +89,7 @@ struct Canvas::Impl { assert(renderer); - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(*renderer)) return Result::InsufficientCondition; @@ -108,7 +108,7 @@ struct Canvas::Impl if (!renderer->clear()) return Result::InsufficientCondition; for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(*renderer)) return Result::InsufficientCondition; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index ca18cca..49c3f96 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -34,6 +34,9 @@ using namespace tvg; #define PAINT_ID_SHAPE 0 #define PAINT_ID_SCENE 1 +#define FILL_ID_LINEAR 0 +#define FILL_ID_RADIAL 1 + #include "tvgRenderCommon.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" diff --git a/src/lib/tvgFill.cpp b/src/lib/tvgFill.cpp new file mode 100644 index 0000000..13001c8 --- /dev/null +++ b/src/lib/tvgFill.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_FILL_CPP_ +#define _TVG_FILL_CPP_ + +#include "tvgCommon.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct Fill::Impl +{ + ColorStop* colorStops = nullptr; + uint32_t cnt = 0; + + ~Impl() + { + if (colorStops) free(colorStops); + } +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +Fill::Fill():pImpl(make_unique()) +{ +} + + +Fill::~Fill() +{ +} + + +Result Fill::colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (cnt == 0) { + if (impl->colorStops) { + free(impl->colorStops); + impl->colorStops = nullptr; + impl->cnt = cnt; + } + return Result::Success; + } + + if (impl->cnt != cnt) { + impl->colorStops = static_cast(realloc(impl->colorStops, cnt * sizeof(ColorStop))); + } + + impl->cnt = cnt; + memcpy(impl->colorStops, colorStops, cnt * sizeof(ColorStop)); + + return Result::Success; +} + + +uint32_t Fill::colorStops(const ColorStop** colorStops) const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return 0; + + if (colorStops) *colorStops = impl->colorStops; + + return impl->cnt; +} + +#endif /* _TVG_FILL_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgLinearGradient.cpp b/src/lib/tvgLinearGradient.cpp new file mode 100644 index 0000000..9ea803d --- /dev/null +++ b/src/lib/tvgLinearGradient.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_LINEAR_GRADIENT_CPP_ +#define _TVG_LINEAR_GRADIENT_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct LinearGradient::Impl +{ + float x1, y1, x2, y2; +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +LinearGradient::LinearGradient():pImpl(make_unique()) +{ + id = FILL_ID_LINEAR; +} + + +LinearGradient::~LinearGradient() +{ +} + + +Result LinearGradient::linear(float x1, float y1, float x2, float y2) noexcept +{ + if (fabsf(x2 - x1) < FLT_EPSILON && fabsf(y2 - y1) < FLT_EPSILON) + return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + impl->x1 = x1; + impl->y1 = y1; + impl->x2 = x2; + impl->y2 = y2; + + return Result::Success; +} + + +Result LinearGradient::linear(float* x1, float* y1, float* x2, float* y2) const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (x1) *x1 = impl->x1; + if (x2) *x2 = impl->x2; + if (y1) *y1 = impl->y1; + if (y2) *y2 = impl->y2; + + return Result::Success; +} + + +unique_ptr LinearGradient::gen() noexcept +{ + auto fill = unique_ptr(new LinearGradient); + assert(fill); + + return fill; +} + +#endif /* _TVG_LINEAR_GRADIENT_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgRadialGradient.cpp b/src/lib/tvgRadialGradient.cpp new file mode 100644 index 0000000..2447e6f --- /dev/null +++ b/src/lib/tvgRadialGradient.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef _TVG_RADIAL_GRADIENT_CPP_ +#define _TVG_RADIAL_GRADIENT_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct RadialGradient::Impl +{ + float cx, cy, radius; +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +RadialGradient::RadialGradient():pImpl(make_unique()) +{ + id = FILL_ID_RADIAL; +} + + +RadialGradient::~RadialGradient() +{ +} + + +Result RadialGradient::radial(float cx, float cy, float radius) noexcept +{ + if (radius < FLT_EPSILON) + return Result::InvalidArguments; + + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + impl->cx = cx; + impl->cy = cy; + impl->radius = radius; + + return Result::Success; +} + + +Result RadialGradient::radial(float* cx, float* cy, float* radius) const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + if (cx) *cx = impl->cx; + if (cy) *cy = impl->cy; + if (radius) *radius = impl->radius; + + return Result::Success; +} + + +unique_ptr RadialGradient::gen() noexcept +{ + auto fill = unique_ptr(new RadialGradient); + assert(fill); + + return fill; +} + +#endif /* _TVG_RADIAL_GRADIENT_CPP_ */ \ No newline at end of file diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h index 0e98e17..f89d949 100644 --- a/src/lib/tvgRenderCommon.h +++ b/src/lib/tvgRenderCommon.h @@ -28,7 +28,7 @@ struct Surface uint32_t w, h; }; -enum RenderUpdateFlag {None = 0, Path = 1, Fill = 2, Stroke = 4, Transform = 8, All = 16}; +enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, All = 32}; struct RenderTransform { diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index a1c7a7f..ac2ae82 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -25,7 +25,7 @@ Scene::Scene() : pImpl(make_unique()) { - Paint_Id = PAINT_ID_SCENE; + id = PAINT_ID_SCENE; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 1f1fa14..8596292 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -39,7 +39,7 @@ struct Scene::Impl bool clear(RenderMethod& renderer) { for (auto paint : paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->clear(renderer)) return false; @@ -57,7 +57,7 @@ struct Scene::Impl bool updateInternal(RenderMethod &renderer, const RenderTransform* transform, uint32_t flag) { for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->update(renderer, transform, flag)) return false; @@ -97,7 +97,7 @@ struct Scene::Impl bool render(RenderMethod &renderer) { for(auto paint: paints) { - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if(!SCENE_IMPL->render(renderer)) return false; @@ -122,7 +122,7 @@ struct Scene::Impl auto w2 = 0.0f; auto h2 = 0.0f; - if (paint->Paint_Id == PAINT_ID_SCENE) { + if (paint->id == PAINT_ID_SCENE) { //We know renderer type, avoid dynamic_cast for performance. auto scene = static_cast(paint); if (!SCENE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 5119ac8..012fcb1 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -32,7 +32,7 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { - Paint_Id = PAINT_ID_SHAPE; + id = PAINT_ID_SHAPE; } @@ -226,7 +226,29 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept impl->color[1] = g; impl->color[2] = b; impl->color[3] = a; - impl->flag |= RenderUpdateFlag::Fill; + impl->flag |= RenderUpdateFlag::Color; + + if (impl->fill) { + delete(impl->fill); + impl->fill = nullptr; + impl->flag |= RenderUpdateFlag::Gradient; + } + + return Result::Success; +} + + +Result Shape::fill(unique_ptr f) noexcept +{ + auto impl = pImpl.get(); + if (!impl) return Result::MemoryCorruption; + + auto p = f.release(); + if (!p) return Result::MemoryCorruption; + + if (impl->fill) delete(impl->fill); + impl->fill = p; + impl->flag |= RenderUpdateFlag::Gradient; return Result::Success; } @@ -245,6 +267,14 @@ Result Shape::fill(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcep return Result::Success; } +const Fill* Shape::fill() const noexcept +{ + auto impl = pImpl.get(); + if (!impl) return nullptr; + + return impl->fill; +} + Result Shape::scale(float factor) noexcept { diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 08acb36..4cce022 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -23,11 +23,6 @@ /* Internal Class Implementation */ /************************************************************************/ -struct ShapeFill -{ -}; - - struct ShapeStroke { float width = 0; @@ -46,9 +41,9 @@ struct ShapeStroke struct Shape::Impl { - ShapeFill *fill = nullptr; - ShapeStroke *stroke = nullptr; ShapePath *path = nullptr; + Fill *fill = nullptr; + ShapeStroke *stroke = nullptr; RenderTransform *transform = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a uint32_t flag = RenderUpdateFlag::None; @@ -62,8 +57,8 @@ struct Shape::Impl ~Impl() { if (path) delete(path); - if (stroke) delete(stroke); if (fill) delete(fill); + if (stroke) delete(stroke); if (transform) delete(transform); } diff --git a/src/meson.build b/src/meson.build index aded001..a0ef37d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,4 +1,4 @@ -compiler_flags = ['-DTIZENVG_BUILD'] +compiler_flags = ['-DTVG_BUILD'] subdir('lib') subdir('examples') diff --git a/test/makefile b/test/makefile index 2aba05d..353d7b8 100644 --- a/test/makefile +++ b/test/makefile @@ -12,3 +12,4 @@ all: gcc -o testSceneTransform testSceneTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testStroke testStroke.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` gcc -o testStrokeLine testStrokeLine.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` + gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg` diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp new file mode 100644 index 0000000..4f87cad --- /dev/null +++ b/test/testLinearGradient.cpp @@ -0,0 +1,107 @@ +#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(); + canvas->target(buffer, WIDTH, WIDTH, HEIGHT); + canvas->reserve(3); //reserve 3 shape nodes (optional) + + //Linear Gradient Color Stops + tvg::Fill::ColorStop colorStops[3]; + colorStops[0] = {0, 255, 0, 0, 255}; + colorStops[1] = {0.5, 255, 255, 255, 255}; + colorStops[2] = {1, 0, 0, 255, 255}; + + //Prepare Round Rectangle + auto shape1 = tvg::Shape::gen(); + shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->stroke(255, 255, 255, 255); + shape1->stroke(2); + + //LinearGradient + auto fill = tvg::LinearGradient::gen(); + fill->linear(0, 0, 400, 400); + fill->colorStops(colorStops, 3); + + shape1->fill(move(fill)); + canvas->push(move(shape1)); + + + //Prepare Circle + auto shape2 = tvg::Shape::gen(); + shape2->appendCircle(400, 400, 200, 200); //cx, cy, radiusW, radiusH + shape2->stroke(255, 255, 255, 255); + shape2->stroke(2); + + //LinearGradient + auto fill2 = tvg::LinearGradient::gen(); + fill2->linear(400, 200, 400, 600); + fill2->colorStops(colorStops, 3); + + shape2->fill(move(fill2)); + canvas->push(move(shape2)); + + + //Prepare Ellipse + auto shape3 = tvg::Shape::gen(); + shape3->appendCircle(600, 600, 150, 100); //cx, cy, radiusW, radiusH + shape3->stroke(255, 255, 255, 255); + shape3->stroke(2); + + //LinearGradient + auto fill3 = tvg::LinearGradient::gen(); + fill3->linear(450, 600, 750, 600); + fill3->colorStops(colorStops, 3); + + shape3->fill(move(fill3)); + canvas->push(move(shape3)); + + //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