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.
This commit is contained in:
Hermet Park 2021-08-10 11:54:24 +09:00 committed by Hermet Park
parent 2337ea2b01
commit abebdbe545
6 changed files with 93 additions and 31 deletions

Binary file not shown.

View file

@ -32,6 +32,7 @@ namespace tvg
virtual ~Iterator() {} virtual ~Iterator() {}
virtual const Paint* next() = 0; virtual const Paint* next() = 0;
virtual uint32_t count() = 0; virtual uint32_t count() = 0;
virtual void begin() = 0;
}; };
struct StrategyMethod struct StrategyMethod

View file

@ -33,14 +33,15 @@
struct PictureIterator : Iterator struct PictureIterator : Iterator
{ {
Paint* paint = nullptr; Paint* paint = nullptr;
Paint* ptr = nullptr;
PictureIterator(Paint* p) : paint(p) {} PictureIterator(Paint* p) : paint(p) {}
const Paint* next() override const Paint* next() override
{ {
auto ret = paint; if (!ptr) ptr = paint;
paint = nullptr; else ptr = nullptr;
return ret; return ptr;
} }
uint32_t count() override uint32_t count() override
@ -48,6 +49,11 @@ struct PictureIterator : Iterator
if (paint) return 1; if (paint) return 1;
else return 0; else return 0;
} }
void begin() override
{
ptr = nullptr;
}
}; };

View file

@ -48,6 +48,11 @@ struct SceneIterator : Iterator
{ {
return paints->count; return paints->count;
} }
void begin() override
{
idx = 0;
}
}; };
struct Scene::Impl struct Scene::Impl

View file

@ -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<Paint*>(child)->opacity(tmp);
}
//propagate composition
if (compTarget) const_cast<Paint*>(child)->composite(unique_ptr<Paint>(compTarget->duplicate()), compMethod);
return serialize(child, transform);
}
TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* 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); writeTag(TVG_TAG_CLASS_SCENE);
reserveCount(); reserveCount();
auto cnt = serializeChildren(scene, transform) + serializePaint(scene); auto cnt = serializeChildren(it, transform) + serializePaint(scene);
delete(it);
writeReservedCount(cnt); 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) 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); writeTag(TVG_TAG_CLASS_PICTURE);
reserveCount(); reserveCount();
TvgBinCounter cnt = 0; TvgBinCounter cnt = 0;
TvgBinCounter sizeCnt = SIZE(w);
TvgBinCounter imgSize = w * h * SIZE(pixels[0]);
//Bitmap Image writeTag(TVG_TAG_PICTURE_RAW_IMAGE);
uint32_t w, h; writeCount(2 * sizeCnt + imgSize);
if (auto pixels = picture->data(&w, &h)) { cnt += writeData(&w, sizeCnt);
TvgBinCounter sizeCnt = SIZE(w); cnt += writeData(&h, sizeCnt);
TvgBinCounter imgSize = w * h * SIZE(pixels[0]); cnt += writeData(pixels, imgSize);
cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
writeTag(TVG_TAG_PICTURE_RAW_IMAGE); //Bitmap picture needs the transform info.
writeCount(2 * sizeCnt + imgSize); cnt += writeTransform(transform);
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);
}
cnt += serializePaint(picture); 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; TvgBinCounter cnt = 0;
while (auto p = it->next()) while (auto p = it->next()) {
cnt += serialize(p, transform); cnt += serialize(p, transform);
}
delete(it);
return cnt; return cnt;
} }

View file

@ -58,7 +58,8 @@ private:
TvgBinCounter serializeStroke(const Shape* shape); TvgBinCounter serializeStroke(const Shape* shape);
TvgBinCounter serializePath(const Shape* shape, const Matrix* transform); TvgBinCounter serializePath(const Shape* shape, const Matrix* transform);
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod); 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: public:
~TvgSaver(); ~TvgSaver();