From 2929fa5c57c17549da1b65e86140806b12823fc3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 3 Jul 2020 18:17:43 +0900 Subject: [PATCH 01/16] sw_engine: optimize rle rendering. we don't need to apply anti-aliasing if stroke is there. here turns off anti-alias if stroke width is more than 2. magic number 2 is experimentally confirmed. Change-Id: I09031dc2a0a84f31c5904651ed1e62004645ba9a --- src/lib/sw_engine/tvgSwCommon.h | 4 ++-- src/lib/sw_engine/tvgSwRenderer.cpp | 10 ++++++---- src/lib/sw_engine/tvgSwRle.cpp | 17 +++++++---------- src/lib/sw_engine/tvgSwShape.cpp | 6 +++--- test/testShape.cpp | 2 +- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 5db4cd7..8d90342 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -265,7 +265,7 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2); void shapeReset(SwShape& shape); bool shapeGenOutline(SwShape& shape, const Shape* sdata); bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip); +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias); void shapeDelOutline(SwShape& shape); void shapeResetStroke(SwShape& shape, const Shape* sdata); bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip); @@ -286,7 +286,7 @@ void fillFree(SwFill* fill); void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); -SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip); +SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias); void rleFree(SwRleData* rle); bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index b9ce7c0..adc3e9f 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -109,7 +109,7 @@ void SwRenderer::doRender() if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a); } task->sdata->strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); + if (a > 0) rasterStroke(surface, task->shape, r, g, b, a); renderTasks.pop(); } } @@ -178,7 +178,8 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* //Valid Stroking? uint8_t strokeAlpha = 0; - if (task->sdata->strokeWidth() > FLT_EPSILON) { + auto strokeWidth = task->sdata->strokeWidth(); + if (strokeWidth > FLT_EPSILON) { task->sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); } @@ -188,10 +189,11 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* uint8_t alpha = 0; task->sdata->fill(nullptr, nullptr, nullptr, &alpha); bool renderShape = (alpha > 0 || task->sdata->fill()); - if (renderShape || strokeAlpha > 0) { + if (renderShape || strokeAlpha) { if (!shapePrepare(task->shape, task->sdata, task->clip, task->transform)) return; if (renderShape) { - if (!shapeGenRle(task->shape, task->sdata, task->clip)) return; + auto antiAlias = (strokeAlpha > 0 && strokeWidth >= 2) ? false : true; + if (!shapeGenRle(task->shape, task->sdata, task->clip, antiAlias)) return; } } } diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 5bb3a31..6ee6f7c 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -87,6 +87,7 @@ struct RleWorker SwSize clip; bool invalid; + bool antiAlias; }; @@ -196,6 +197,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor } if (coverage > 0) { + if (!rw.antiAlias) coverage = 255; auto count = rw.spansCnt; auto span = rw.spans + count - 1; assert(span); @@ -261,22 +263,16 @@ static void _sweep(RleWorker& rw) while (cell) { - if (cell->x > x && cover != 0) - _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); - + if (cell->x > x && cover != 0) _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), cell->x - x); cover += cell->cover; auto area = cover * (ONE_PIXEL * 2) - cell->area; - - //OPTIMIZE ME: This occurs 1 length span data. - if (area != 0 && cell->x >= 0) - _horizLine(rw, cell->x, y, area, 1); + if (area != 0 && cell->x >= 0) _horizLine(rw, cell->x, y, area, 1); x = cell->x + 1; cell = cell->next; } - if (cover != 0) - _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x); + if (cover != 0) _horizLine(rw, x, y, cover * (ONE_PIXEL * 2), rw.cellXCnt - x); } if (rw.spansCnt > 0) _genSpan(rw.rle, rw.spans, rw.spansCnt); @@ -648,7 +644,7 @@ static bool _genRle(RleWorker& rw) /* External Class Implementation */ /************************************************************************/ -SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip) +SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& clip, bool antiAlias) { //Please adjust when you out of cell memory (default: 16384L) constexpr auto RENDER_POOL_SIZE = 163840L * 2; @@ -681,6 +677,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8); //bandSize: 64 rw.bandShoot = 0; rw.clip = clip; + rw.antiAlias = antiAlias; rw.rle = reinterpret_cast(calloc(1, sizeof(SwRleData))); assert(rw.rle); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index dbdfb6a..a2ca5c6 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -477,7 +477,7 @@ bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const } -bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip) +bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias) { //FIXME: Should we draw it? //Case: Stroke Line @@ -486,7 +486,7 @@ bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip) //Case A: Fast Track Rectangle Drawing if ((shape.rect = _fastTrack(shape.outline))) return true; //Case B: Normale Shape RLE Drawing - if ((shape.rle = rleRender(shape.outline, shape.bbox, clip))) return true; + if ((shape.rle = rleRender(shape.outline, shape.bbox, clip, antiAlias))) return true; return false; } @@ -667,7 +667,7 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) if (!_checkValid(strokeOutline, bbox, clip)) return false; - shape.strokeRle = rleRender(strokeOutline, bbox, clip); + shape.strokeRle = rleRender(strokeOutline, bbox, clip, true); _delOutline(strokeOutline); diff --git a/test/testShape.cpp b/test/testShape.cpp index 5bf9e65..617d024 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -119,4 +119,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} -- 2.7.4 From cfa17c6df602c04a88e9cc489a508207f963a309 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 6 Jul 2020 19:26:50 +0900 Subject: [PATCH 02/16] svg_engine: fix infinit loop dead in stroke rendering. here logic was wrongly introducedd, we fix the condition check properly. Change-Id: I97f18f68290c61096f4e7fe54bd6f6fde51e175b --- src/lib/sw_engine/tvgSwMath.cpp | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 1 - src/lib/sw_engine/tvgSwStroke.cpp | 10 ++++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lib/sw_engine/tvgSwMath.cpp b/src/lib/sw_engine/tvgSwMath.cpp index 53cc8ce..540ddcf 100644 --- a/src/lib/sw_engine/tvgSwMath.cpp +++ b/src/lib/sw_engine/tvgSwMath.cpp @@ -237,7 +237,7 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& auto theta2 = abs(mathDiff(angleMid, angleOut)); if ((theta1 < (SW_ANGLE_PI / 8)) && (theta2 < (SW_ANGLE_PI / 8))) return true; - else return false; + return false; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index a2ca5c6..66655b0 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -648,7 +648,6 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) if (sdata->strokeDash(nullptr) > 0) { shapeOutline = _genDashOutline(sdata); if (!shapeOutline) return false; - //Normal Style stroke } else { if (!shape.outline) { diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 6ccfb7d..d45ddd8 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -442,7 +442,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl //initialize with current direction angleIn = angleOut = angleMid = stroke.angleIn; - if (arc < limit && mathSmallCubic(arc, angleIn, angleMid, angleOut)) { + if (arc < limit && !mathSmallCubic(arc, angleIn, angleMid, angleOut)) { if (stroke.firstPt) stroke.angleIn = angleIn; mathSplitCubic(arc); arc += 3; @@ -458,7 +458,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl stroke.angleOut = angleIn; _processCorner(stroke, 0); } - } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (SW_ANGLE_PI / 8)) { + } else if (abs(mathDiff(stroke.angleIn, angleIn)) > (SW_ANGLE_PI / 8) / 4) { //if the deviation from one arc to the next is too great add a round corner stroke.center = arc[3]; stroke.angleOut = angleIn; @@ -534,9 +534,11 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl _borderLineTo(border, _end, false); _borderCubicTo(border, _ctrl2, _ctrl1, _start); - //and thenmove to the endpoint + //and then move to the endpoint _borderLineTo(border, _end, false); + ++side; + ++border; continue; } @@ -651,7 +653,7 @@ static void _addReverseLeft(SwStroke& stroke, bool opened) static void _beginSubPath(SwStroke& stroke, SwPoint& to, bool opened) { - /* We cannot process the first point because there is not enought + /* We cannot process the first point because there is not enough information regarding its corner/cap. Later, it will be processed in the _endSubPath() */ -- 2.7.4 From 0d19700b4ea4a34cdcab1088cd1fbad0bbc3cfea Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 14:02:38 +0900 Subject: [PATCH 03/16] SvgLoader: Support ellipse draw Change-Id: I6420673d8341a59b91546224576d1c977c1a08d2 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index b79a3eb..66b3593 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -125,7 +125,7 @@ unique_ptr _shapeBuildHelper(SvgNode* node) break; } case SvgNodeType::Ellipse: { - //TODO: Support ellipse + shape->appendCircle(node->node.ellipse.cx, node->node.ellipse.cy, node->node.ellipse.rx, node->node.ellipse.ry); break; } case SvgNodeType::Polygon: { -- 2.7.4 From 02a0e985961b7472f32ab31e864bafbf6f387f18 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 17:01:56 +0900 Subject: [PATCH 04/16] SvgLoader: Support x,y rounded rect Change-Id: I45d8f7ff3604da0a80c09e2495ed8c0301310094 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 21 +++++++++++++++++++-- test/svgs/rect.svg | 7 +++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 test/svgs/rect.svg diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 66b3593..2451103 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -150,11 +150,28 @@ unique_ptr _shapeBuildHelper(SvgNode* node) break; } case SvgNodeType::Rect: { - if (node->node.rect.rx == node->node.rect.ry) { + if (node->node.rect.rx == node->node.rect.ry || (node->node.rect.rx == 0 || node->node.rect.ry == 0)) { shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx); } else { - //TODO: Support rounded rectangle + float x = node->node.rect.x; + float y = node->node.rect.y; + float w = node->node.rect.w; + float h = node->node.rect.h; + float rx = node->node.rect.rx; + float ry = node->node.rect.ry; + float rhx = rx / 2; + float rhy = ry / 2; + shape->moveTo(x + rx, y); + shape->lineTo(x + w - rx, y); + shape->cubicTo(x + w - rx + rhx, y, x + w, y + ry - rhy, x + w, y + ry); + shape->lineTo(x + w, y + h - ry); + shape->cubicTo(x + w, y + h - ry + rhy, x + w - rx + rhx, y + h, x + w - rx, y + h); + shape->lineTo(x + rx, y + h); + shape->cubicTo(x + rx - rhx, y + h, x, y + h - ry + rhy, x, y + h - ry); + shape->lineTo(x, y + ry); + shape->cubicTo(x, y + ry - rhy, x + rx - rhx, y, x + rx, y); + shape->close(); } break; } diff --git a/test/svgs/rect.svg b/test/svgs/rect.svg new file mode 100644 index 0000000..2e82905 --- /dev/null +++ b/test/svgs/rect.svg @@ -0,0 +1,7 @@ + + + + + + + -- 2.7.4 From ef4d7a39565926706f577ada8d8fbf5a50868d0b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 13:05:44 +0900 Subject: [PATCH 05/16] common shape: expand rectangle arguement to support both corner radius x, y this is useful for svg loader Change-Id: Ia11c2d1c6ea88f3fd65c7f75cef8b59bef426bcb --- inc/thorvg.h | 4 +-- src/lib/tvgShape.cpp | 52 ++++++++++++++------------- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 24 +------------ test/testAsync.cpp | 2 +- test/testBlending.cpp | 4 +-- test/testBoundary.cpp | 8 ++--- test/testDirectUpdate.cpp | 6 ++-- test/testGradientTransform.cpp | 10 +++--- test/testLinearGradient.cpp | 4 +-- test/testMultiShapes.cpp | 4 +-- test/testRadialGradient.cpp | 4 +-- test/testScene.cpp | 4 +-- test/testSceneTransform.cpp | 2 +- test/testShape.cpp | 10 +++--- test/testStroke.cpp | 8 ++--- test/testSvg.cpp | 2 +- test/testTransform.cpp | 10 +++--- test/testUpdate.cpp | 6 ++-- 18 files changed, 73 insertions(+), 91 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 54c7e11..bdca5a2 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -228,8 +228,8 @@ public: Result close() noexcept; //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 appendRect(float x, float y, float w, float h, float rx, float ry) noexcept; + Result appendCircle(float cx, float cy, float rx, float ry) noexcept; Result appendPath(const PathCommand* cmds, uint32_t cmdCnt, const Point* pts, uint32_t ptsCnt) noexcept; //Stroke diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index f7699b4..36aefed 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -154,20 +154,20 @@ Result Shape::close() noexcept } -Result Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noexcept +Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept { auto impl = pImpl.get(); if (!impl || !impl->path) return Result::MemoryCorruption; - auto halfKappaW = radiusW * PATH_KAPPA; - auto halfKappaH = radiusH * PATH_KAPPA; + auto rxKappa = rx * PATH_KAPPA; + auto ryKappa = ry * PATH_KAPPA; impl->path->grow(6, 13); - impl->path->moveTo(cx, cy - radiusH); - impl->path->cubicTo(cx + halfKappaW, cy - radiusH, cx + radiusW, cy - halfKappaH, cx + radiusW, cy); - impl->path->cubicTo(cx + radiusW, cy + halfKappaH, cx + halfKappaW, cy + radiusH, cx, cy + radiusH); - impl->path->cubicTo(cx - halfKappaW, cy + radiusH, cx - radiusW, cy + halfKappaH, cx - radiusW, cy); - impl->path->cubicTo(cx - radiusW, cy - halfKappaH, cx - halfKappaW, cy - radiusH, cx, cy - radiusH); + impl->path->moveTo(cx, cy - ry); + impl->path->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); + impl->path->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry); + impl->path->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy); + impl->path->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry); impl->path->close(); impl->flag |= RenderUpdateFlag::Path; @@ -176,17 +176,20 @@ Result Shape::appendCircle(float cx, float cy, float radiusW, float radiusH) noe } -Result 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 rx, float ry) noexcept { auto impl = pImpl.get(); if (!impl || !impl->path) return Result::MemoryCorruption; + auto halfW = w * 0.5f; + auto halfH = h * 0.5f; + //clamping cornerRadius by minimum size - auto min = (w < h ? w : h) * 0.5f; - if (cornerRadius > min) cornerRadius = min; + if (rx > halfW) rx = halfW; + if (ry > halfH) ry = halfH; //rectangle - if (cornerRadius == 0) { + if (rx == 0 && ry == 0) { impl->path->grow(5, 4); impl->path->moveTo(x, y); impl->path->lineTo(x + w, y); @@ -194,20 +197,21 @@ Result Shape::appendRect(float x, float y, float w, float h, float cornerRadius) impl->path->lineTo(x, y + h); impl->path->close(); //circle - } else if (w == h && cornerRadius * 2 == w) { - return appendCircle(x + (w * 0.5f), y + (h * 0.5f), cornerRadius, cornerRadius); + } else if (fabsf(rx - halfW) < FLT_EPSILON && fabsf(ry - halfH) < FLT_EPSILON) { + return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry); } else { - auto halfKappa = cornerRadius * 0.5; + auto hrx = rx * 0.5f; + auto hry = ry * 0.5f; impl->path->grow(10, 17); - impl->path->moveTo(x + cornerRadius, y); - impl->path->lineTo(x + w - cornerRadius, y); - impl->path->cubicTo(x + w - cornerRadius + halfKappa, y, x + w, y + cornerRadius - halfKappa, x + w, y + cornerRadius); - impl->path->lineTo(x + w, y + h - cornerRadius); - impl->path->cubicTo(x + w, y + h - cornerRadius + halfKappa, x + w - cornerRadius + halfKappa, y + h, x + w - cornerRadius, y + h); - impl->path->lineTo(x + cornerRadius, y + h); - impl->path->cubicTo(x + cornerRadius - halfKappa, y + h, x, y + h - cornerRadius + halfKappa, x, y + h - cornerRadius); - impl->path->lineTo(x, y + cornerRadius); - impl->path->cubicTo(x, y + cornerRadius - halfKappa, x + cornerRadius - halfKappa, y, x + cornerRadius, y); + impl->path->moveTo(x + rx, y); + impl->path->lineTo(x + w - rx, y); + impl->path->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); + impl->path->lineTo(x + w, y + h - ry); + impl->path->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h); + impl->path->lineTo(x + rx, y + h); + impl->path->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry); + impl->path->lineTo(x, y + ry); + impl->path->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y); impl->path->close(); } diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 2451103..2be0122 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -150,29 +150,7 @@ unique_ptr _shapeBuildHelper(SvgNode* node) break; } case SvgNodeType::Rect: { - if (node->node.rect.rx == node->node.rect.ry || (node->node.rect.rx == 0 || node->node.rect.ry == 0)) { - shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx); - } - else { - float x = node->node.rect.x; - float y = node->node.rect.y; - float w = node->node.rect.w; - float h = node->node.rect.h; - float rx = node->node.rect.rx; - float ry = node->node.rect.ry; - float rhx = rx / 2; - float rhy = ry / 2; - shape->moveTo(x + rx, y); - shape->lineTo(x + w - rx, y); - shape->cubicTo(x + w - rx + rhx, y, x + w, y + ry - rhy, x + w, y + ry); - shape->lineTo(x + w, y + h - ry); - shape->cubicTo(x + w, y + h - ry + rhy, x + w - rx + rhx, y + h, x + w - rx, y + h); - shape->lineTo(x + rx, y + h); - shape->cubicTo(x + rx - rhx, y + h, x, y + h - ry + rhy, x, y + h - ry); - shape->lineTo(x, y + ry); - shape->cubicTo(x, y + ry - rhy, x + rx - rhx, y, x + rx, y); - shape->close(); - } + shape->appendRect(node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h, node->node.rect.rx, node->node.rect.ry); break; } case SvgNodeType::Line: { diff --git a/test/testAsync.cpp b/test/testAsync.cpp index ca1d473..bb890ab 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -29,7 +29,7 @@ bool tvgUpdateCmds(tvg::Canvas* canvas) float w = 1 + rand() % (int)(WIDTH * 1.3 / 2); float h = 1 + rand() % (int)(HEIGHT * 1.3 / 2); - shape->appendRect(x, y, w, h, 0); + shape->appendRect(x, y, w, h, 0, 0); //LinearGradient auto fill = tvg::LinearGradient::gen(); diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 14bc9ac..6f5f6e1 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a if (canvas->push(move(shape1)) != tvg::Result::Success) return; @@ -151,4 +151,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index ca598e4..b23b82e 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -10,19 +10,19 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Shape1 auto shape1 = tvg::Shape::gen(); - shape1->appendRect(-100, -100, 1000, 1000, 50); + shape1->appendRect(-100, -100, 1000, 1000, 50, 50); shape1->fill(255, 255, 255, 255); if (canvas->push(move(shape1)) != tvg::Result::Success) return; //Prepare Shape2 auto shape2 = tvg::Shape::gen(); - shape2->appendRect(-100, -100, 250, 250, 50); + shape2->appendRect(-100, -100, 250, 250, 50, 50); shape2->fill(0, 0, 255, 255); if (canvas->push(move(shape2)) != tvg::Result::Success) return; //Prepare Shape3 auto shape3 = tvg::Shape::gen(); - shape3->appendRect(500, 500, 550, 550, 0); + shape3->appendRect(500, 500, 550, 550, 0, 0); shape3->fill(0, 255, 255, 255); if (canvas->push(move(shape3)) != tvg::Result::Success) return; @@ -140,4 +140,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 24fae64..437ad1f 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -14,7 +14,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(-100, -100, 200, 200, 0); + shape->appendRect(-100, -100, 200, 200, 0, 0); //fill property will be retained shape->fill(127, 255, 255, 255); @@ -32,7 +32,7 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) //Reset Shape if (pShape->reset() == tvg::Result::Success) { - pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress)); + pShape->appendRect(-100 + (800 * progress), -100 + (800 * progress), 200, 200, (100 * progress), (100 * progress)); pShape->stroke(30 * progress); //Update shape for drawing (this may work asynchronously) @@ -166,4 +166,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index ddc9c88..fd5a563 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -16,8 +16,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(-285, -300, 200, 200, 0); - shape->appendRect(-185, -200, 300, 300, 100); + shape->appendRect(-285, -300, 200, 200, 0, 0); + shape->appendRect(-185, -200, 300, 300, 100, 100); shape->appendCircle(115, 100, 100, 100); shape->appendCircle(115, 200, 170, 100); @@ -39,7 +39,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape2 auto shape2 = tvg::Shape::gen(); pShape2 = shape2.get(); - shape2->appendRect(-50, -50, 100, 100, 0); + shape2->appendRect(-50, -50, 100, 100, 0, 0); shape2->translate(400, 400); //LinearGradient @@ -61,7 +61,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) /* Look, how shape3's origin is different with shape2 The center of the shape is the anchor point for transformation. */ - shape3->appendRect(100, 100, 150, 100, 20); + shape3->appendRect(100, 100, 150, 100, 20, 20); //RadialGradient auto fill3 = tvg::RadialGradient::gen(); @@ -231,4 +231,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index d6f04e4..45f38d7 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 0, 0); //x, y, w, h, rx, ry //LinearGradient auto fill = tvg::LinearGradient::gen(); @@ -169,4 +169,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index b5c6d42..ec46f2f 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a if (canvas->push(move(shape1)) != tvg::Result::Success) return; @@ -129,4 +129,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index de93d46..71cfaae 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -10,7 +10,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 0); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 0, 0); //x, y, w, h, rx, ry //RadialGradient auto fill = tvg::RadialGradient::gen(); @@ -169,4 +169,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testScene.cpp b/test/testScene.cpp index ec1ed4a..bee2b54 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -12,7 +12,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(0, 0, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a scene->push(move(shape1)); @@ -176,4 +176,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index c1b1662..d5d538d 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -15,7 +15,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Prepare Round Rectangle (Scene1) auto shape1 = tvg::Shape::gen(); - shape1->appendRect(-235, -250, 400, 400, 50); //x, y, w, h, cornerRadius + shape1->appendRect(-235, -250, 400, 400, 50, 50); //x, y, w, h, rx, ry shape1->fill(0, 255, 0, 255); //r, g, b, a shape1->stroke(5); //width shape1->stroke(255, 255, 255, 255); //r, g, b, a diff --git a/test/testShape.cpp b/test/testShape.cpp index 617d024..e5e4c57 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -8,11 +8,11 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //Prepare a Shape (Rectangle + Rectangle + Circle + Circle) auto shape1 = tvg::Shape::gen(); - shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius - shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius - shape1->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH - shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH - shape1->fill(255, 255, 0, 255); //r, g, b, a + shape1->appendRect(0, 0, 200, 200, 0, 0); //x, y, w, h, rx, ry + shape1->appendRect(100, 100, 300, 300, 100, 100); //x, y, w, h, rx, ry + shape1->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH + shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH + shape1->fill(255, 255, 0, 255); //r, g, b, a canvas->push(move(shape1)); } diff --git a/test/testStroke.cpp b/test/testStroke.cpp index b9cfb4c..f4f7c8c 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -8,7 +8,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //Shape 1 auto shape1 = tvg::Shape::gen(); - shape1->appendRect(50, 50, 200, 200, 0); + shape1->appendRect(50, 50, 200, 200, 0, 0); shape1->fill(50, 50, 50, 255); shape1->stroke(255, 255, 255, 255); //color: r, g, b, a shape1->stroke(tvg::StrokeJoin::Bevel); //default is Bevel @@ -18,7 +18,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape 2 auto shape2 = tvg::Shape::gen(); - shape2->appendRect(300, 50, 200, 200, 0); + shape2->appendRect(300, 50, 200, 200, 0, 0); shape2->fill(50, 50, 50, 255); shape2->stroke(255, 255, 255, 255); shape2->stroke(tvg::StrokeJoin::Round); @@ -28,7 +28,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape 3 auto shape3 = tvg::Shape::gen(); - shape3->appendRect(550, 50, 200, 200, 0); + shape3->appendRect(550, 50, 200, 200, 0, 0); shape3->fill(50, 50, 50, 255); shape3->stroke(255, 255, 255, 255); shape3->stroke(tvg::StrokeJoin::Miter); @@ -166,4 +166,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testSvg.cpp b/test/testSvg.cpp index e023274..04b9ab0 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -33,7 +33,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //Background auto shape = tvg::Shape::gen(); - shape->appendRect(0, 0, WIDTH, HEIGHT, 0); //x, y, w, h, cornerRadius + shape->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry shape->fill(255, 255, 255, 255); //r, g, b, a if (canvas->push(move(shape)) != tvg::Result::Success) return; diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 35b237c..65492b1 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -16,8 +16,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) instead, you should consider not to interrupt this pointer life-cycle. */ pShape = shape.get(); - shape->appendRect(-285, -300, 200, 200, 0); - shape->appendRect(-185, -200, 300, 300, 100); + shape->appendRect(-285, -300, 200, 200, 0, 0); + shape->appendRect(-185, -200, 300, 300, 100, 100); shape->appendCircle(115, 100, 100, 100); shape->appendCircle(115, 200, 170, 100); shape->fill(255, 255, 255, 255); @@ -27,7 +27,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape2 auto shape2 = tvg::Shape::gen(); pShape2 = shape2.get(); - shape2->appendRect(-50, -50, 100, 100, 0); + shape2->appendRect(-50, -50, 100, 100, 0, 0); shape2->fill(0, 255, 255, 255); shape2->translate(400, 400); if (canvas->push(move(shape2)) != tvg::Result::Success) return; @@ -38,7 +38,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) /* Look, how shape3's origin is different with shape2 The center of the shape is the anchor point for transformation. */ - shape3->appendRect(100, 100, 150, 50, 20); + shape3->appendRect(100, 100, 150, 50, 20, 20); shape3->fill(255, 0, 255, 255); shape3->translate(400, 400); if (canvas->push(move(shape3)) != tvg::Result::Success) return; @@ -194,4 +194,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 051a581..6bfbddc 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -8,7 +8,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) { //Shape auto shape = tvg::Shape::gen(); - shape->appendRect(-100, -100, 200, 200, 0); + shape->appendRect(-100, -100, 200, 200, 0, 0); shape->fill(255, 255, 255, 255); canvas->push(move(shape)); } @@ -20,7 +20,7 @@ void tvgUpdateCmds(tvg::Canvas* canvas, float progress) //Shape auto shape = tvg::Shape::gen(); - shape->appendRect(-100, -100, 200, 200, (100 * progress)); + shape->appendRect(-100, -100, 200, 200, (100 * progress), (100 * progress)); shape->fill(rand()%255, rand()%255, rand()%255, 255); shape->translate(800 * progress, 800 * progress); shape->scale(1 - 0.75 * progress); @@ -155,4 +155,4 @@ int main(int argc, char **argv) //Terminate ThorVG Engine tvg::Initializer::term(tvgEngine); -} \ No newline at end of file +} -- 2.7.4 From d5e78eac71d73b6c73fdd42590feb1542c69d930 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 7 Jul 2020 10:15:05 +0900 Subject: [PATCH 06/16] SvgLoader: Async conversion of svg data Change-Id: I58025e646b531a0451be096ef1891377e655a3fc --- src/loaders/svg_loader/tvgSvgLoader.cpp | 70 +++++++++++++++++++-------------- src/loaders/svg_loader/tvgSvgLoader.h | 3 +- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 99bb689..81991a0 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2227,13 +2227,22 @@ static void _freeSvgNode(SvgNode* node) /************************************************************************/ -SvgLoader::SvgLoader() +SvgLoader::SvgLoader() : + loaderData {vector(), + nullptr, + nullptr, + vector(), + nullptr, + nullptr, + 0, + false} { } SvgLoader::~SvgLoader() { + if (rootProgress.valid()) root = rootProgress.get(); } @@ -2261,52 +2270,53 @@ bool SvgLoader::read() { if (content.empty()) return false; - loaderData = {vector(), - nullptr, - nullptr, - vector(), - nullptr, - nullptr, - 0, - false}; - - loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); - - bool res = simpleXmlParse(content.c_str(), content.size(), true, _svgLoaderParser, &loaderData); - - if (loaderData.doc) { - SvgNode *defs; - _updateStyle(loaderData.doc, nullptr); - defs = loaderData.doc->node.doc.defs; - if (defs) _updateGradient(loaderData.doc, defs->node.defs.gradients); - else { - if (!loaderData.gradients.empty()) { - vector gradientList; - std::copy(loaderData.gradients.begin(), loaderData.gradients.end(), gradientList.begin()); - _updateGradient(loaderData.doc, gradientList); - gradientList.clear(); + auto asyncTask = [](SvgLoader *loader) { + + loader->loaderData.svgParse = (SvgParser*)malloc(sizeof(SvgParser)); + + bool res = simpleXmlParse(loader->content.c_str(), loader->content.size(), true, _svgLoaderParser, &(loader->loaderData)); + + if (!res) return unique_ptr(nullptr); + + if (loader->loaderData.doc) { + SvgNode *defs; + _updateStyle(loader->loaderData.doc, nullptr); + defs = loader->loaderData.doc->node.doc.defs; + if (defs) _updateGradient(loader->loaderData.doc, defs->node.defs.gradients); + else { + if (!loader->loaderData.gradients.empty()) { + vector gradientList; + std::copy(loader->loaderData.gradients.begin(), loader->loaderData.gradients.end(), gradientList.begin()); + _updateGradient(loader->loaderData.doc, gradientList); + gradientList.clear(); + } } } - } + return loader->builder.build(loader->loaderData.doc); + }; - root = builder.build(loaderData.doc); + rootProgress = async(launch::async, asyncTask, this); - if (!res) return false; return true; } bool SvgLoader::close() { + if (rootProgress.valid()) root = rootProgress.get(); + if (loaderData.svgParse) free(loaderData.svgParse); _freeSvgNode(loaderData.doc); - return false; + return true; } unique_ptr SvgLoader::data() { - return move(root); + if (rootProgress.valid()) root = rootProgress.get(); + + if (root) return move(root); + else return unique_ptr(nullptr); } #endif //_TVG_SVG_LOADER_CPP_ diff --git a/src/loaders/svg_loader/tvgSvgLoader.h b/src/loaders/svg_loader/tvgSvgLoader.h index eba74c3..9a02a86 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.h +++ b/src/loaders/svg_loader/tvgSvgLoader.h @@ -19,7 +19,7 @@ #include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" - +#include class SvgLoader : public Loader { @@ -27,6 +27,7 @@ private: string content; SvgLoaderData loaderData; SvgSceneBuilder builder; + future> rootProgress; unique_ptr root; public: -- 2.7.4 From 88ed685f1da609c107e8095792b4bb446cf7c480 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 14:09:52 +0900 Subject: [PATCH 07/16] SvgLoader: Skip unnecessary transform calc Change-Id: I58e3baae6d68a2ad4a34c8b460fe67bd36f03b3d --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 2be0122..442cde4 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -48,9 +48,9 @@ unique_ptr _applyProperty(SvgNode* node, unique_ptr vg) if (node->transform) { float tx = 0, ty = 0, s = 0, z = 0; _getTransformationData(node->transform, &tx, &ty, &s, &z); - vg->scale(s); - vg->rotate(z); - vg->translate(tx, ty); + if (!(fabsf(s - 1) <= FLT_EPSILON)) vg->scale(s); + if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) vg->rotate(fmod(z, 360.0)); + if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) vg->translate(tx, ty); } if (node->type == SvgNodeType::Doc) return vg; @@ -174,9 +174,9 @@ unique_ptr _sceneBuildHelper(SvgNode* node) if (node->transform) { float tx = 0, ty = 0, s = 0, z = 0; _getTransformationData(node->transform, &tx, &ty, &s, &z); - scene->scale(s); - scene->rotate(z); - scene->translate(tx, ty); + if (!(fabsf(s - 1) <= FLT_EPSILON)) scene->scale(s); + if (!(fmod(fabsf(z), 360.0) <= FLT_EPSILON)) scene->rotate(fmod(z, 360.0)); + if (!(fabsf(tx) <= FLT_EPSILON) && !(fabsf(ty) <= FLT_EPSILON)) scene->translate(tx, ty); } for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { SvgNode* child = *itrChild; -- 2.7.4 From a94bd31d56b4886b4e2e252ebc17e7d74fe121bf Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 13:54:33 +0900 Subject: [PATCH 08/16] svg_loader: release resources just in case when it's destroyed. Change-Id: Ib4a61ae0769d3f9284e3cf450002750c47fba01c --- src/loaders/svg_loader/tvgSvgLoader.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 81991a0..928c754 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2242,7 +2242,7 @@ SvgLoader::SvgLoader() : SvgLoader::~SvgLoader() { - if (rootProgress.valid()) root = rootProgress.get(); + close(); } @@ -2305,8 +2305,13 @@ bool SvgLoader::close() { if (rootProgress.valid()) root = rootProgress.get(); - if (loaderData.svgParse) free(loaderData.svgParse); + if (loaderData.svgParse) { + free(loaderData.svgParse); + loaderData.svgParse = nullptr; + } _freeSvgNode(loaderData.doc); + loaderData.doc = nullptr; + return true; } -- 2.7.4 From 1d24838c672ffa1610b64cfa1e54c41ac4c0d365 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Mon, 6 Jul 2020 16:35:10 +0900 Subject: [PATCH 09/16] SvgLoader: Support arc_to draw Change-Id: I950c8e850605f990d6a0aa59a067ced571ffdb51 --- src/loaders/svg_loader/tvgSvgPath.cpp | 193 ++++++++++++++++++++++++++++++++-- 1 file changed, 183 insertions(+), 10 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp index c3d3cac..ba01ae7 100644 --- a/src/loaders/svg_loader/tvgSvgPath.cpp +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -14,7 +14,7 @@ static char* _skipComma(const char* content) } -static inline bool _parseNumber(char** content, float* number) +static bool _parseNumber(char** content, float* number) { char* end = NULL; *number = strtof(*content, &end); @@ -26,7 +26,7 @@ static inline bool _parseNumber(char** content, float* number) } -static inline bool _parseLong(char** content, int* number) +static bool _parseLong(char** content, int* number) { char* end = NULL; *number = strtol(*content, &end, 10) ? 1 : 0; @@ -36,6 +36,183 @@ static inline bool _parseLong(char** content, int* number) return true; } +void _pathAppendArcTo(vector* cmds, vector* pts, float* arr, Point* cur, Point* curCtl, float x, float y, float rx, float ry, float angle, bool largeArc, bool sweep) +{ + float cxp, cyp, cx, cy; + float sx, sy; + float cosPhi, sinPhi; + float dx2, dy2; + float x1p, y1p; + float x1p2, y1p2; + float rx2, ry2; + float lambda; + float c; + float at; + float theta1, deltaTheta; + float nat; + float delta, bcp; + float cosPhiRx, cosPhiRy; + float sinPhiRx, sinPhiRy; + float cosTheta1, sinTheta1; + int segments, i; + + //Some helpful stuff is available here: + //http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes + sx = cur->x; + sy = cur->y; + + //If start and end points are identical, then no arc is drawn + if ((fabs(x - sx) < (1.0f / 256.0f)) && (fabs(y - sy) < (1.0f / 256.0f))) return; + + //Correction of out-of-range radii, see F6.6.1 (step 2) + rx = fabs(rx); + ry = fabs(ry); + if ((rx < 0.5f) || (ry < 0.5f)) { + Point p = {x, y}; + cmds->push_back(PathCommand::LineTo); + pts->push_back(p); + *cur = p; + return; + } + + angle = angle * M_PI / 180.0f; + cosPhi = cosf(angle); + sinPhi = sinf(angle); + dx2 = (sx - x) / 2.0f; + dy2 = (sy - y) / 2.0f; + x1p = cosPhi * dx2 + sinPhi * dy2; + y1p = cosPhi * dy2 - sinPhi * dx2; + x1p2 = x1p * x1p; + y1p2 = y1p * y1p; + rx2 = rx * rx; + ry2 = ry * ry; + lambda = (x1p2 / rx2) + (y1p2 / ry2); + + //Correction of out-of-range radii, see F6.6.2 (step 4) + if (lambda > 1.0f) { + //See F6.6.3 + float lambdaRoot = sqrt(lambda); + + rx *= lambdaRoot; + ry *= lambdaRoot; + //Update rx2 and ry2 + rx2 = rx * rx; + ry2 = ry * ry; + } + + c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2); + + //Check if there is no possible solution + //(i.e. we can't do a square root of a negative value) + if (c < 0.0f) { + //Scale uniformly until we have a single solution + //(see F6.2) i.e. when c == 0.0 + float scale = sqrt(1.0f - c / (rx2 * ry2)); + rx *= scale; + ry *= scale; + //Update rx2 and ry2 + rx2 = rx * rx; + ry2 = ry * ry; + + //Step 2 (F6.5.2) - simplified since c == 0.0 + cxp = 0.0f; + cyp = 0.0f; + //Step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0 + cx = 0.0f; + cy = 0.0f; + } else { + //Complete c calculation + c = sqrt(c / ((rx2 * y1p2) + (ry2 * x1p2))); + //Inverse sign if Fa == Fs + if (largeArc == sweep) c = -c; + + //Step 2 (F6.5.2) + cxp = c * (rx * y1p / ry); + cyp = c * (-ry * x1p / rx); + + //Step 3 (F6.5.3 first part) + cx = cosPhi * cxp - sinPhi * cyp; + cy = sinPhi * cxp + cosPhi * cyp; + } + + //Step 3 (F6.5.3 second part) we now have the center point of the ellipse + cx += (sx + x) / 2.0f; + cy += (sy + y) / 2.0f; + + //Sstep 4 (F6.5.4) + //We dont' use arccos (as per w3c doc), see + //http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm + //Note: atan2 (0.0, 1.0) == 0.0 + at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx)); + theta1 = (at < 0.0f) ? 2.0f * M_PI + at : at; + + nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx)); + deltaTheta = (nat < at) ? 2.0f * M_PI - at + nat : nat - at; + + if (sweep) { + //Ensure delta theta < 0 or else add 360 degrees + if (deltaTheta < 0.0f) deltaTheta += 2.0f * M_PI; + } else { + //Ensure delta theta > 0 or else substract 360 degrees + if (deltaTheta > 0.0f) deltaTheta -= 2.0f * M_PI; + } + + //Add several cubic bezier to approximate the arc + //(smaller than 90 degrees) + //We add one extra segment because we want something + //Smaller than 90deg (i.e. not 90 itself) + segments = (int)(fabs(deltaTheta / M_PI_2)) + 1.0f; + delta = deltaTheta / segments; + + //http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13) + bcp = 4.0f / 3.0f * (1.0f - cos(delta / 2.0f)) / sin(delta / 2.0f); + + cosPhiRx = cosPhi * rx; + cosPhiRy = cosPhi * ry; + sinPhiRx = sinPhi * rx; + sinPhiRy = sinPhi * ry; + + cosTheta1 = cos(theta1); + sinTheta1 = sin(theta1); + + for (i = 0; i < segments; ++i) { + //End angle (for this segment) = current + delta + float c1x, c1y, ex, ey, c2x, c2y; + float theta2 = theta1 + delta; + float cosTheta2 = cos(theta2); + float sinTheta2 = sin(theta2); + static Point p[3]; + + //First control point (based on start point sx,sy) + c1x = sx - bcp * (cosPhiRx * sinTheta1 + sinPhiRy * cosTheta1); + c1y = sy + bcp * (cosPhiRy * cosTheta1 - sinPhiRx * sinTheta1); + + //End point (for this segment) + ex = cx + (cosPhiRx * cosTheta2 - sinPhiRy * sinTheta2); + ey = cy + (sinPhiRx * cosTheta2 + cosPhiRy * sinTheta2); + + //Second control point (based on end point ex,ey) + c2x = ex + bcp * (cosPhiRx * sinTheta2 + sinPhiRy * cosTheta2); + c2y = ey + bcp * (sinPhiRx * sinTheta2 - cosPhiRy * cosTheta2); + cmds->push_back(PathCommand::CubicTo); + p[0] = {c1x, c1y}; + p[1] = {c2x, c2y}; + p[2] = {ex, ey}; + pts->push_back(p[0]); + pts->push_back(p[1]); + pts->push_back(p[2]); + *curCtl = p[1]; + *cur = p[2]; + + //Next start point is the current end point (same for angle) + sx = ex; + sy = ey; + theta1 = theta2; + //Avoid recomputations + cosTheta1 = cosTheta2; + sinTheta1 = sinTheta2; + } +} static int _numberCount(char cmd) { @@ -170,12 +347,12 @@ static void _processCommand(vector* cmds, vector* pts, char } case 'q': case 'Q': { - tvg::Point p[3]; + Point p[3]; float ctrl_x0 = (cur->x + 2 * arr[0]) * (1.0 / 3.0); float ctrl_y0 = (cur->y + 2 * arr[1]) * (1.0 / 3.0); float ctrl_x1 = (arr[2] + 2 * arr[0]) * (1.0 / 3.0); float ctrl_y1 = (arr[3] + 2 * arr[1]) * (1.0 / 3.0); - cmds->push_back(tvg::PathCommand::CubicTo); + cmds->push_back(PathCommand::CubicTo); p[0] = {ctrl_x0, ctrl_y0}; p[1] = {ctrl_x1, ctrl_y1}; p[2] = {arr[2], arr[3]}; @@ -217,12 +394,8 @@ static void _processCommand(vector* cmds, vector* pts, char } case 'a': case 'A': { - //TODO: Implement arc_to - break; - } - case 'E': - case 'e': { - //TODO: Implement arc + _pathAppendArcTo(cmds, pts, arr, cur, curCtl, arr[5], arr[6], arr[0], arr[1], arr[2], arr[3], arr[4]); + *cur = {arr[5] ,arr[6]}; break; } default: { -- 2.7.4 From 6967b998b67d65e35e9dabd9cfecb0226fb87b1e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 15:12:11 +0900 Subject: [PATCH 10/16] common loader: return viewbox info from the vector resource. if a scene loads a vector resource, it must have viewbox info from the design, That viewbox will be used as bounding box so that user can scale up/down the scene by its requirements. Change-Id: Iafa39af23118a03de207c745364d56c837892e1b --- src/lib/tvgLoader.h | 6 +++ src/lib/tvgSceneImpl.h | 75 ++++++++++++++++++--------------- src/loaders/svg_loader/tvgSvgLoader.cpp | 7 +++ 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h index 8a1c918..8f5bb49 100644 --- a/src/lib/tvgLoader.h +++ b/src/lib/tvgLoader.h @@ -23,6 +23,12 @@ namespace tvg class Loader { public: + //default view box, if any. + float vx = 0; + float vy = 0; + float vw = 0; + float vh = 0; + virtual ~Loader() {} virtual bool open(const char* path) = 0; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 4e412d4..a70991c 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -74,11 +74,12 @@ struct Scene::Impl { if (loader) { auto scene = loader->data(); - auto p = scene.release(); - if (!p) return false; - paints.push_back(p); - loader->close(); - loader.reset(nullptr); + if (scene) { + auto p = scene.release(); + if (!p) return false; + paints.push_back(p); + loader->close(); + } } if (flag & RenderUpdateFlag::Transform) { @@ -121,38 +122,44 @@ struct Scene::Impl bool bounds(float* px, float* py, float* pw, float* ph) { - auto x = FLT_MAX; - auto y = FLT_MAX; - auto w = 0.0f; - auto h = 0.0f; - - for(auto paint: paints) { - auto x2 = FLT_MAX; - auto y2 = FLT_MAX; - auto w2 = 0.0f; - auto h2 = 0.0f; - - 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; - } else { - auto shape = static_cast(paint); - if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; + if (loader) { + if (px) *px = loader->vx; + if (py) *py = loader->vy; + if (pw) *pw = loader->vw; + if (ph) *ph = loader->vh; + } else { + auto x = FLT_MAX; + auto y = FLT_MAX; + auto w = 0.0f; + auto h = 0.0f; + + for(auto paint: paints) { + auto x2 = FLT_MAX; + auto y2 = FLT_MAX; + auto w2 = 0.0f; + auto h2 = 0.0f; + + 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; + } else { + auto shape = static_cast(paint); + if (!SHAPE_IMPL->bounds(&x2, &y2, &w2, &h2)) return false; + } + + //Merge regions + if (x2 < x) x = x2; + if (x + w < x2 + w2) w = (x2 + w2) - x; + if (y2 < y) y = x2; + if (y + h < y2 + h2) h = (y2 + h2) - y; } - //Merge regions - if (x2 < x) x = x2; - if (x + w < x2 + w2) w = (x2 + w2) - x; - if (y2 < y) y = x2; - if (y + h < y2 + h2) h = (y2 + h2) - y; + if (px) *px = x; + if (py) *py = y; + if (pw) *pw = w; + if (ph) *ph = h; } - - if (px) *px = x; - if (py) *py = y; - if (pw) *pw = w; - if (ph) *ph = h; - return true; } diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 928c754..d258005 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2262,6 +2262,13 @@ bool SvgLoader::open(const char* path) if (content.empty()) return false; } + //FIXME: Verify this resource is normal SVG, otherwise return false + //Also, return the brief resource info such as viewbox: + //this->vx = ? + //this->vy = ? + //this->vw = ? + //this->vh = ? + return true; } -- 2.7.4 From feb6aad641af8d792a1c3d57e642b641980048d5 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 7 Jul 2020 15:09:13 +0900 Subject: [PATCH 11/16] SvgLoader: Fix z-angle calculation Change-Id: I9220abd9f92dbdf250ea071af128a93a0bbb3d78 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 442cde4..69e4a0a 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -29,11 +29,11 @@ static void _getTransformationData(Matrix* m, float* tx, float* ty, float* s, fl *ty = m->e23; cs = m->e11; - si = m->e12; + si = m->e21; rz = atan2(si, cs); - *z = rz * (180.0 / M_PI); - zcs = cosf(rz); - zsi = sinf(rz); + *z = rz * (180.0f / M_PI); + zcs = cosf(-1.0f * rz); + zsi = sinf(-1.0f * rz); m->e11 = m->e11 * zcs + m->e12 * zsi; m->e22 = m->e21 * (-1 * zsi) + m->e22 * zcs; *s = m->e11 > m->e22 ? m->e11 : m->e22; -- 2.7.4 From 018f4919da4cfcbd3df97c5da91054a8f31688e0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 17:46:29 +0900 Subject: [PATCH 12/16] svg_loader: allow deferred loading. don't push thread to work hard unless it's necessary. that might occur performance drop. Change-Id: Ib71fa0ae46461b10b7ed7ef356512fbf2a7aa0a8 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 928c754..2bfafdb 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2295,7 +2295,7 @@ bool SvgLoader::read() return loader->builder.build(loader->loaderData.doc); }; - rootProgress = async(launch::async, asyncTask, this); + rootProgress = async((launch::async | launch::deferred), asyncTask, this); return true; } -- 2.7.4 From c0280e6d57ead75dd0304cb2cdbcf1efb36513c3 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Jul 2020 17:52:16 +0900 Subject: [PATCH 13/16] svg_loader: code refactoring. initialize members in its own constructor. Change-Id: I6450971330dd3e3235b0f690a8d9b066cf374212 --- src/loaders/svg_loader/tvgSvgLoader.cpp | 11 +---------- src/loaders/svg_loader/tvgSvgLoaderCommon.h | 14 +++++++------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgLoader.cpp b/src/loaders/svg_loader/tvgSvgLoader.cpp index 2bfafdb..cf91fb2 100644 --- a/src/loaders/svg_loader/tvgSvgLoader.cpp +++ b/src/loaders/svg_loader/tvgSvgLoader.cpp @@ -2226,16 +2226,7 @@ static void _freeSvgNode(SvgNode* node) /* External Class Implementation */ /************************************************************************/ - -SvgLoader::SvgLoader() : - loaderData {vector(), - nullptr, - nullptr, - vector(), - nullptr, - nullptr, - 0, - false} +SvgLoader::SvgLoader() { } diff --git a/src/loaders/svg_loader/tvgSvgLoaderCommon.h b/src/loaders/svg_loader/tvgSvgLoaderCommon.h index a909e54..b5ae7bb 100644 --- a/src/loaders/svg_loader/tvgSvgLoaderCommon.h +++ b/src/loaders/svg_loader/tvgSvgLoaderCommon.h @@ -325,13 +325,13 @@ struct SvgParser struct SvgLoaderData { vector stack; - SvgNode* doc; - SvgNode* def; + SvgNode* doc = nullptr; + SvgNode* def = nullptr; vector gradients; - SvgStyleGradient* latestGradient; //For stops - SvgParser* svgParse; - int level; - bool result; + SvgStyleGradient* latestGradient = nullptr; //For stops + SvgParser* svgParse = nullptr; + int level = 0; + bool result = false; }; -#endif +#endif \ No newline at end of file -- 2.7.4 From e2fc3538463a8e8b8370cb81ef6758df750a43cf Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 8 Jul 2020 10:44:51 +0900 Subject: [PATCH 14/16] build: refactoriong meson script. move gl dependency to gl_engine part which is right position. Change-Id: I9d4935f94eff96ca1527762c92d07f9b216f19cd --- meson.build | 2 +- src/lib/gl_engine/meson.build | 7 ++++++- src/meson.build | 6 +----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index b1cf7ac..66b907d 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('thorvg', 'cpp', - default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++14', 'optimization=s'], + default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++17', 'optimization=s'], version : '0.1.0', license : 'Apache-2.0') diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build index 943fb06..6856f1d 100644 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -14,7 +14,12 @@ source_file = [ 'tvgGlShaderSrc.cpp', ] +egl_dep = meson.get_compiler('cpp').find_library('EGL') +gles_dep = meson.get_compiler('cpp').find_library('GLESv2') +external_dep = [egl_dep, gles_dep] + glengine_dep = declare_dependency( + dependencies : external_dep, include_directories : include_directories('.'), - sources : source_file + sources : source_file, ) diff --git a/src/meson.build b/src/meson.build index 493497b..7320bb2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,12 +4,8 @@ subdir('lib') subdir('loaders') subdir('examples') -m_dep = meson.get_compiler('cpp').find_library('m') thread_dep = meson.get_compiler('cpp').find_library('pthread') -egl_dep = meson.get_compiler('cpp').find_library('EGL') -gles_dep = meson.get_compiler('cpp').find_library('GLESv2') - -thorvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, m_dep, egl_dep, gles_dep, svgloader_dep, thread_dep] +thorvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, svgloader_dep, thread_dep] thorvg_lib = library( -- 2.7.4 From 84af527a27b7e2cbe67717ee5fbb527ec903d35c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 8 Jul 2020 10:51:34 +0900 Subject: [PATCH 15/16] build: refactoring meson script. move out engine/loader dependency to its immediate parent folders. Change-Id: I7f08433fc6d2a333951fceaffea81cbe2e5da9e3 --- meson.build | 2 +- src/lib/meson.build | 8 +++++--- src/loaders/meson.build | 5 +++++ src/meson.build | 3 +-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 66b907d..0142de0 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('thorvg', 'cpp', - default_options : ['buildtype=debugoptimized', 'werror=false', 'cpp_std=c++17', 'optimization=s'], + default_options : ['buildtype=debugoptimized', 'werror=false', 'optimization=s'], version : '0.1.0', license : 'Apache-2.0') diff --git a/src/lib/meson.build b/src/lib/meson.build index 53c9a19..9a7dc61 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -25,8 +25,10 @@ source_file = [ 'tvgSwCanvas.cpp', ] -src_dep = declare_dependency( +engine_dep = [swengine_dep, glengine_dep] + +common_dep = declare_dependency( + dependencies : engine_dep, include_directories : include_directories('.'), - sources : source_file + sources : source_file ) - diff --git a/src/loaders/meson.build b/src/loaders/meson.build index 53186dd..3abf0fd 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -1 +1,6 @@ subdir('svg_loader') + +loader_dep = declare_dependency( + dependencies : svgloader_dep, + include_directories : include_directories('.'), +) diff --git a/src/meson.build b/src/meson.build index 7320bb2..faff2b3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,8 +5,7 @@ subdir('loaders') subdir('examples') thread_dep = meson.get_compiler('cpp').find_library('pthread') -thorvg_lib_dep = [ src_dep, swengine_dep, glengine_dep, svgloader_dep, thread_dep] - +thorvg_lib_dep = [ common_dep, loader_dep, thread_dep] thorvg_lib = library( 'thorvg', -- 2.7.4 From 581451ea8d593edecfd7d62a705d46110f11ac06 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 9 Jul 2020 15:40:21 +0900 Subject: [PATCH 16/16] SvgLoader: Fix typo (SCubic draw) Change-Id: Id54cf6a7ca66cdbc96cfb93143aacccab95de822 --- src/loaders/svg_loader/tvgSvgPath.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgPath.cpp b/src/loaders/svg_loader/tvgSvgPath.cpp index ba01ae7..bd43027 100644 --- a/src/loaders/svg_loader/tvgSvgPath.cpp +++ b/src/loaders/svg_loader/tvgSvgPath.cpp @@ -328,9 +328,9 @@ static void _processCommand(vector* cmds, vector* pts, char case 's': case 'S': { Point p[3], ctrl; - if ((cmds->size() > 1) && (cmds->at(cmds->size() - 2) == PathCommand::CubicTo)) { + if ((cmds->size() > 1) && (cmds->at(cmds->size() - 1) == PathCommand::CubicTo)) { ctrl.x = 2 * cur->x - curCtl->x; - ctrl.y = 2 * cur->x - curCtl->y; + ctrl.y = 2 * cur->y - curCtl->y; } else { ctrl = *cur; } -- 2.7.4