tvg_saver/tvg_loader: gradient fill in the tvg format

Introducing the gradient transform() apis and changing the grad
algorithms made it possible to apply the shape's transformation
before saving the tvg file, in case the shape (or its stroke)
has a fill.
This commit is contained in:
Mira Grudzinska 2021-10-26 02:07:24 +02:00 committed by Hermet Park
parent 3b54e4797e
commit 6b132d77e8
4 changed files with 31 additions and 20 deletions

View file

@ -87,6 +87,7 @@ using TvgBinFlag = TvgBinByte;
#define TVG_TAG_FILL_RADIAL_GRADIENT (TvgBinTag)0x61
#define TVG_TAG_FILL_COLORSTOPS (TvgBinTag)0x62
#define TVG_TAG_FILL_FILLSPREAD (TvgBinTag)0x63
#define TVG_TAG_FILL_TRANSFORM (TvgBinTag)0x64
//Picture

View file

@ -225,6 +225,13 @@ static unique_ptr<Fill> _parseShapeFill(const char *ptr, const char *end)
fillGrad->colorStops(stops, stopsCnt);
break;
}
case TVG_TAG_FILL_TRANSFORM: {
if (!fillGrad || block.length != SIZE(Matrix)) return nullptr;
Matrix gradTransform;
memcpy(&gradTransform, block.data, SIZE(Matrix));
fillGrad->transform(gradTransform);
break;
}
default: {
TVGLOG("TVG", "Unsupported tag %d (0x%x) used as one of the fill properties, %d bytes skipped", block.type, block.type, block.length);
break;

View file

@ -323,12 +323,12 @@ TvgBinCounter TvgSaver::writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const
}
TvgBinCounter TvgSaver::writeTransform(const Matrix* transform)
TvgBinCounter TvgSaver::writeTransform(const Matrix* transform, TvgBinTag tag)
{
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 writeTagProperty(tag, SIZE(Matrix), transform);
}
return 0;
}
@ -423,7 +423,7 @@ TvgBinCounter TvgSaver::serializeScene(const Scene* scene, const Matrix* pTransf
}
TvgBinCounter TvgSaver::serializeFill(const Fill* fill, TvgBinTag tag)
TvgBinCounter TvgSaver::serializeFill(const Fill* fill, TvgBinTag tag, const Matrix* pTransform)
{
const Fill::ColorStop* stops = nullptr;
auto stopsCnt = fill->colorStops(&stops);
@ -450,6 +450,10 @@ TvgBinCounter TvgSaver::serializeFill(const Fill* fill, TvgBinTag tag)
cnt += writeTagProperty(TVG_TAG_FILL_FILLSPREAD, SIZE(TvgBinFlag), &flag);
cnt += writeTagProperty(TVG_TAG_FILL_COLORSTOPS, stopsCnt * SIZE(Fill::ColorStop), stops);
auto gTransform = fill->transform();
if (pTransform) gTransform = _multiply(pTransform, &gTransform);
cnt += writeTransform(&gTransform, TVG_TAG_FILL_TRANSFORM);
writeReservedCount(cnt);
return SERIAL_DONE(cnt);
@ -476,7 +480,7 @@ TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTrans
//fill
if (auto fill = shape->strokeFill()) {
cnt += serializeFill(fill, TVG_TAG_SHAPE_STROKE_FILL);
cnt += serializeFill(fill, TVG_TAG_SHAPE_STROKE_FILL, (preTransform ? pTransform : nullptr));
} else {
uint8_t color[4] = {0, 0, 0, 0};
shape->strokeColor(color, color + 1, color + 2, color + 3);
@ -555,33 +559,32 @@ TvgBinCounter TvgSaver::serializeShape(const Shape* shape, const Matrix* pTransf
cnt = writeTagProperty(TVG_TAG_SHAPE_FILLRULE, SIZE(TvgBinFlag), &flag);
}
//the pre-transformation can't be applied in the case where any fill is present or when the stroke is dashed or irregulary scaled
//the pre-transformation can't be applied in the case when the stroke is dashed or irregulary scaled
bool preTransform = true;
//fill
if (auto fill = shape->fill()) {
preTransform = false;
cnt += serializeFill(fill, TVG_TAG_SHAPE_FILL);
} else {
uint8_t color[4] = {0, 0, 0, 0};
shape->fillColor(color, color + 1, color + 2, color + 3);
if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
}
//stroke
if (shape->strokeWidth() > 0) {
uint8_t color[4] = {0, 0, 0, 0};
shape->strokeColor(color, color + 1, color + 2, color + 3);
auto fill = shape->strokeFill();
if (fill || color[3] > 0) {
if (fill || fabsf(cTransform->e11 - cTransform->e22) > FLT_EPSILON || (fabsf(cTransform->e11) < FLT_EPSILON && fabsf(cTransform->e12 - cTransform->e21) > FLT_EPSILON) || shape->strokeDash(nullptr) > 0) preTransform = false;
if (fabsf(cTransform->e11 - cTransform->e22) > FLT_EPSILON || (fabsf(cTransform->e11) < FLT_EPSILON && fabsf(cTransform->e12 - cTransform->e21) > FLT_EPSILON) || shape->strokeDash(nullptr) > 0) preTransform = false;
cnt += serializeStroke(shape, cTransform, preTransform);
}
}
//fill
if (auto fill = shape->fill()) {
cnt += serializeFill(fill, TVG_TAG_SHAPE_FILL, (preTransform ? cTransform : nullptr));
} else {
uint8_t color[4] = {0, 0, 0, 0};
shape->fillColor(color, color + 1, color + 2, color + 3);
if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
}
cnt += serializePath(shape, cTransform, preTransform);
if (!preTransform) cnt += writeTransform(cTransform);
if (!preTransform) cnt += writeTransform(cTransform, TVG_TAG_PAINT_TRANSFORM);
cnt += serializePaint(shape, pTransform);
writeReservedCount(cnt);
@ -636,7 +639,7 @@ TvgBinCounter TvgSaver::serializePicture(const Picture* picture, const Matrix* p
cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
//Bitmap picture needs the transform info.
cnt += writeTransform(cTransform);
cnt += writeTransform(cTransform, TVG_TAG_PAINT_TRANSFORM);
cnt += serializePaint(picture, pTransform);

View file

@ -50,14 +50,14 @@ 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, TvgBinTag tag);
TvgBinCounter serialize(const Paint* paint, const Matrix* pTransform, bool compTarget = false);
TvgBinCounter serializeScene(const Scene* scene, const Matrix* pTransform, const Matrix* cTransform);
TvgBinCounter serializeShape(const Shape* shape, const Matrix* pTransform, const Matrix* cTransform);
TvgBinCounter serializePicture(const Picture* picture, const Matrix* pTransform, const Matrix* cTransform);
TvgBinCounter serializePaint(const Paint* paint, const Matrix* pTransform);
TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag);
TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag, const Matrix* pTransform);
TvgBinCounter serializeStroke(const Shape* shape, const Matrix* pTransform, bool preTransform);
TvgBinCounter serializePath(const Shape* shape, const Matrix* transform, bool preTransform);
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod, const Matrix* pTransform);