diff --git a/src/examples/images/test.tvg b/src/examples/images/test.tvg index e68e57ab..9c42fae9 100644 Binary files a/src/examples/images/test.tvg and b/src/examples/images/test.tvg differ diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index afa3acb2..5f19377d 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -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; } diff --git a/src/savers/tvg/tvgTvgSaver.cpp b/src/savers/tvg/tvgTvgSaver.cpp index 473cd447..b35850af 100644 --- a/src/savers/tvg/tvgTvgSaver.cpp +++ b/src/savers/tvg/tvgTvgSaver.cpp @@ -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)->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)->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); } @@ -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)->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(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)->transform(); - if (transform) m = _multiply(transform, &m); - switch (paint->id()) { - case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast(paint), &m); - case TVG_CLASS_ID_SCENE: return serializeScene(static_cast(paint), &m); - case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast(paint), &m); + case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast(paint), pTransform); + case TVG_CLASS_ID_SCENE: return serializeScene(static_cast(paint), pTransform); + case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast(paint), pTransform); } return 0; diff --git a/src/savers/tvg/tvgTvgSaver.h b/src/savers/tvg/tvgTvgSaver.h index 4d70e88d..c8cb989e 100644 --- a/src/savers/tvg/tvgTvgSaver.h +++ b/src/savers/tvg/tvgTvgSaver.h @@ -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();