From abebdbe5452a7ccbf44f289a9bc6fac5df377f5c Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 10 Aug 2021 11:54:24 +0900 Subject: [PATCH] tvg_saver: optimize saving data. This optimizes binary size by skipping the scene if it has the only child. though the reduced size is too trivial size (avg 0.4% as far as I checked our example svgs), we can reduce the loading job & runtime memory as well. --- src/examples/images/test.tvg | Bin 302026 -> 302006 bytes src/lib/tvgPaint.h | 1 + src/lib/tvgPictureImpl.h | 12 +++- src/lib/tvgSceneImpl.h | 5 ++ src/savers/tvg/tvgTvgSaver.cpp | 103 ++++++++++++++++++++++++--------- src/savers/tvg/tvgTvgSaver.h | 3 +- 6 files changed, 93 insertions(+), 31 deletions(-) diff --git a/src/examples/images/test.tvg b/src/examples/images/test.tvg index 56cc056366d57e719eac987b2d996cc37b78edf3..873daee9ea975946f322bbe6728473fb91890a64 100644 GIT binary patch delta 43 zcmV+`0M!4=w-UCu5|9}InSmOG8UckG0<{_gU#qu+s{?`o2mbEt00916w-&7fwC-_C B5zznu delta 64 zcmdnCUFg(yp$U?VYa69nr5IbKn6^qW$FJu4*Urem@NX>x1H<;p)yz$df`5Lz0Scsn Ph(r(}xSeS&^Oko23_KZR diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index b15ab177..4700413b 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -32,6 +32,7 @@ namespace tvg virtual ~Iterator() {} virtual const Paint* next() = 0; virtual uint32_t count() = 0; + virtual void begin() = 0; }; struct StrategyMethod diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 12352fd8..dbb8916f 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -33,14 +33,15 @@ struct PictureIterator : Iterator { Paint* paint = nullptr; + Paint* ptr = nullptr; PictureIterator(Paint* p) : paint(p) {} const Paint* next() override { - auto ret = paint; - paint = nullptr; - return ret; + if (!ptr) ptr = paint; + else ptr = nullptr; + return ptr; } uint32_t count() override @@ -48,6 +49,11 @@ struct PictureIterator : Iterator if (paint) return 1; else return 0; } + + void begin() override + { + ptr = nullptr; + } }; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 0a2292b1..f9354877 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -48,6 +48,11 @@ struct SceneIterator : Iterator { return paints->count; } + + void begin() override + { + idx = 0; + } }; struct Scene::Impl diff --git a/src/savers/tvg/tvgTvgSaver.cpp b/src/savers/tvg/tvgTvgSaver.cpp index 32ac23fa..db9e09fa 100644 --- a/src/savers/tvg/tvgTvgSaver.cpp +++ b/src/savers/tvg/tvgTvgSaver.cpp @@ -200,12 +200,59 @@ TvgBinCounter TvgSaver::serializePaint(const Paint* paint) } +/* Propagate parents properties to the child so that we can skip saving the parent. */ +TvgBinCounter TvgSaver::serializeChild(const Paint* parent, const Paint* child, const Matrix* transform) +{ + 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; + + //propagate opacity + uint32_t opacity = parent->opacity(); + + if (opacity < 255) { + uint32_t tmp = (child->opacity() * opacity); + if (tmp > 0) tmp /= 255; + const_cast(child)->opacity(tmp); + } + + //propagate composition + if (compTarget) const_cast(child)->composite(unique_ptr(compTarget->duplicate()), compMethod); + + return serialize(child, transform); +} + + TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* transform) { + auto it = this->iterator(scene); + if (it->count() == 0) return 0; + + //Case - Only Child: Skip saving this scene. + if (it->count() == 1) { + auto cnt = serializeChild(scene, it->next(), transform); + if (cnt > 0) { + delete(it); + return cnt; + } + } + + it->begin(); + + //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); + } + + //Case - Serialize Scene & its children writeTag(TVG_TAG_CLASS_SCENE); reserveCount(); - auto cnt = serializeChildren(scene, transform) + serializePaint(scene); + auto cnt = serializeChildren(it, transform) + serializePaint(scene); + + delete(it); writeReservedCount(cnt); @@ -367,34 +414,40 @@ 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) { + //Case - Vector Scene: Only child, Skip to save Picture... + auto it = this->iterator(picture); + if (it->count() == 1) { + auto cnt = serializeChild(picture, it->next(), transform); + delete(it); + return cnt; + } + delete(it); + + //Case - Bitmap Image: + uint32_t w, h; + auto pixels = picture->data(&w, &h); + if (!pixels) return 0; + writeTag(TVG_TAG_CLASS_PICTURE); reserveCount(); TvgBinCounter cnt = 0; + TvgBinCounter sizeCnt = SIZE(w); + TvgBinCounter imgSize = w * h * SIZE(pixels[0]); - //Bitmap Image - uint32_t w, h; + writeTag(TVG_TAG_PICTURE_RAW_IMAGE); + writeCount(2 * sizeCnt + imgSize); - if (auto pixels = picture->data(&w, &h)) { - TvgBinCounter sizeCnt = SIZE(w); - TvgBinCounter imgSize = w * h * SIZE(pixels[0]); + cnt += writeData(&w, sizeCnt); + cnt += writeData(&h, sizeCnt); + cnt += writeData(pixels, imgSize); + cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter); - writeTag(TVG_TAG_PICTURE_RAW_IMAGE); - writeCount(2 * sizeCnt + imgSize); - - cnt += writeData(&w, sizeCnt); - cnt += writeData(&h, sizeCnt); - cnt += writeData(pixels, imgSize); - cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter); - - //Only Bitmap picture needs the transform info. - cnt += writeTransform(transform); - //Vector Image - } else { - cnt += serializeChildren(picture, transform); - } + //Bitmap picture needs the transform info. + cnt += writeTransform(transform); cnt += serializePaint(picture); @@ -420,17 +473,13 @@ TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMeth } -TvgBinCounter TvgSaver::serializeChildren(const Paint* paint, const Matrix* transform) +TvgBinCounter TvgSaver::serializeChildren(Iterator* it, const Matrix* transform) { - auto it = this->iterator(paint); - if (!it) return 0; - TvgBinCounter cnt = 0; - while (auto p = it->next()) + while (auto p = it->next()) { cnt += serialize(p, transform); - - delete(it); + } return cnt; } diff --git a/src/savers/tvg/tvgTvgSaver.h b/src/savers/tvg/tvgTvgSaver.h index b2ad4fa4..90761736 100644 --- a/src/savers/tvg/tvgTvgSaver.h +++ b/src/savers/tvg/tvgTvgSaver.h @@ -58,7 +58,8 @@ private: TvgBinCounter serializeStroke(const Shape* shape); TvgBinCounter serializePath(const Shape* shape, const Matrix* transform); TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod); - TvgBinCounter serializeChildren(const Paint* paint, const Matrix* transform); + TvgBinCounter serializeChildren(Iterator* it, const Matrix* transform); + TvgBinCounter serializeChild(const Paint* parent, const Paint* child, const Matrix* transform); public: ~TvgSaver();