tvg_format: fix broken clippath region.
authorHermet Park <chuneon.park@samsung.com>
Sat, 28 Aug 2021 12:55:51 +0000 (21:55 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Mon, 30 Aug 2021 00:44:59 +0000 (09:44 +0900)
there some multiple wrong calculation about size during tvg optimiation.
this patch fixes them.

1. picture needs to return the current desired size because
it will save the transformed the geometry. the final size should be
recorvered as the base size from the loader.

2. clippath missed to multiply parents transform, it's fixed.

@Issue: https://github.com/Samsung/thorvg/issues/752

src/examples/images/test.tvg
src/lib/tvgPictureImpl.h
src/savers/tvg/tvgTvgSaver.cpp
src/savers/tvg/tvgTvgSaver.h

index e68e57a..9c42fae 100644 (file)
Binary files a/src/examples/images/test.tvg and b/src/examples/images/test.tvg differ
index afa3acb..5f19377 100644 (file)
@@ -171,14 +171,9 @@ struct Picture::Impl
     {
         if (x) *x = 0;
         if (y) *y = 0;
-        if (w) {
-            if (loader) *w = loader->w;
-            else *w = 0;
-        }
-        if (h) {
-            if (loader) *h = loader->h;
-            else *h = 0;
-        }
+        if (w) *w = this->w;
+        if (h) *h = this->h;
         return true;
     }
 
index 473cd44..b35850a 100644 (file)
@@ -57,10 +57,10 @@ static Matrix _multiply(const Matrix* lhs, const Matrix* rhs)
 }
 
 
-static void _multiply(Point* pt, const Matrix* transform)
+static void _multiply(Point* pt, const Matrix& transform)
 {
-    auto tx = pt->x * transform->e11 + pt->y * transform->e12 + transform->e13;
-    auto ty = pt->x * transform->e21 + pt->y * transform->e22 + transform->e23;
+    auto tx = pt->x * transform.e11 + pt->y * transform.e12 + transform.e13;
+    auto ty = pt->x * transform.e21 + pt->y * transform.e22 + transform.e23;
     pt->x = tx;
     pt->y = ty;
 }
@@ -299,20 +299,18 @@ TvgBinCounter TvgSaver::writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const
 }
 
 
-TvgBinCounter TvgSaver::writeTransform(const Matrix* transform)
+TvgBinCounter TvgSaver::writeTransform(const Matrix& transform)
 {
-    if (!transform) return 0;
-
-    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) {
-        return writeTagProperty(TVG_TAG_PAINT_TRANSFORM, SIZE(Matrix), 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) {
+        return writeTagProperty(TVG_TAG_PAINT_TRANSFORM, SIZE(Matrix), &transform);
     }
     return 0;
 }
 
 
-TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
+TvgBinCounter TvgSaver::serializePaint(const Paint* paint, const Matrix* pTransform)
 {
     TvgBinCounter cnt = 0;
 
@@ -326,7 +324,7 @@ TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
     const Paint* cmpTarget = nullptr;
     auto cmpMethod = paint->composite(&cmpTarget);
     if (cmpMethod != CompositeMethod::None && cmpTarget) {
-        cnt += serializeComposite(cmpTarget, cmpMethod);
+        cnt += serializeComposite(cmpTarget, cmpMethod, pTransform);
     }
 
     return cnt;
@@ -339,8 +337,11 @@ TvgBinCounter TvgSaver::serializeChild(const Paint* parent, const Paint* child,
     const Paint* compTarget = nullptr;
     auto compMethod = parent->composite(&compTarget);
 
-    //If the parent & the only child have composition, we can't skip the parent....
-    if (compMethod != CompositeMethod::None && child->composite(nullptr) != CompositeMethod::None) return 0;
+    /* If the parent & the only child have composition, we can't skip the parent...
+       Or if the parent has the transform and composition, we can't skip the parent... */
+    if (compMethod != CompositeMethod::None) {
+        if (transform || child->composite(nullptr) != CompositeMethod::None) return 0;
+    }
 
     //propagate opacity
     uint32_t opacity = parent->opacity();
@@ -358,14 +359,17 @@ TvgBinCounter TvgSaver::serializeChild(const Paint* parent, const Paint* child,
 }
 
 
-TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* transform)
+TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* pTransform)
 {
     auto it = this->iterator(scene);
     if (it->count() == 0) return 0;
 
+    auto transform = const_cast<Scene*>(scene)->transform();
+    if (pTransform) transform = _multiply(pTransform, &transform);
+
     //Case - Only Child: Skip saving this scene.
     if (it->count() == 1) {
-        auto cnt = serializeChild(scene, it->next(), transform);
+        auto cnt = serializeChild(scene, it->next(), &transform);
         if (cnt > 0) {
             delete(it);
             return cnt;
@@ -376,14 +380,14 @@ TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* transfo
 
     //Case - Delegator Scene: This scene is just a delegator, we can skip this:
     if (scene->composite(nullptr) == CompositeMethod::None && scene->opacity() == 255) {
-        return serializeChildren(it, transform);
+        return serializeChildren(it, &transform);
     }
 
     //Case - Serialize Scene & its children
     writeTag(TVG_TAG_CLASS_SCENE);
     reserveCount();
 
-    auto cnt = serializeChildren(it, transform) + serializePaint(scene);
+    auto cnt = serializeChildren(it, &transform) + serializePaint(scene, pTransform);
 
     delete(it);
 
@@ -472,7 +476,7 @@ TvgBinCounter TvgSaver::serializeStroke(const Shape* shape)
 }
 
 
-TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* transform)
+TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* pTransform)
 {
     const PathCommand* cmds = nullptr;
     auto cmdCnt = shape->pathCommands(&cmds);
@@ -496,9 +500,12 @@ TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* transfor
     cnt += writeData(outCmds, SIZE(outCmds));
 
     //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 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);
     }
@@ -511,7 +518,7 @@ TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* transfor
 }
 
 
-TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* transform)
+TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* pTransform)
 {
     writeTag(TVG_TAG_CLASS_SHAPE);
     reserveCount();
@@ -538,8 +545,8 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* transfo
         if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
     }
 
-    cnt += serializePath(shape, transform);
-    cnt += serializePaint(shape);
+    cnt += serializePath(shape, pTransform);
+    cnt += serializePaint(shape, pTransform);
 
     writeReservedCount(cnt);
 
@@ -548,14 +555,31 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* transfo
 
 
 /* Picture has either a vector scene or a bitmap. */
-TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* transform)
+TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* pTransform)
 {
-    //Case - Vector Scene: Only child, Skip to save Picture...
+    //transform
+    auto transform = const_cast<Picture*>(picture)->transform();
+    if (pTransform) transform = _multiply(pTransform, &transform);
+
     auto it = this->iterator(picture);
+
+    //Case - Vector Scene:
     if (it->count() == 1) {
-        auto cnt = serializeChild(picture, it->next(), transform);
+        auto cnt = serializeChild(picture, it->next(), &transform);
+        //Only child, Skip to save Picture...
+        if (cnt > 0) {
+            delete(it);
+            return cnt;
+        /* Unfortunately, we can't skip the Picture because it might have a compositor,
+           Serialize Scene(instead of the Picture) & its scene. */
+        } else {
+            writeTag(TVG_TAG_CLASS_SCENE);
+            reserveCount();
+            auto cnt = serializeChildren(it, &transform) + serializePaint(picture, pTransform);
+            writeReservedCount(cnt);
+        }
         delete(it);
-        return cnt;
+        return SERIAL_DONE(cnt);
     }
     delete(it);
 
@@ -582,7 +606,7 @@ TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* t
     //Bitmap picture needs the transform info.
     cnt += writeTransform(transform);
 
-    cnt += serializePaint(picture);
+    cnt += serializePaint(picture, pTransform);
 
     writeReservedCount(cnt);
 
@@ -590,7 +614,7 @@ TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* t
 }
 
 
-TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod)
+TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform)
 {
     writeTag(TVG_TAG_PAINT_CMP_TARGET);
     reserveCount();
@@ -598,7 +622,7 @@ TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMeth
     auto flag = static_cast<TvgBinFlag>(cmpMethod);
     auto cnt = writeTagProperty(TVG_TAG_PAINT_CMP_METHOD, SIZE(TvgBinFlag), &flag);
 
-    cnt += serialize(cmpTarget, nullptr, true);
+    cnt += serialize(cmpTarget, pTransform, true);
 
     writeReservedCount(cnt);
 
@@ -606,7 +630,7 @@ TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMeth
 }
 
 
-TvgBinCounter TvgSaver::serializeChildren(Iterator* it, const Matrix* transform)
+TvgBinCounter TvgSaver::serializeChildren(Iterator* it, const Matrix* pTransform)
 {
     TvgBinCounter cnt = 0;
 
@@ -631,27 +655,24 @@ TvgBinCounter TvgSaver::serializeChildren(Iterator* it, const Matrix* transform)
     //Serialize merged children.
     auto child = children.data;
     for (uint32_t i = 0; i < children.count; ++i, ++child) {
-        cnt += serialize(*child, transform);
+        cnt += serialize(*child, pTransform);
     }
 
     return cnt;
 }
 
 
-TvgBinCounter TvgSaver::serialize(const Paint* paint, const Matrix* transform, bool compTarget)
+TvgBinCounter TvgSaver::serialize(const Paint* paint, const Matrix* pTransform, bool compTarget)
 {
     if (!paint) return 0;
 
     //Invisible paint, no point to save it if the paint is not the composition target...
     if (!compTarget && paint->opacity() == 0) return 0;
 
-    auto m = const_cast<Paint*>(paint)->transform();
-    if (transform) m = _multiply(transform, &m);
-
     switch (paint->id()) {
-        case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast<const Shape*>(paint), &m);
-        case TVG_CLASS_ID_SCENE: return serializeScene(static_cast<const Scene*>(paint), &m);
-        case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast<const Picture*>(paint), &m);
+        case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast<const Shape*>(paint), pTransform);
+        case TVG_CLASS_ID_SCENE: return serializeScene(static_cast<const Scene*>(paint), pTransform);
+        case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast<const Picture*>(paint), pTransform);
     }
 
     return 0;
index 4d70e88..c8cb989 100644 (file)
@@ -50,19 +50,19 @@ private:
     void writeReservedCount(TvgBinCounter cnt);
     TvgBinCounter writeData(const void* data, TvgBinCounter cnt);
     TvgBinCounter writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const void* data);
-    TvgBinCounter writeTransform(const Matrix* transform);
+    TvgBinCounter writeTransform(const Matrix& transform);
 
-    TvgBinCounter serialize(const Paint* paint, const Matrix* transform, bool compTarget = false);
-    TvgBinCounter serializeScene(const Scene* scene, const Matrix* transform);
-    TvgBinCounter serializeShape(const Shape* shape, const Matrix* transform);
-    TvgBinCounter serializePicture(const Picture* picture, const Matrix* transform);
-    TvgBinCounter serializePaint(const Paint* paint);
+    TvgBinCounter serialize(const Paint* paint, const Matrix* pTransform, bool compTarget = false);
+    TvgBinCounter serializeScene(const Scene* scene, const Matrix* pTransform);
+    TvgBinCounter serializeShape(const Shape* shape, const Matrix* pTransform);
+    TvgBinCounter serializePicture(const Picture* picture, const Matrix* pTransform);
+    TvgBinCounter serializePaint(const Paint* paint, const Matrix* pTransform);
     TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag);
     TvgBinCounter serializeStroke(const Shape* shape);
-    TvgBinCounter serializePath(const Shape* shape, const Matrix* transform);
-    TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod);
+    TvgBinCounter serializePath(const Shape* shape, const Matrix* pTransform);
+    TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform);
     TvgBinCounter serializeChildren(Iterator* it, const Matrix* transform);
-    TvgBinCounter serializeChild(const Paint* parent, const Paint* child, const Matrix* transform);
+    TvgBinCounter serializeChild(const Paint* parent, const Paint* child, const Matrix* pTransform);
 
 public:
     ~TvgSaver();