mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 20:14:37 +00:00
tvg_format: fix broken clippath region.
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
This commit is contained in:
parent
ed31fc215f
commit
2fcc06b553
4 changed files with 74 additions and 58 deletions
Binary file not shown.
|
@ -171,14 +171,9 @@ struct Picture::Impl
|
||||||
{
|
{
|
||||||
if (x) *x = 0;
|
if (x) *x = 0;
|
||||||
if (y) *y = 0;
|
if (y) *y = 0;
|
||||||
if (w) {
|
if (w) *w = this->w;
|
||||||
if (loader) *w = loader->w;
|
if (h) *h = this->h;
|
||||||
else *w = 0;
|
|
||||||
}
|
|
||||||
if (h) {
|
|
||||||
if (loader) *h = loader->h;
|
|
||||||
else *h = 0;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 tx = pt->x * transform.e11 + pt->y * transform.e12 + transform.e13;
|
||||||
auto ty = pt->x * transform->e21 + pt->y * transform->e22 + transform->e23;
|
auto ty = pt->x * transform.e21 + pt->y * transform.e22 + transform.e23;
|
||||||
pt->x = tx;
|
pt->x = tx;
|
||||||
pt->y = ty;
|
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 ||
|
||||||
if (fabs(transform->e11 - 1) > FLT_EPSILON || fabs(transform->e12) > FLT_EPSILON || fabs(transform->e13) > FLT_EPSILON ||
|
fabs(transform.e31) > FLT_EPSILON || fabs(transform.e32) > FLT_EPSILON || fabs(transform.e33 - 1) > FLT_EPSILON) {
|
||||||
fabs(transform->e21) > FLT_EPSILON || fabs(transform->e22 - 1) > FLT_EPSILON || fabs(transform->e23) > FLT_EPSILON ||
|
return writeTagProperty(TVG_TAG_PAINT_TRANSFORM, SIZE(Matrix), &transform);
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
|
TvgBinCounter TvgSaver::serializePaint(const Paint* paint, const Matrix* pTransform)
|
||||||
{
|
{
|
||||||
TvgBinCounter cnt = 0;
|
TvgBinCounter cnt = 0;
|
||||||
|
|
||||||
|
@ -326,7 +324,7 @@ TvgBinCounter TvgSaver::serializePaint(const Paint* paint)
|
||||||
const Paint* cmpTarget = nullptr;
|
const Paint* cmpTarget = nullptr;
|
||||||
auto cmpMethod = paint->composite(&cmpTarget);
|
auto cmpMethod = paint->composite(&cmpTarget);
|
||||||
if (cmpMethod != CompositeMethod::None && cmpTarget) {
|
if (cmpMethod != CompositeMethod::None && cmpTarget) {
|
||||||
cnt += serializeComposite(cmpTarget, cmpMethod);
|
cnt += serializeComposite(cmpTarget, cmpMethod, pTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cnt;
|
return cnt;
|
||||||
|
@ -339,8 +337,11 @@ TvgBinCounter TvgSaver::serializeChild(const Paint* parent, const Paint* child,
|
||||||
const Paint* compTarget = nullptr;
|
const Paint* compTarget = nullptr;
|
||||||
auto compMethod = parent->composite(&compTarget);
|
auto compMethod = parent->composite(&compTarget);
|
||||||
|
|
||||||
//If the parent & the only child have composition, we can't skip the parent....
|
/* 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;
|
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
|
//propagate opacity
|
||||||
uint32_t opacity = parent->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);
|
auto it = this->iterator(scene);
|
||||||
if (it->count() == 0) return 0;
|
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.
|
//Case - Only Child: Skip saving this scene.
|
||||||
if (it->count() == 1) {
|
if (it->count() == 1) {
|
||||||
auto cnt = serializeChild(scene, it->next(), transform);
|
auto cnt = serializeChild(scene, it->next(), &transform);
|
||||||
if (cnt > 0) {
|
if (cnt > 0) {
|
||||||
delete(it);
|
delete(it);
|
||||||
return cnt;
|
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:
|
//Case - Delegator Scene: This scene is just a delegator, we can skip this:
|
||||||
if (scene->composite(nullptr) == CompositeMethod::None && scene->opacity() == 255) {
|
if (scene->composite(nullptr) == CompositeMethod::None && scene->opacity() == 255) {
|
||||||
return serializeChildren(it, transform);
|
return serializeChildren(it, &transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Case - Serialize Scene & its children
|
//Case - Serialize Scene & its children
|
||||||
writeTag(TVG_TAG_CLASS_SCENE);
|
writeTag(TVG_TAG_CLASS_SCENE);
|
||||||
reserveCount();
|
reserveCount();
|
||||||
|
|
||||||
auto cnt = serializeChildren(it, transform) + serializePaint(scene);
|
auto cnt = serializeChildren(it, &transform) + serializePaint(scene, pTransform);
|
||||||
|
|
||||||
delete(it);
|
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;
|
const PathCommand* cmds = nullptr;
|
||||||
auto cmdCnt = shape->pathCommands(&cmds);
|
auto cmdCnt = shape->pathCommands(&cmds);
|
||||||
|
@ -496,9 +500,12 @@ TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* transfor
|
||||||
cnt += writeData(outCmds, SIZE(outCmds));
|
cnt += writeData(outCmds, SIZE(outCmds));
|
||||||
|
|
||||||
//transform?
|
//transform?
|
||||||
if (fabs(transform->e11 - 1) > FLT_EPSILON || fabs(transform->e12) > FLT_EPSILON || fabs(transform->e13) > FLT_EPSILON ||
|
auto transform = const_cast<Shape*>(shape)->transform();
|
||||||
fabs(transform->e21) > FLT_EPSILON || fabs(transform->e22 - 1) > FLT_EPSILON || fabs(transform->e23) > FLT_EPSILON ||
|
if (pTransform) transform = _multiply(pTransform, &transform);
|
||||||
fabs(transform->e31) > FLT_EPSILON || fabs(transform->e32) > FLT_EPSILON || fabs(transform->e33 - 1) > FLT_EPSILON) {
|
|
||||||
|
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);
|
auto p = const_cast<Point*>(pts);
|
||||||
for (uint32_t i = 0; i < ptsCnt; ++i) _multiply(p++, transform);
|
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);
|
writeTag(TVG_TAG_CLASS_SHAPE);
|
||||||
reserveCount();
|
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);
|
if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt += serializePath(shape, transform);
|
cnt += serializePath(shape, pTransform);
|
||||||
cnt += serializePaint(shape);
|
cnt += serializePaint(shape, pTransform);
|
||||||
|
|
||||||
writeReservedCount(cnt);
|
writeReservedCount(cnt);
|
||||||
|
|
||||||
|
@ -548,14 +555,31 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* transfo
|
||||||
|
|
||||||
|
|
||||||
/* Picture has either a vector scene or a bitmap. */
|
/* 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);
|
auto it = this->iterator(picture);
|
||||||
|
|
||||||
|
//Case - Vector Scene:
|
||||||
if (it->count() == 1) {
|
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);
|
delete(it);
|
||||||
return cnt;
|
return SERIAL_DONE(cnt);
|
||||||
}
|
}
|
||||||
delete(it);
|
delete(it);
|
||||||
|
|
||||||
|
@ -582,7 +606,7 @@ TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* t
|
||||||
//Bitmap picture needs the transform info.
|
//Bitmap picture needs the transform info.
|
||||||
cnt += writeTransform(transform);
|
cnt += writeTransform(transform);
|
||||||
|
|
||||||
cnt += serializePaint(picture);
|
cnt += serializePaint(picture, pTransform);
|
||||||
|
|
||||||
writeReservedCount(cnt);
|
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);
|
writeTag(TVG_TAG_PAINT_CMP_TARGET);
|
||||||
reserveCount();
|
reserveCount();
|
||||||
|
@ -598,7 +622,7 @@ TvgBinCounter TvgSaver::serializeComposite(const Paint* cmpTarget, CompositeMeth
|
||||||
auto flag = static_cast<TvgBinFlag>(cmpMethod);
|
auto flag = static_cast<TvgBinFlag>(cmpMethod);
|
||||||
auto cnt = writeTagProperty(TVG_TAG_PAINT_CMP_METHOD, SIZE(TvgBinFlag), &flag);
|
auto cnt = writeTagProperty(TVG_TAG_PAINT_CMP_METHOD, SIZE(TvgBinFlag), &flag);
|
||||||
|
|
||||||
cnt += serialize(cmpTarget, nullptr, true);
|
cnt += serialize(cmpTarget, pTransform, true);
|
||||||
|
|
||||||
writeReservedCount(cnt);
|
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;
|
TvgBinCounter cnt = 0;
|
||||||
|
|
||||||
|
@ -631,27 +655,24 @@ TvgBinCounter TvgSaver::serializeChildren(Iterator* it, const Matrix* transform)
|
||||||
//Serialize merged children.
|
//Serialize merged children.
|
||||||
auto child = children.data;
|
auto child = children.data;
|
||||||
for (uint32_t i = 0; i < children.count; ++i, ++child) {
|
for (uint32_t i = 0; i < children.count; ++i, ++child) {
|
||||||
cnt += serialize(*child, transform);
|
cnt += serialize(*child, pTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cnt;
|
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;
|
if (!paint) return 0;
|
||||||
|
|
||||||
//Invisible paint, no point to save it if the paint is not the composition target...
|
//Invisible paint, no point to save it if the paint is not the composition target...
|
||||||
if (!compTarget && paint->opacity() == 0) return 0;
|
if (!compTarget && paint->opacity() == 0) return 0;
|
||||||
|
|
||||||
auto m = const_cast<Paint*>(paint)->transform();
|
|
||||||
if (transform) m = _multiply(transform, &m);
|
|
||||||
|
|
||||||
switch (paint->id()) {
|
switch (paint->id()) {
|
||||||
case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast<const Shape*>(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), &m);
|
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), &m);
|
case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast<const Picture*>(paint), pTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -50,19 +50,19 @@ private:
|
||||||
void writeReservedCount(TvgBinCounter cnt);
|
void writeReservedCount(TvgBinCounter cnt);
|
||||||
TvgBinCounter writeData(const void* data, TvgBinCounter cnt);
|
TvgBinCounter writeData(const void* data, TvgBinCounter cnt);
|
||||||
TvgBinCounter writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const void* data);
|
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 serialize(const Paint* paint, const Matrix* pTransform, bool compTarget = false);
|
||||||
TvgBinCounter serializeScene(const Scene* scene, const Matrix* transform);
|
TvgBinCounter serializeScene(const Scene* scene, const Matrix* pTransform);
|
||||||
TvgBinCounter serializeShape(const Shape* shape, const Matrix* transform);
|
TvgBinCounter serializeShape(const Shape* shape, const Matrix* pTransform);
|
||||||
TvgBinCounter serializePicture(const Picture* picture, const Matrix* transform);
|
TvgBinCounter serializePicture(const Picture* picture, const Matrix* pTransform);
|
||||||
TvgBinCounter serializePaint(const Paint* paint);
|
TvgBinCounter serializePaint(const Paint* paint, const Matrix* pTransform);
|
||||||
TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag);
|
TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag);
|
||||||
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* pTransform);
|
||||||
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod);
|
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform);
|
||||||
TvgBinCounter serializeChildren(Iterator* it, const Matrix* transform);
|
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:
|
public:
|
||||||
~TvgSaver();
|
~TvgSaver();
|
||||||
|
|
Loading…
Add table
Reference in a new issue