From 96477c0a24f4112170ff4d084518a735d8f6483e Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 21 Jul 2020 17:18:48 +0900 Subject: [PATCH 01/16] sw_engine: revise outline transform sw_engine simulates floating point by integer bit shifting, it loses the accuracy while converting the number data. This occurs the inacculated curve points result if it scales up very large size. So we transform points before converting data in order to avoid losing the numbers less decimal point. Change-Id: I0172e83f06b1a19143a2f65f667dc193e9a4396a --- src/lib/sw_engine/tvgSwCommon.h | 10 +--- src/lib/sw_engine/tvgSwRenderer.cpp | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 101 +++++++++++++++++------------------- 3 files changed, 50 insertions(+), 63 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 5e47483..3639166 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -207,12 +207,6 @@ struct SwShape }; -static inline SwPoint TO_SWPOINT(const Point* pt) -{ - return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; -} - - static inline SwCoord TO_SWCOORD(float val) { return SwCoord(val * 64); @@ -261,12 +255,12 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& SwFixed mathMean(SwFixed angle1, SwFixed angle2); void shapeReset(SwShape& shape); -bool shapeGenOutline(SwShape& shape, const Shape* sdata); +bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform); bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); 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); +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); void shapeFree(SwShape& shape); void shapeDelStroke(SwShape& shape); bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transform, bool ctable); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index adc3e9f..7c3ca8d 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -212,7 +212,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (strokeAlpha > 0) { shapeResetStroke(task->shape, task->sdata); - if (!shapeGenStrokeRle(task->shape, task->sdata, task->clip)) return; + if (!shapeGenStrokeRle(task->shape, task->sdata, task->transform, task->clip)) return; } else { shapeDelStroke(task->shape); } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 026dae0..d302fd7 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -96,13 +96,25 @@ static void _outlineEnd(SwOutline& outline) } -static void _outlineMoveTo(SwOutline& outline, const Point* to) +static inline SwPoint _transform(const Point* to, const Matrix* transform) +{ + if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)}; + + auto tx = round(to->x * transform->e11 + to->y * transform->e12 + transform->e13); + auto ty = round(to->x * transform->e21 + to->y * transform->e22 + transform->e23); + + return {TO_SWCOORD(tx), TO_SWCOORD(ty)}; +} + + +static void _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform) { assert(to); _growOutlinePoint(outline, 1); - outline.pts[outline.ptsCnt] = TO_SWPOINT(to); + outline.pts[outline.ptsCnt] = _transform(to, transform); + outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; if (outline.ptsCnt > 0) { @@ -115,33 +127,33 @@ static void _outlineMoveTo(SwOutline& outline, const Point* to) } -static void _outlineLineTo(SwOutline& outline, const Point* to) +static void _outlineLineTo(SwOutline& outline, const Point* to, const Matrix* transform) { assert(to); _growOutlinePoint(outline, 1); - outline.pts[outline.ptsCnt] = TO_SWPOINT(to); + outline.pts[outline.ptsCnt] = _transform(to, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } -static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to) +static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform) { assert(ctrl1 && ctrl2 && to); _growOutlinePoint(outline, 3); - outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl1); + outline.pts[outline.ptsCnt] = _transform(ctrl1, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; - outline.pts[outline.ptsCnt] = TO_SWPOINT(ctrl2); + outline.pts[outline.ptsCnt] = _transform(ctrl2, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_CUBIC; ++outline.ptsCnt; - outline.pts[outline.ptsCnt] = TO_SWPOINT(to); + outline.pts[outline.ptsCnt] = _transform(to, transform); outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT; ++outline.ptsCnt; } @@ -230,24 +242,7 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi } -static void _transformOutline(SwOutline* outline, const Matrix* transform) -{ - if (!transform) return; - - assert(outline); - - 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{round(tx), round(ty)}; - outline->pts[i] = TO_SWPOINT(&pt); - } -} - - -static void _dashLineTo(SwDashStroke& dash, const Point* to) +static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* transform) { _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); @@ -258,8 +253,8 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) if (len < dash.curLen) { dash.curLen -= len; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &dash.ptCur); - _outlineLineTo(*dash.outline, to); + _outlineMoveTo(*dash.outline, &dash.ptCur, transform); + _outlineLineTo(*dash.outline, to, transform); } } else { while (len > dash.curLen) { @@ -268,8 +263,8 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) _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); + _outlineMoveTo(*dash.outline, &left.pt1, transform); + _outlineLineTo(*dash.outline, &left.pt2, transform); } dash.curLen = dash.pattern[dash.curIdx]; dash.curOpGap = !dash.curOpGap; @@ -278,9 +273,9 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) } //leftovers dash.curLen -= len; - if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &cur.pt1); - _outlineLineTo(*dash.outline, &cur.pt2); + if (!dash.curOpGap) { + _outlineMoveTo(*dash.outline, &cur.pt1, transform); + _outlineLineTo(*dash.outline, &cur.pt2, transform); } if (dash.curLen < 1) { //move to next dash @@ -293,7 +288,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to) } -static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to) +static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ctrl2, const Point* to, const Matrix* transform) { _growOutlinePoint(*dash.outline, dash.outline->ptsCnt >> 1); _growOutlineContour(*dash.outline, dash.outline->cntrsCnt >> 1); @@ -304,8 +299,8 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct if (len < dash.curLen) { dash.curLen -= len; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &dash.ptCur); - _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to); + _outlineMoveTo(*dash.outline, &dash.ptCur, transform); + _outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform); } } else { while (len > dash.curLen) { @@ -314,8 +309,8 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct 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); + _outlineMoveTo(*dash.outline, &left.start, transform); + _outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end, transform); } dash.curLen = dash.pattern[dash.curIdx]; dash.curOpGap = !dash.curOpGap; @@ -325,8 +320,8 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct //leftovers dash.curLen -= len; if (!dash.curOpGap) { - _outlineMoveTo(*dash.outline, &cur.start); - _outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end); + _outlineMoveTo(*dash.outline, &cur.start, transform); + _outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end, transform); } if (dash.curLen < 1) { //move to next dash @@ -339,7 +334,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct } -SwOutline* _genDashOutline(const Shape* sdata) +SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) { assert(sdata); @@ -405,7 +400,7 @@ SwOutline* _genDashOutline(const Shape* sdata) while (cmdCnt-- > 0) { switch(*cmds) { case PathCommand::Close: { - _dashLineTo(dash, &dash.ptStart); + _dashLineTo(dash, &dash.ptStart, transform); break; } case PathCommand::MoveTo: { @@ -418,12 +413,12 @@ SwOutline* _genDashOutline(const Shape* sdata) break; } case PathCommand::LineTo: { - _dashLineTo(dash, pts); + _dashLineTo(dash, pts, transform); ++pts; break; } case PathCommand::CubicTo: { - _dashCubicTo(dash, pts, pts + 1, pts + 2); + _dashCubicTo(dash, pts, pts + 1, pts + 2, transform); pts += 3; break; } @@ -465,9 +460,7 @@ bool _fastTrack(const SwOutline* outline) bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform) { - if (!shapeGenOutline(shape, sdata)) return false; - - _transformOutline(shape.outline, transform); + if (!shapeGenOutline(shape, sdata, transform)) return false; if (!_updateBBox(shape.outline, shape.bbox)) return false; @@ -510,7 +503,7 @@ void shapeReset(SwShape& shape) } -bool shapeGenOutline(SwShape& shape, const Shape* sdata) +bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform) { assert(sdata); @@ -571,17 +564,17 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata) break; } case PathCommand::MoveTo: { - _outlineMoveTo(*outline, pts); + _outlineMoveTo(*outline, pts, transform); ++pts; break; } case PathCommand::LineTo: { - _outlineLineTo(*outline, pts); + _outlineLineTo(*outline, pts, transform); ++pts; break; } case PathCommand::CubicTo: { - _outlineCubicTo(*outline, pts, pts + 1, pts + 2); + _outlineCubicTo(*outline, pts, pts + 1, pts + 2, transform); pts += 3; break; } @@ -638,7 +631,7 @@ void shapeResetStroke(SwShape& shape, const Shape* sdata) } -bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) +bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip) { assert(sdata); @@ -646,12 +639,12 @@ bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const SwSize& clip) //Dash Style Stroke if (sdata->strokeDash(nullptr) > 0) { - shapeOutline = _genDashOutline(sdata); + shapeOutline = _genDashOutline(sdata, transform); if (!shapeOutline) return false; //Normal Style stroke } else { if (!shape.outline) { - if (!shapeGenOutline(shape, sdata)) return false; + if (!shapeGenOutline(shape, sdata, transform)) return false; } shapeOutline = shape.outline; } -- 2.7.4 From 5dcafb8b89928d36821a5c92573df2009b6ae821 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 22 Jul 2020 18:45:11 +0900 Subject: [PATCH 02/16] comon: code refactoring renamed internal variable for better readibility. Change-Id: I07dc66c4bd63f2aec8036aab14ec3ed608820fbc --- src/lib/tvgRender.cpp | 6 +++--- src/lib/tvgRender.h | 2 +- src/lib/tvgSceneImpl.h | 4 ++-- src/lib/tvgShapeImpl.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/tvgRender.cpp b/src/lib/tvgRender.cpp index 4317aac..89edcb1 100644 --- a/src/lib/tvgRender.cpp +++ b/src/lib/tvgRender.cpp @@ -48,7 +48,7 @@ bool RenderTransform::update() //Init Status if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON && - fabsf(degree) <= FLT_EPSILON && fabsf(factor - 1) <= FLT_EPSILON) { + fabsf(degree) <= FLT_EPSILON && fabsf(scale - 1) <= FLT_EPSILON) { return false; } @@ -64,8 +64,8 @@ bool RenderTransform::update() m.e33 = 1.0f; //scale - m.e11 *= factor; - m.e22 *= factor; + m.e11 *= scale; + m.e22 *= scale; //rotation if (fabsf(degree) > FLT_EPSILON) { diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index e20271b..576961e 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -36,7 +36,7 @@ struct RenderTransform float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree - float factor = 1.0f; //scale factor + float scale = 1.0f; //scale factor bool overriding = false; //user transform? bool update(); diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index a70991c..9972d72 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -166,13 +166,13 @@ struct Scene::Impl bool scale(float factor) { if (rTransform) { - if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; rTransform = new RenderTransform(); if (!rTransform) return false; } - rTransform->factor = factor; + rTransform->scale = factor; flag |= RenderUpdateFlag::Transform; return true; diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index fa670f0..54d37a3 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -105,13 +105,13 @@ struct Shape::Impl bool scale(float factor) { if (rTransform) { - if (fabsf(factor - rTransform->factor) <= FLT_EPSILON) return true; + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; } else { if (fabsf(factor) <= FLT_EPSILON) return true; rTransform = new RenderTransform(); if (!rTransform) return false; } - rTransform->factor = factor; + rTransform->scale = factor; if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; return true; -- 2.7.4 From 4d72eeda1556e179ecf7b60bc2a7829a476ef8e8 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 21 Jul 2020 20:24:25 +0900 Subject: [PATCH 03/16] sw_engine: revise scale transform logic. Basically, stroke width size is linear, engine couldn't apply scale factor from the matrix which contains 2 dimensional values. Thus, we can apply it if the scale factor of x/y is identical. Otherwise, we should transform every stroke points in the stroking process. That scenario can be improved with another patch. Change-Id: I070dcf29d2e42f21e182bdf4239781464158ef73 --- src/lib/sw_engine/tvgSwCommon.h | 5 +++-- src/lib/sw_engine/tvgSwRenderer.cpp | 4 ++-- src/lib/sw_engine/tvgSwShape.cpp | 4 ++-- src/lib/sw_engine/tvgSwStroke.cpp | 11 +++++++++-- src/lib/tvgRender.h | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 3639166..b1d38af 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -156,6 +156,7 @@ struct SwStroke bool firstPt; bool openSubPath; bool handleWideStrokes; + bool preScaled; }; struct SwDashStroke @@ -259,7 +260,7 @@ bool shapeGenOutline(SwShape& shape, const Shape* sdata, const Matrix* transform bool shapePrepare(SwShape& shape, const Shape* sdata, const SwSize& clip, const Matrix* transform); bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, bool antiAlias); void shapeDelOutline(SwShape& shape); -void shapeResetStroke(SwShape& shape, const Shape* sdata); +void shapeResetStroke(SwShape& shape, const Shape* sdata, const Matrix* transform); bool shapeGenStrokeRle(SwShape& shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); void shapeFree(SwShape& shape); void shapeDelStroke(SwShape& shape); @@ -267,7 +268,7 @@ bool shapeGenFillColors(SwShape& shape, const Fill* fill, const Matrix* transfor void shapeResetFill(SwShape& shape); void shapeDelFill(SwShape& shape); -void strokeReset(SwStroke& stroke, const Shape* shape); +void strokeReset(SwStroke& stroke, const Shape* shape, const Matrix* transform); bool strokeParseOutline(SwStroke& stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke& stroke); void strokeFree(SwStroke* stroke); diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 7c3ca8d..aac6d8e 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -211,7 +211,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* //Stroke if (task->flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (strokeAlpha > 0) { - shapeResetStroke(task->shape, task->sdata); + shapeResetStroke(task->shape, task->sdata, task->transform); if (!shapeGenStrokeRle(task->shape, task->sdata, task->transform, task->clip)) return; } else { shapeDelStroke(task->shape); @@ -257,4 +257,4 @@ SwRenderer* SwRenderer::inst() return static_cast(RenderInitializer::inst(renderInit)); } -#endif /* _TVG_SW_RENDERER_CPP_ */ +#endif /* _TVG_SW_RENDERER_CPP_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index d302fd7..c3aced8 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -618,13 +618,13 @@ void shapeDelStroke(SwShape& shape) } -void shapeResetStroke(SwShape& shape, const Shape* sdata) +void shapeResetStroke(SwShape& shape, const Shape* sdata, const Matrix* transform) { if (!shape.stroke) shape.stroke = static_cast(calloc(1, sizeof(SwStroke))); auto stroke = shape.stroke; assert(stroke); - strokeReset(*stroke, sdata); + strokeReset(*stroke, sdata, transform); rleFree(shape.strokeRle); shape.strokeRle = nullptr; diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index d45ddd8..abaf455 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -818,11 +818,18 @@ void strokeFree(SwStroke* stroke) } -void strokeReset(SwStroke& stroke, const Shape* sdata) +void strokeReset(SwStroke& stroke, const Shape* sdata, const Matrix* transform) { assert(sdata); - stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5); + //If x/y scale factor is identical, we can scale width size simply. + auto scale = 1.0f; + if (transform && fabsf(transform->e11 - transform->e22) < FLT_EPSILON) { + scale = transform->e11; + stroke.preScaled = true; + } + + stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5 * scale); stroke.cap = sdata->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 576961e..6a0897e 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -32,7 +32,7 @@ enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, struct RenderTransform { - Matrix m; //3x3 Matrix Elements + Matrix m; //3x3 Matrix Elements float x = 0.0f; float y = 0.0f; float degree = 0.0f; //rotation degree -- 2.7.4 From 62aa24d9adcb1c84b623b1bdfe6197b6234a1160 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Thu, 23 Jul 2020 10:14:46 +0900 Subject: [PATCH 04/16] SvgLoader: Fix opacity propagation Remove duplicate opacity calculation of the scene. Change-Id: I1253ea290e78fdbf946a492ebfcaaa082fbfc121 --- src/loaders/svg_loader/tvgSvgSceneBuilder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp index 3b88d96..4d7a27a 100644 --- a/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg_loader/tvgSvgSceneBuilder.cpp @@ -335,9 +335,11 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; if (node->display) { for (auto child : node->child) { - child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity)); - else scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); + else { + child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; + scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); + } } } return move(scene); -- 2.7.4 From f1aab529589fa4ff0bbafe86965d9e25ec40e3b0 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 22 Jul 2020 20:31:57 +0900 Subject: [PATCH 05/16] sw_engine: support bidirectional stroke scaling. if the transform scale factor for x/y is not identical, it keeps its both xy scale factor then apply them for stroking calculation. Change-Id: I519dfce3ce7b4a12c13da1801d6a00e139e7400f --- src/lib/sw_engine/tvgSwCommon.h | 5 ++- src/lib/sw_engine/tvgSwShape.cpp | 22 +++++++------- src/lib/sw_engine/tvgSwStroke.cpp | 64 +++++++++++++++++++++++++++++++-------- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index b1d38af..bad159b 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -153,10 +153,13 @@ struct SwStroke SwStrokeBorder borders[2]; + float sx; + float sy; + bool firstPt; bool openSubPath; bool handleWideStrokes; - bool preScaled; + bool postScale; }; struct SwDashStroke diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index c3aced8..2165f42 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -30,6 +30,17 @@ struct Line }; +static SwPoint _transform(const Point* to, const Matrix* transform) +{ + if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)}; + + auto tx = round(to->x * transform->e11 + to->y * transform->e12 + transform->e13); + auto ty = round(to->x * transform->e21 + to->y * transform->e22 + transform->e23); + + return {TO_SWCOORD(tx), TO_SWCOORD(ty)}; +} + + static float _lineLength(const Point& pt1, const Point& pt2) { /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. @@ -96,17 +107,6 @@ static void _outlineEnd(SwOutline& outline) } -static inline SwPoint _transform(const Point* to, const Matrix* transform) -{ - if (!transform) return {TO_SWCOORD(to->x), TO_SWCOORD(to->y)}; - - auto tx = round(to->x * transform->e11 + to->y * transform->e12 + transform->e13); - auto ty = round(to->x * transform->e21 + to->y * transform->e22 + transform->e23); - - return {TO_SWCOORD(tx), TO_SWCOORD(ty)}; -} - - static void _outlineMoveTo(SwOutline& outline, const Point* to, const Matrix* transform) { assert(to); diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index abaf455..53fae90 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -34,6 +34,15 @@ static inline SwFixed SIDE_TO_ROTATE(const int32_t s) } +static inline void SCALE(SwStroke& stroke, SwPoint& pt) +{ + if (stroke.postScale) { + pt.x = pt.x * stroke.sx; + pt.y = pt.y * stroke.sy; + } +} + + static void _growBorder(SwStrokeBorder* border, uint32_t newPts) { assert(border); @@ -132,11 +141,12 @@ static void _borderCubicTo(SwStrokeBorder* border, SwPoint& ctrl1, SwPoint& ctrl } -static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff) +static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius, SwFixed angleStart, SwFixed angleDiff, SwStroke& stroke) { constexpr SwFixed ARC_CUBIC_ANGLE = SW_ANGLE_PI / 2; SwPoint a = {radius, 0}; mathRotate(a, angleStart); + SCALE(stroke, a); a += center; auto total = angleDiff; @@ -157,6 +167,7 @@ static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius //compute end point SwPoint b = {radius, 0}; mathRotate(b, next); + SCALE(stroke, b); b += center; //compute first and second control points @@ -164,10 +175,12 @@ static void _borderArcTo(SwStrokeBorder* border, SwPoint& center, SwFixed radius SwPoint a2 = {length, 0}; mathRotate(a2, angle + rotate); + SCALE(stroke, a2); a2 += a; SwPoint b2 = {length, 0}; mathRotate(b2, next - rotate); + SCALE(stroke, b2); b2 += b; //add cubic arc @@ -224,7 +237,7 @@ static void _arcTo(SwStroke& stroke, int32_t side) auto total = mathDiff(stroke.angleIn, stroke.angleOut); if (total == SW_ANGLE_PI) total = -rotate * 2; - _borderArcTo(border, stroke.center, stroke.width, stroke.angleIn + rotate, total); + _borderArcTo(border, stroke.center, stroke.width, stroke.angleIn + rotate, total, stroke); border->movable = false; } @@ -268,6 +281,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (bevel) { SwPoint delta = {stroke.width, 0}; mathRotate(delta, stroke.angleOut + rotate); + SCALE(stroke, delta); delta += stroke.center; border->movable = false; _borderLineTo(border, delta, false); @@ -276,6 +290,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) auto length = mathDivide(stroke.width, thcos); SwPoint delta = {length, 0}; mathRotate(delta, phi); + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); @@ -284,6 +299,7 @@ static void _outside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (lineLength == 0) { delta = {stroke.width, 0}; mathRotate(delta, stroke.angleOut + rotate); + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); } @@ -312,15 +328,16 @@ static void _inside(SwStroke& stroke, int32_t side, SwFixed lineLength) if (!intersect) { delta = {stroke.width, 0}; mathRotate(delta, stroke.angleOut + rotate); + SCALE(stroke, delta); delta += stroke.center; border->movable = false; } else { //compute median angle auto phi = stroke.angleIn + theta; auto thcos = mathCos(theta); - auto length = mathDivide(stroke.width, thcos); - delta = {length, 0}; + delta = {mathDivide(stroke.width, thcos), 0}; mathRotate(delta, phi + rotate); + SCALE(stroke, delta); delta += stroke.center; } @@ -353,6 +370,7 @@ void _firstSubPath(SwStroke& stroke, SwFixed startAngle, SwFixed lineLength) { SwPoint delta = {stroke.width, 0}; mathRotate(delta, startAngle + SW_ANGLE_PI2); + SCALE(stroke, delta); auto pt = stroke.center + delta; auto border = stroke.borders; @@ -383,6 +401,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) delta = {stroke.width, 0}; mathRotate(delta, angle + SW_ANGLE_PI2); + SCALE(stroke, delta); //process corner if necessary if (stroke.firstPt) { @@ -428,9 +447,9 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl } SwPoint bezStack[37]; //TODO: static? - auto firstArc = true; auto limit = bezStack + 32; auto arc = bezStack; + auto firstArc = true; arc[0] = to; arc[1] = ctrl2; arc[2] = ctrl1; @@ -494,15 +513,18 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl //compute control points SwPoint _ctrl1 = {length1, 0}; mathRotate(_ctrl1, phi1 + rotate); + SCALE(stroke, _ctrl1); _ctrl1 += arc[2]; SwPoint _ctrl2 = {length2, 0}; mathRotate(_ctrl2, phi2 + rotate); + SCALE(stroke, _ctrl2); _ctrl2 += arc[1]; //compute end point SwPoint _end = {stroke.width, 0}; mathRotate(_end, angleOut + rotate); + SCALE(stroke, _end); _end += arc[0]; if (stroke.handleWideStrokes) { @@ -526,6 +548,7 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl SwPoint delta = {alen, 0}; mathRotate(delta, beta); + SCALE(stroke, delta); delta += _start; //circumnavigate the negative sector backwards @@ -557,25 +580,28 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) { - if (stroke.cap == StrokeCap::Square) { + if (stroke.cap == StrokeCap::Square) { auto rotate = SIDE_TO_ROTATE(side); auto border = stroke.borders + side; SwPoint delta = {stroke.width, 0}; mathRotate(delta, angle); + SCALE(stroke, delta); SwPoint delta2 = {stroke.width, 0}; mathRotate(delta2, angle + rotate); + SCALE(stroke, delta2); delta += stroke.center + delta2; _borderLineTo(border, delta, false); delta = {stroke.width, 0}; mathRotate(delta, angle); + SCALE(stroke, delta); delta2 = {stroke.width, 0}; mathRotate(delta2, angle - rotate); - + SCALE(stroke, delta2); delta += delta2 + stroke.center; _borderLineTo(border, delta, false); @@ -593,14 +619,14 @@ static void _addCap(SwStroke& stroke, SwFixed angle, int32_t side) SwPoint delta = {stroke.width, 0}; mathRotate(delta, angle + rotate); - + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); delta = {stroke.width, 0}; mathRotate(delta, angle - rotate); - + SCALE(stroke, delta); delta += stroke.center; _borderLineTo(border, delta, false); @@ -822,11 +848,23 @@ void strokeReset(SwStroke& stroke, const Shape* sdata, const Matrix* transform) { assert(sdata); - //If x/y scale factor is identical, we can scale width size simply. auto scale = 1.0f; - if (transform && fabsf(transform->e11 - transform->e22) < FLT_EPSILON) { - scale = transform->e11; - stroke.preScaled = true; + + if (transform) { + //Fast Track: if x/y scale factor is identical, we can scale width size simply. + auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); + if (fabsf(sx - sy) < FLT_EPSILON) { + scale = sx; + stroke.postScale = false; + //Try scaling stroke with normal approach. + } else { + stroke.postScale = true; + stroke.sx = sx; + stroke.sy = sy; + } + } else { + stroke.postScale = false; } stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5 * scale); -- 2.7.4 From 5fdc1f7fc86b9a9667741491c63d060ecfb15dd6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 24 Jul 2020 11:03:20 +0900 Subject: [PATCH 06/16] sw_engine: revise stroke scaling logic. previous fast track logic is useless, it actually doesn't helpful for performance, just increase the code complexity. Change-Id: Ib6ad204edfb241d74c41413dfec7ab42fb02af81 --- src/lib/sw_engine/tvgSwCommon.h | 4 +--- src/lib/sw_engine/tvgSwStroke.cpp | 27 ++++++--------------------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index bad159b..5f7ec46 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -153,13 +153,11 @@ struct SwStroke SwStrokeBorder borders[2]; - float sx; - float sy; + float sx, sy; bool firstPt; bool openSubPath; bool handleWideStrokes; - bool postScale; }; struct SwDashStroke diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 53fae90..15cbf02 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -36,10 +36,8 @@ static inline SwFixed SIDE_TO_ROTATE(const int32_t s) static inline void SCALE(SwStroke& stroke, SwPoint& pt) { - if (stroke.postScale) { - pt.x = pt.x * stroke.sx; - pt.y = pt.y * stroke.sy; - } + pt.x *= stroke.sx; + pt.y *= stroke.sy; } @@ -548,7 +546,6 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl SwPoint delta = {alen, 0}; mathRotate(delta, beta); - SCALE(stroke, delta); delta += _start; //circumnavigate the negative sector backwards @@ -848,26 +845,14 @@ void strokeReset(SwStroke& stroke, const Shape* sdata, const Matrix* transform) { assert(sdata); - auto scale = 1.0f; - if (transform) { - //Fast Track: if x/y scale factor is identical, we can scale width size simply. - auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); - auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); - if (fabsf(sx - sy) < FLT_EPSILON) { - scale = sx; - stroke.postScale = false; - //Try scaling stroke with normal approach. - } else { - stroke.postScale = true; - stroke.sx = sx; - stroke.sy = sy; - } + stroke.sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + stroke.sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); } else { - stroke.postScale = false; + stroke.sx = stroke.sy = 1.0f; } - stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5 * scale); + stroke.width = TO_SWCOORD(sdata->strokeWidth() * 0.5); stroke.cap = sdata->strokeCap(); //Save line join: it can be temporarily changed when stroking curves... -- 2.7.4 From 76a7c900bebceb7735712366cb7571b2fa105874 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 23 Jul 2020 20:56:05 +0900 Subject: [PATCH 07/16] sw_engine gradient: support x/y scale for radial gradient Change-Id: Id725637e261642d0e92d100c73841278b7f44c1c --- src/lib/sw_engine/tvgSwCommon.h | 2 ++ src/lib/sw_engine/tvgSwFill.cpp | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 5f7ec46..469ce0f 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -193,6 +193,8 @@ struct SwFill uint32_t* ctable; FillSpread spread; + float sx, sy; + bool translucent; }; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 43514bc..0ac9383 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -130,12 +130,25 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr if (radial->radial(&fill->radial.cx, &fill->radial.cy, &radius) != Result::Success) return false; if (radius < FLT_EPSILON) return true; + fill->sx = 1.0f; + fill->sy = 1.0f; + if (transform) { auto tx = fill->radial.cx * transform->e11 + fill->radial.cy * transform->e12 + transform->e13; auto ty = fill->radial.cx * transform->e21 + fill->radial.cy * transform->e22 + transform->e23; fill->radial.cx = tx; fill->radial.cy = ty; - radius *= transform->e33; + + auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); + + //FIXME; Scale + Rotation is not working properly + radius *= sx; + + if (fabsf(sx - sy) > FLT_EPSILON) { + fill->sx = sx; + fill->sy = sy; + } } fill->radial.a = radius * radius; @@ -190,8 +203,8 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fill->radial.a < FLT_EPSILON) return; //Rotation - auto rx = x + 0.5f - fill->radial.cx; - auto ry = y + 0.5f - fill->radial.cy; + auto rx = (x + 0.5f - fill->radial.cx) * fill->sy; + auto ry = (y + 0.5f - fill->radial.cy) * fill->sx; auto inv2a = fill->radial.inv2a; auto rxy = rx * rx + ry * ry; auto rxryPlus = 2 * rx; -- 2.7.4 From bee94d48fee5c2d17716d63f5b15d79c45feab36 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 24 Jul 2020 21:09:24 +0900 Subject: [PATCH 08/16] sw_engine gradient: support x/y scale for linear gradient Change-Id: Ic58e7cc61a3c90307b6cfb629eb8af69b75fb903 --- src/lib/sw_engine/tvgSwFill.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 0ac9383..266acaa 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -96,16 +96,18 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr if (linear->linear(&x1, &y1, &x2, &y2) != Result::Success) return false; if (transform) { + auto sx = sqrt(pow(transform->e11, 2) + pow(transform->e21, 2)); + auto sy = sqrt(pow(transform->e12, 2) + pow(transform->e22, 2)); auto cx = (x2 - x1) * 0.5f + x1; auto cy = (y2 - y1) * 0.5f + y1; auto dx = x1 - cx; auto dy = y1 - cy; - x1 = dx * transform->e11 + dy * transform->e12 + transform->e13 + cx; - y1 = dx * transform->e21 + dy * transform->e22 + transform->e23 + cy; + x1 = dx * transform->e11 + dy * transform->e12 + transform->e13 + (cx * sx); + y1 = dx * transform->e21 + dy * transform->e22 + transform->e23 + (cy * sy); dx = x2 - cx; dy = y2 - cy; - x2 = dx * transform->e11 + dy * transform->e12 + transform->e13 + cx; - y2 = dx * transform->e21 + dy * transform->e22 + transform->e23 + cy; + x2 = dx * transform->e11 + dy * transform->e12 + transform->e13 + (cx * sx); + y2 = dx * transform->e21 + dy * transform->e22 + transform->e23 + (cy * sy); } fill->linear.dx = x2 - x1; @@ -116,7 +118,7 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr fill->linear.dx /= fill->linear.len; fill->linear.dy /= fill->linear.len; - fill->linear.offset = -fill->linear.dx * x1 - fill->linear.dy * y1; + fill->linear.offset = -fill->linear.dx * x1 -fill->linear.dy * y1; return true; } @@ -158,20 +160,23 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr } -static inline uint32_t _clamp(const SwFill* fill, uint32_t pos) +static inline uint32_t _clamp(const SwFill* fill, int32_t pos) { switch (fill->spread) { case FillSpread::Pad: { if (pos >= GRADIENT_STOP_SIZE) pos = GRADIENT_STOP_SIZE - 1; + else if (pos < 0) pos = 0; break; } case FillSpread::Repeat: { + if (pos < 0) pos = GRADIENT_STOP_SIZE + pos; pos = pos % GRADIENT_STOP_SIZE; break; } case FillSpread::Reflect: { auto limit = GRADIENT_STOP_SIZE * 2; pos = pos % limit; + if (pos < 0) pos = limit + pos; if (pos >= GRADIENT_STOP_SIZE) pos = (limit - pos - 1); break; } @@ -180,16 +185,16 @@ static inline uint32_t _clamp(const SwFill* fill, uint32_t pos) } -static inline uint32_t _fixedPixel(const SwFill* fill, uint32_t pos) +static inline uint32_t _fixedPixel(const SwFill* fill, int32_t pos) { - auto i = (pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; + int32_t i = (pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; return fill->ctable[_clamp(fill, i)]; } static inline uint32_t _pixel(const SwFill* fill, float pos) { - auto i = static_cast(pos * (GRADIENT_STOP_SIZE - 1) + 0.5f); + auto i = static_cast(pos * (GRADIENT_STOP_SIZE - 1) + 0.5f); return fill->ctable[_clamp(fill, i)]; } @@ -226,13 +231,13 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fill->linear.len < FLT_EPSILON) return; //Rotation - auto rx = x + 0.5f; - auto ry = y + 0.5f; - auto t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); - auto inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1); + float rx = x + 0.5f; + float ry = y + 0.5f; + float t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); + float inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1); if (fabsf(inc) < FLT_EPSILON) { - auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); + auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); rasterARGB32(dst, color, offset, len); return; } -- 2.7.4 From 87a6b5219f4c61ce747f71a76845b0d641917299 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Mon, 27 Jul 2020 14:07:03 +0200 Subject: [PATCH 09/16] capi: Added wrapper for tvg::Shape::scale Change-Id: Ie8380478d9e5bf99c924f3b93cfbb3d80ff55611 --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 7c92184..d7f98ec 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -140,6 +140,7 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_dash(Tvg_Paint* paint, const float* d TVG_EXPORT Tvg_Result tvg_shape_set_stroke_cap(Tvg_Paint* paint, Tvg_Stroke_Cap cap); TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Join join); TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); +TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 6ba0e6d..2e4e866 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -226,6 +226,11 @@ TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t return (Tvg_Result) reinterpret_cast(paint)->fill(r, g, b, a); } +TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor) +{ + return (Tvg_Result) reinterpret_cast(paint)->scale(factor); +} + #ifdef __cplusplus } #endif \ No newline at end of file -- 2.7.4 From 52ece17fc37f69535f8b0b278fc36e80868b5166 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Mon, 27 Jul 2020 14:08:01 +0200 Subject: [PATCH 10/16] capi: Added wrapper for tvg::Shape::rotate Change-Id: I2cef6600586c037caaf8d2f45fc6d78e93dce925 --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index d7f98ec..9d32483 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -141,6 +141,7 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_cap(Tvg_Paint* paint, Tvg_Stroke_Cap TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Join join); TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); +TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 2e4e866..bd83ccd 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -231,6 +231,11 @@ TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor) return (Tvg_Result) reinterpret_cast(paint)->scale(factor); } +TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree) +{ + return (Tvg_Result) reinterpret_cast(paint)->rotate(degree); +} + #ifdef __cplusplus } #endif \ No newline at end of file -- 2.7.4 From ba17287419a739a3d2f0fb86d5af7ecb323d727e Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Mon, 27 Jul 2020 14:08:51 +0200 Subject: [PATCH 11/16] capi: Added wrapper for tvg::Shape::translate Change-Id: Idcf672926c489148f15c654f85b4d6c3ff8cde80 --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 9d32483..efb135b 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -142,6 +142,7 @@ TVG_EXPORT Tvg_Result tvg_shape_set_stroke_join(Tvg_Paint* paint, Tvg_Stroke_Joi TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t g, uint8_t b, uint8_t a); TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); +TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index bd83ccd..5c6fd59 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -236,6 +236,11 @@ TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree) return (Tvg_Result) reinterpret_cast(paint)->rotate(degree); } +TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y) +{ + return (Tvg_Result) reinterpret_cast(paint)->translate(x, y); +} + #ifdef __cplusplus } #endif \ No newline at end of file -- 2.7.4 From 621d60712684d7f82e9776ff1af07cc566fcf965 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 28 Jul 2020 20:46:11 +0900 Subject: [PATCH 12/16] updated AUTHORS Change-Id: Ia3b91f2dff139b80c5e968be2a0ecb725e6b62bd --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 348597a..1299d6b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,3 +2,4 @@ Hermet Park Prudhvi Raj Vasireddi Junsu Choi Pranay Samanta +Mateusz Palkowski -- 2.7.4 From d2d4a2a3e7f959531f69516fb3828b7df7fc84f9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 28 Jul 2020 20:57:18 +0900 Subject: [PATCH 13/16] gl_engine: updated file permission. please keep 664 for files. Change-Id: Iaddd87b0d35a74bc8c6cbf330fecbd28e14ad57a --- src/lib/gl_engine/tvgGlGeometry.cpp | 0 src/lib/gl_engine/tvgGlRenderer.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/lib/gl_engine/tvgGlGeometry.cpp mode change 100755 => 100644 src/lib/gl_engine/tvgGlRenderer.cpp diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp old mode 100755 new mode 100644 diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100755 new mode 100644 -- 2.7.4 From 8a924cbd78a1e019e9af48e4d021963c0942c8d1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 29 Jul 2020 13:40:11 +0900 Subject: [PATCH 14/16] sw_engine: fix out of cell memory. we can adjust cell size if the cell memory is out. the main rle logic missed the exception handling. Change-Id: I4419eefefccafd788729111eafeb65aa4e6a20e9 --- src/lib/sw_engine/tvgSwRle.cpp | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRle.cpp b/src/lib/sw_engine/tvgSwRle.cpp index 6ee6f7c..d88a837 100644 --- a/src/lib/sw_engine/tvgSwRle.cpp +++ b/src/lib/sw_engine/tvgSwRle.cpp @@ -625,17 +625,15 @@ invalid_outline: } -static bool _genRle(RleWorker& rw) +static int _genRle(RleWorker& rw) { - bool ret = false; - if (setjmp(rw.jmpBuf) == 0) { - ret = _decomposeOutline(rw); + auto ret = _decomposeOutline(rw); if (!rw.invalid) _recordCell(rw); - } else { - cout << "Lack of Cell Memory" << endl; + if (ret) return 0; //success + else return 1; //fail } - return ret; + return -1; //lack of cell memory } @@ -646,14 +644,9 @@ static bool _genRle(RleWorker& rw) 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; + constexpr auto RENDER_POOL_SIZE = 16384L; constexpr auto BAND_SIZE = 40; - assert(outline); - assert(outline->cntrs && outline->pts); - assert(outline->ptsCnt == outline->cntrs[outline->cntrsCnt - 1] + 1); - //TODO: We can preserve several static workers in advance RleWorker rw; Cell buffer[RENDER_POOL_SIZE / sizeof(Cell)]; @@ -693,6 +686,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& auto min = rw.cellMin.y; auto yMax = rw.cellMax.y; SwCoord max; + int ret; for (int n = 0; n < bandCnt; ++n, min = max) { max = min + rw.bandSize; @@ -706,8 +700,8 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.yCells = static_cast(rw.buffer); rw.yCnt = band->max - band->min; - auto cellStart = sizeof(Cell*) * (int)rw.yCnt; - auto cellMod = cellStart % sizeof(Cell); + int cellStart = sizeof(Cell*) * (int)rw.yCnt; + int cellMod = cellStart % sizeof(Cell); if (cellMod > 0) cellStart += sizeof(Cell) - cellMod; @@ -722,7 +716,7 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.maxCells = cellsMax - rw.cells; if (rw.maxCells < 2) goto reduce_bands; - for (auto y = 0; y < rw.yCnt; ++y) + for (int y = 0; y < rw.yCnt; ++y) rw.yCells[y] = nullptr; rw.cellsCnt = 0; @@ -731,11 +725,14 @@ SwRleData* rleRender(const SwOutline* outline, const SwBBox& bbox, const SwSize& rw.cellMax.y = band->max; rw.cellYCnt = band->max - band->min; - if (!_genRle(rw)) goto error; - - _sweep(rw); - --band; - continue; + ret = _genRle(rw); + if (ret == 0) { + _sweep(rw); + --band; + continue; + } else if (ret == 1) { + goto error; + } reduce_bands: /* render pool overflow: we will reduce the render band by half */ -- 2.7.4 From 9e0c4666af8e7411595136853fb30d9a65e3ab7a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 29 Jul 2020 14:25:18 +0900 Subject: [PATCH 15/16] common: revise transform interfaces. transform interfaces are getting duplicated in derived classes. we moved to the super for smaller apis count. Applied strategy pattern to hide the inheritance. Change-Id: I7b0c3ff9317e9bf3c97bb0c849bf55e79ee9a591 --- inc/thorvg.h | 23 ++++++--------- src/lib/meson.build | 1 + src/lib/tvgCommon.h | 1 + src/lib/tvgPaint.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgPaint.h | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgScene.cpp | 57 ++----------------------------------- src/lib/tvgSceneImpl.h | 6 ++++ src/lib/tvgShape.cpp | 58 ++----------------------------------- src/lib/tvgShapeImpl.h | 6 ++++ 9 files changed, 177 insertions(+), 126 deletions(-) create mode 100644 src/lib/tvgPaint.cpp create mode 100644 src/lib/tvgPaint.h diff --git a/inc/thorvg.h b/inc/thorvg.h index bdca5a2..c8dafaf 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -97,9 +97,16 @@ struct Matrix class TVG_EXPORT Paint { public: - virtual ~Paint() {} + virtual ~Paint(); + + Result rotate(float degree) noexcept; + Result scale(float factor) noexcept; + Result translate(float x, float y) noexcept; + Result transform(const Matrix& m) noexcept; + Result bounds(float* x, float* y, float* w, float* h) const noexcept; _TVG_DECALRE_IDENTIFIER(); + _TVG_DECLARE_PRIVATE(Paint); }; @@ -243,18 +250,11 @@ public: 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; - Result scale(float factor) noexcept; - Result translate(float x, float y) noexcept; - Result transform(const Matrix& m) noexcept; - //Getters 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; float strokeWidth() const noexcept; Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) const noexcept; @@ -287,13 +287,6 @@ public: Result reserve(uint32_t size) noexcept; Result load(const std::string& path) noexcept; - Result rotate(float degree) noexcept; - Result scale(float factor) noexcept; - Result translate(float x, float y) noexcept; - Result transform(const Matrix& m) noexcept; - - Result bounds(float* x, float* y, float* w, float* h) const noexcept; - static std::unique_ptr gen() noexcept; _TVG_DECLARE_ACCESSOR(Canvas); diff --git a/src/lib/meson.build b/src/lib/meson.build index ad02261..64cedbd 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -27,6 +27,7 @@ source_file = [ 'tvgInitializer.cpp', 'tvgLinearGradient.cpp', 'tvgLoaderMgr.cpp', + 'tvgPaint.cpp', 'tvgRadialGradient.cpp', 'tvgRender.cpp', 'tvgScene.cpp', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index ac91f49..3c390b1 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -43,6 +43,7 @@ using namespace tvg; #include "tvgLoader.h" #include "tvgLoaderMgr.h" #include "tvgRender.h" +#include "tvgPaint.h" #include "tvgShapePath.h" #include "tvgShapeImpl.h" #include "tvgSceneImpl.h" diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp new file mode 100644 index 0000000..7eeca19 --- /dev/null +++ b/src/lib/tvgPaint.cpp @@ -0,0 +1,74 @@ +/* + * 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_PAINT_CPP_ +#define _TVG_PAINT_CPP_ + +#include "tvgCommon.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +Paint :: Paint() : pImpl(make_unique()) +{ +} + + +Paint :: ~Paint() +{ +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +Result Paint::rotate(float degree) noexcept +{ + if (pImpl.get()->ts->rotate(degree)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::scale(float factor) noexcept +{ + if (pImpl.get()->ts->scale(factor)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::translate(float x, float y) noexcept +{ + if (pImpl.get()->ts->translate(x, y)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::transform(const Matrix& m) noexcept +{ + if (pImpl.get()->ts->transform(m)) return Result::Success; + return Result::FailedAllocation; +} + + +Result Paint::bounds(float* x, float* y, float* w, float* h) const noexcept +{ + if (pImpl.get()->ts->bounds(x, y, w, h)) return Result::Success; + return Result::InsufficientCondition; +} + +#endif //_TVG_PAINT_CPP_ \ No newline at end of file diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h new file mode 100644 index 0000000..cd0933b --- /dev/null +++ b/src/lib/tvgPaint.h @@ -0,0 +1,77 @@ +/* + * 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_PAINT_H_ +#define _TVG_PAINT_H_ + +namespace tvg +{ + struct ITransformMethod + { + virtual ~ITransformMethod(){} + virtual bool rotate(float degree) = 0; + virtual bool scale(float factor) = 0; + virtual bool translate(float x, float y) = 0; + virtual bool transform(const Matrix& m) = 0; + virtual bool bounds(float* x, float* y, float* w, float* h) const = 0; + }; + + struct Paint::Impl + { + ITransformMethod* ts = nullptr; + + ~Impl() { + if (ts) delete(ts); + } + }; + + + template + struct TransformMethod : ITransformMethod + { + T* _inst = nullptr; + + TransformMethod(T* inst) : _inst(inst) {} + ~TransformMethod(){} + + bool rotate(float degree) override + { + return _inst->rotate(degree); + } + + bool scale(float factor) override + { + return _inst->scale(factor); + } + + bool translate(float x, float y) override + { + return _inst->translate(x, y); + } + + bool transform(const Matrix& m) override + { + return _inst->transform(m); + } + + bool bounds(float* x, float* y, float* w, float* h) const override + { + return _inst->bounds(x, y, w, h); + } + }; +} + +#endif //_TVG_PAINT_H_ \ No newline at end of file diff --git a/src/lib/tvgScene.cpp b/src/lib/tvgScene.cpp index 1980d96..78ca868 100644 --- a/src/lib/tvgScene.cpp +++ b/src/lib/tvgScene.cpp @@ -26,6 +26,8 @@ Scene::Scene() : pImpl(make_unique()) { _id = PAINT_ID_SCENE; + + Paint::pImpl.get()->ts = pImpl.get()->transformMethod(); } @@ -64,61 +66,6 @@ Result Scene::reserve(uint32_t size) noexcept } -Result Scene::scale(float factor) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->scale(factor)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::rotate(float degree) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->rotate(degree)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::translate(float x, float y) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->translate(x, y)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::transform(const Matrix& m) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->transform(m)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Scene::bounds(float* x, float* y, float* w, float* h) const noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - - return Result::Success; -} - - Result Scene::load(const std::string& path) noexcept { if (path.empty()) return Result::InvalidArguments; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 9972d72..08b42d3 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -231,6 +231,12 @@ struct Scene::Impl if (!loader->read()) return Result::Unknown; return Result::Success; } + + ITransformMethod* transformMethod() + { + return new TransformMethod(this); + } + }; #endif //_TVG_SCENE_IMPL_H_ \ No newline at end of file diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 36aefed..c822f94 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -25,7 +25,6 @@ /************************************************************************/ constexpr auto PATH_KAPPA = 0.552284f; - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -33,6 +32,8 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(make_unique()) { _id = PAINT_ID_SHAPE; + + Paint::pImpl.get()->ts = pImpl.get()->transformMethod(); } @@ -280,61 +281,6 @@ const Fill* Shape::fill() const noexcept } -Result Shape::scale(float factor) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->scale(factor)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::rotate(float degree) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->rotate(degree)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::translate(float x, float y) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->translate(x, y)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::transform(const Matrix& m) noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->transform(m)) return Result::FailedAllocation; - - return Result::Success; -} - - -Result Shape::bounds(float* x, float* y, float* w, float* h) const noexcept -{ - auto impl = pImpl.get(); - if (!impl) return Result::MemoryCorruption; - - if (!impl->bounds(x, y, w, h)) return Result::InsufficientCondition; - - return Result::Success; -} - - Result Shape::stroke(float width) noexcept { auto impl = pImpl.get(); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 54d37a3..c38916a 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -235,6 +235,12 @@ struct Shape::Impl return true; } + + + ITransformMethod* transformMethod() + { + return new TransformMethod(this); + } }; #endif //_TVG_SHAPE_IMPL_H_ \ No newline at end of file -- 2.7.4 From cd699738b60a2d128e0f1c4fceeab3ef9aadb009 Mon Sep 17 00:00:00 2001 From: Mateusz Palkowski Date: Wed, 29 Jul 2020 12:23:18 +0200 Subject: [PATCH 16/16] capi: Added wrapper for tvg::Shape::transform (fixed) Change-Id: Ibbb867e828a07af90f38ed506894d026004fa53d --- inc/thorvg_capi.h | 1 + src/bindings/capi/tvgCapi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index efb135b..96724dc 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -143,6 +143,7 @@ TVG_EXPORT Tvg_Result tvg_shape_fill_color(Tvg_Paint* paint, uint8_t r, uint8_t TVG_EXPORT Tvg_Result tvg_shape_scale(Tvg_Paint* paint, float factor); TVG_EXPORT Tvg_Result tvg_shape_rotate(Tvg_Paint* paint, float degree); TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y); +TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m); #ifdef __cplusplus } diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 5c6fd59..1972bd0 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -241,6 +241,11 @@ TVG_EXPORT Tvg_Result tvg_shape_translate(Tvg_Paint* paint, float x, float y) return (Tvg_Result) reinterpret_cast(paint)->translate(x, y); } +TVG_EXPORT Tvg_Result tvg_shape_transform(Tvg_Paint* paint, const Tvg_Matrix* m) +{ + return (Tvg_Result) reinterpret_cast(paint)->transform(*(reinterpret_cast(m))); +} + #ifdef __cplusplus } #endif \ No newline at end of file -- 2.7.4