Skip to content

[vector_graphics] AffineTransform in package vector_graphics_compiler mismanages m4_10 value #173817

@flar

Description

@flar

The AffineTransform class in vector_graphics_compiler/lib/src/geometry/matrix.dart maintains a value for the Z scale (m4_10 in the constructor and _m4_10 in the fields), but it breaks many graphics conventions in doing so.

First, the class is designed around a 2x3 affine matrix transform, a common 2D graphics library concept, where it represents a 3x3 transform matrix, but with the 3rd row hard-coded to [0, 0, 1]. This is common and used in many 2D graphics libraries (Postscript, Java2D, SVG and the 2D affine values defined by CSS). Such a transform is capable of any 2D affine transformation but cannot represent Z coordinate transforms, nor any perspective properties. The class has also defined a 7th parameter on the constructor called m4_10 which seems to represent a "Z scale" parameter since that is the 4x4 matrix entry that it is placed into when the class is called upon to produce the 4x4 matrix that the Dart vector_math package uses.

There are some questionable behaviors of this extra field, though, that don't seem to follow any conventions that I've seen before for sprinkling in a bit of 3D to an otherwise 2D affine transform, including:

  • Originally the default for the parameter was 1.0, but was switched to "a copy of the first (X scale) parameter if not otherwise specified" in an undocumented early PR (Add some missing tests, fix bugs dnfield/vector_graphics#9). To truly represent a 2D-only matrix, the Z scale would be left at 1.0 since the drawing is constrained to a plane with only X and Y coordinates.
  • Even if the class wanted to somehow replicate the existing scale of the 2D affine matrix into the Z scale parameter, making it a copy of the existing first matrix entry (the X scale) doesn't really do that for many reasons, but particularly since in a rotated coordinate system that first entry may be some value usually smaller than the scale or even 0.0 for a quadrant rotated coordinate system. Trying to deduce the "Z scale" from the existing elements of the matrix would make assumptions about how it was constructed that cannot be inferred statically from those elements. The best approach would be to not make assumptions, produce a 1.0 value, and let the caller pass in a Z scale if there was one in the model or view in which it is working.
  • If a scale operation is performed, the scale is assumed to apply to Z even though this class may be used (is used) by a predominantly 2D graphics packages (such as the related SVG parser in the same package). When scaling in a 2D coordinate system, typically one assumes that the Z scale is unaffected, or there is no assumption. The same "just reuse the X scale" assumption is made for the scale method, which is more assumption than the provided scale parameters can support.

Unfortunately, due to a lack of documentation for these early commits to the original repo, we have no explanations for why these behaviors were created or changed as described above and no way to test for the intended behaviors that were supposed to be supported, but we will continue to run into problems such as identified in #171854 (that last bug was fixed exclusively for SVG parsing only by hard-coding a Z=1 scale for SVG transforms produced by the package's SVG matrix parsing method).

Metadata

Metadata

Assignees

No one assigned

    Labels

    p: vector_graphicsThe vector_graphics package setpackageflutter/packages repository. See also p: labels.team-engineOwned by Engine team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions