From f1d9f691ccc64bbc74b59ca9c7fc3ebf095c8ccb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 7 Sep 2021 14:34:04 +0900 Subject: [PATCH] tvg_saver: fix the incorrect stroke transformation Saver tries to pre-transfom to skip the matrix data, but it missed the case - transformed stroking, we skip it also only when xy scaling factors are same excluding the dash properties, because scaled of the stroking is depent on the engines, we have no idea of the proper input data in advance. @Issues: https://github.com/Samsung/thorvg/issues/773 --- src/savers/tvg/tvgTvgSaver.cpp | 32 ++++++++++++++++++++------------ src/savers/tvg/tvgTvgSaver.h | 4 ++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/savers/tvg/tvgTvgSaver.cpp b/src/savers/tvg/tvgTvgSaver.cpp index 26a2e9d2..21d3f12a 100644 --- a/src/savers/tvg/tvgTvgSaver.cpp +++ b/src/savers/tvg/tvgTvgSaver.cpp @@ -444,13 +444,14 @@ TvgBinCounter TvgSaver::serializeFill(const Fill* fill, TvgBinTag tag, const Mat } -TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTransform) +TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTransform, bool preTransform) { writeTag(TVG_TAG_SHAPE_STROKE); reserveCount(); //width auto width = shape->strokeWidth(); + if (preTransform) width *= pTransform->e11; //we know x/y scaling factors are same. auto cnt = writeTagProperty(TVG_TAG_SHAPE_STROKE_WIDTH, SIZE(width), &width); //cap @@ -490,7 +491,7 @@ TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTrans } -TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* pTransform) +TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix& transform, bool preTransform) { const PathCommand* cmds = nullptr; auto cmdCnt = shape->pathCommands(&cmds); @@ -514,14 +515,13 @@ TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* pTransfo cnt += writeData(outCmds, SIZE(outCmds)); //transform? - auto transform = const_cast(shape)->transform(); - if (pTransform) transform = _multiply(pTransform, &transform); - - if (fabs(transform.e11 - 1) > FLT_EPSILON || fabs(transform.e12) > FLT_EPSILON || fabs(transform.e13) > FLT_EPSILON || - fabs(transform.e21) > FLT_EPSILON || fabs(transform.e22 - 1) > FLT_EPSILON || fabs(transform.e23) > FLT_EPSILON || - fabs(transform.e31) > FLT_EPSILON || fabs(transform.e32) > FLT_EPSILON || fabs(transform.e33 - 1) > FLT_EPSILON) { - auto p = const_cast(pts); - for (uint32_t i = 0; i < ptsCnt; ++i) _multiply(p++, transform); + if (preTransform) { + if (fabs(transform.e11 - 1) > FLT_EPSILON || fabs(transform.e12) > FLT_EPSILON || fabs(transform.e13) > FLT_EPSILON || + fabs(transform.e21) > FLT_EPSILON || fabs(transform.e22 - 1) > FLT_EPSILON || fabs(transform.e23) > FLT_EPSILON || + fabs(transform.e31) > FLT_EPSILON || fabs(transform.e32) > FLT_EPSILON || fabs(transform.e33 - 1) > FLT_EPSILON) { + auto p = const_cast(pts); + for (uint32_t i = 0; i < ptsCnt; ++i) _multiply(p++, transform); + } } cnt += writeData(pts, ptsCnt * SIZE(pts[0])); @@ -545,12 +545,18 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* pTransf if (auto flag = static_cast(shape->fillRule())) cnt = writeTagProperty(TVG_TAG_SHAPE_FILLRULE, SIZE(TvgBinFlag), &flag); + + bool preTransform = true; + //stroke if (shape->strokeWidth() > 0) { + //We can't apply pre-transformation if the stroke has the irregular scaling per directions or it has dash. + if (abs(transform.e11 - transform.e22) > FLT_EPSILON || shape->strokeDash(nullptr) > 0) preTransform = false; + uint8_t color[4] = {0, 0, 0, 0}; shape->strokeColor(color, color + 1, color + 2, color + 3); auto fill = shape->strokeFill(); - if (fill || color[3] > 0) cnt += serializeStroke(shape, &transform); + if (fill || color[3] > 0) cnt += serializeStroke(shape, &transform, preTransform); } //fill @@ -562,7 +568,9 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* pTransf if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color); } - cnt += serializePath(shape, pTransform); + cnt += serializePath(shape, transform, preTransform); + + if (!preTransform) cnt += writeTransform(transform); cnt += serializePaint(shape, pTransform); writeReservedCount(cnt); diff --git a/src/savers/tvg/tvgTvgSaver.h b/src/savers/tvg/tvgTvgSaver.h index 155f3500..8839f3c6 100644 --- a/src/savers/tvg/tvgTvgSaver.h +++ b/src/savers/tvg/tvgTvgSaver.h @@ -58,8 +58,8 @@ private: TvgBinCounter serializePicture(const Picture* picture, const Matrix* pTransform); TvgBinCounter serializePaint(const Paint* paint, const Matrix* pTransform); TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag, const Matrix* pTransform); - TvgBinCounter serializeStroke(const Shape* shape, const Matrix* pTransform); - TvgBinCounter serializePath(const Shape* shape, const Matrix* pTransform); + TvgBinCounter serializeStroke(const Shape* shape, const Matrix* pTransform, bool preTransform); + TvgBinCounter serializePath(const Shape* shape, const Matrix& transform, bool preTransform); TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform); TvgBinCounter serializeChildren(Iterator* it, const Matrix* transform, bool reserved); TvgBinCounter serializeChild(const Paint* parent, const Paint* child, const Matrix* pTransform);