tvg_saver: fix the incorrect stroke transformation
authorHermet Park <chuneon.park@samsung.com>
Tue, 7 Sep 2021 05:34:04 +0000 (14:34 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Wed, 8 Sep 2021 08:11:43 +0000 (17:11 +0900)
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
src/savers/tvg/tvgTvgSaver.h

index 26a2e9d2268bcc640f3458fca9bd662ba3f9a48b..21d3f12afd69a781a8a98ff86b5158b9d830eaea 100644 (file)
@@ -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*>(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<Point*>(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<Point*>(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<TvgBinFlag>(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);
index 155f3500ea90b66240260bebf5513b19cc1fd8b8..8839f3c659bfcbb649908f9c004319ed582e05c8 100644 (file)
@@ -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);