}
-TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTransform)
+TvgBinCounter TvgSaver::serializeStroke(const Shape* shape, const Matrix* pTransform, bool preTransform)
{
writeTag(TVG_TAG_SHAPE_STROKE);
reserveCount();
//width
auto width = shape->strokeWidth();
+ if (preTransform) width *= pTransform->e11; //we know x/y scaling factors are same.
auto cnt = writeTagProperty(TVG_TAG_SHAPE_STROKE_WIDTH, SIZE(width), &width);
//cap
}
-TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix* pTransform)
+TvgBinCounter TvgSaver::serializePath(const Shape* shape, const Matrix& transform, bool preTransform)
{
const PathCommand* cmds = nullptr;
auto cmdCnt = shape->pathCommands(&cmds);
cnt += writeData(outCmds, SIZE(outCmds));
//transform?
- auto transform = const_cast<Shape*>(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<Point*>(pts);
- for (uint32_t i = 0; i < ptsCnt; ++i) _multiply(p++, transform);
+ if (preTransform) {
+ 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);
+ for (uint32_t i = 0; i < ptsCnt; ++i) _multiply(p++, transform);
+ }
}
cnt += writeData(pts, ptsCnt * SIZE(pts[0]));
if (auto flag = static_cast<TvgBinFlag>(shape->fillRule()))
cnt = writeTagProperty(TVG_TAG_SHAPE_FILLRULE, SIZE(TvgBinFlag), &flag);
+
+ bool preTransform = true;
+
//stroke
if (shape->strokeWidth() > 0) {
+ //We can't apply pre-transformation if the stroke has the irregular scaling per directions or it has dash.
+ if (abs(transform.e11 - transform.e22) > FLT_EPSILON || shape->strokeDash(nullptr) > 0) preTransform = false;
+
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) cnt += serializeStroke(shape, &transform);
+ if (fill || color[3] > 0) cnt += serializeStroke(shape, &transform, preTransform);
}
//fill
if (color[3] > 0) cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, SIZE(color), color);
}
- cnt += serializePath(shape, pTransform);
+ cnt += serializePath(shape, transform, preTransform);
+
+ if (!preTransform) cnt += writeTransform(transform);
cnt += serializePaint(shape, pTransform);
writeReservedCount(cnt);
TvgBinCounter serializePicture(const Picture* picture, const Matrix* pTransform);
TvgBinCounter serializePaint(const Paint* paint, const Matrix* pTransform);
TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag, const Matrix* pTransform);
- TvgBinCounter serializeStroke(const Shape* shape, const Matrix* pTransform);
- TvgBinCounter serializePath(const Shape* shape, 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);
TvgBinCounter serializeChildren(Iterator* it, const Matrix* transform, bool reserved);
TvgBinCounter serializeChild(const Paint* parent, const Paint* child, const Matrix* pTransform);