Skip to content

Commit f30ff4f

Browse files
authored
Use 2d matrix for transform to work around Safari clipping bug (flutter#15976)
1 parent 1e7a9de commit f30ff4f

2 files changed

Lines changed: 42 additions & 14 deletions

File tree

lib/web_ui/lib/src/engine/util.dart

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,14 @@ void setElementTransform(html.Element element, Float64List matrix4) {
7777
final bool isHighDevicePixelRatioScreen =
7878
EngineWindow.browserDevicePixelRatio > 1.0;
7979

80-
if (transformKind == TransformKind.complex || isHighDevicePixelRatioScreen) {
80+
if (transformKind == TransformKind.scaleAndTranslate2d) {
81+
final String cssTransform = float64ListToCssTransform2d(matrix4);
82+
element.style
83+
..transformOrigin = '0 0 0'
84+
..transform = cssTransform
85+
..top = null
86+
..left = null;
87+
} else if (transformKind == TransformKind.complex || isHighDevicePixelRatioScreen) {
8188
final String cssTransform = float64ListToCssTransform3d(matrix4);
8289
element.style
8390
..transformOrigin = '0 0 0'
@@ -107,6 +114,9 @@ enum TransformKind {
107114
/// No effect.
108115
identity,
109116

117+
/// A transform that contains only 2d scale and transform.
118+
scaleAndTranslate2d,
119+
110120
/// A translation along either X or Y axes, or both.
111121
translation2d,
112122

@@ -123,12 +133,13 @@ TransformKind transformKindOf(Float64List matrix) {
123133

124134
// If matrix contains scaling, rotation, z translation or
125135
// perspective transform, it is not considered simple.
126-
final bool isSimpleTransform = m[0] == 1.0 &&
136+
final bool isSimple2dTransform =
137+
// m[0] - scale x is simple
127138
m[1] == 0.0 &&
128139
m[2] == 0.0 &&
129140
m[3] == 0.0 &&
130141
m[4] == 0.0 &&
131-
m[5] == 1.0 &&
142+
// m[5] - scale y is simple
132143
m[6] == 0.0 &&
133144
m[7] == 0.0 &&
134145
m[8] == 0.0 &&
@@ -140,15 +151,19 @@ TransformKind transformKindOf(Float64List matrix) {
140151
m[14] == 0.0 && // z translation is NOT simple
141152
m[15] == 1.0;
142153

143-
if (!isSimpleTransform) {
154+
if (!isSimple2dTransform) {
144155
return TransformKind.complex;
145156
}
146157

147-
if (ty != 0.0 || tx != 0.0) {
148-
return TransformKind.translation2d;
158+
if (m[0] == 1.0 && m[5] == 1.0) {
159+
if (ty != 0.0 || tx != 0.0) {
160+
return TransformKind.translation2d;
161+
} else {
162+
return TransformKind.identity;
163+
}
164+
} else {
165+
return TransformKind.scaleAndTranslate2d;
149166
}
150-
151-
return TransformKind.identity;
152167
}
153168

154169
/// Returns `true` is the [matrix] describes an identity transformation.
@@ -157,29 +172,38 @@ bool isIdentityFloat64ListTransform(Float64List matrix) {
157172
return transformKindOf(matrix) == TransformKind.identity;
158173
}
159174

175+
/// Converts [matrix] to CSS transform value.
176+
String float64ListToCssTransform2d(Float64List matrix) {
177+
assert (transformKindOf(matrix) == TransformKind.scaleAndTranslate2d);
178+
return 'matrix(${matrix[0]},0,0,${matrix[5]},${matrix[12]},${matrix[13]})';
179+
}
180+
160181
/// Converts [matrix] to CSS transform value.
161182
String float64ListToCssTransform(Float64List matrix) {
162183
assert(matrix.length == 16);
163184
final Float64List m = matrix;
164-
if (m[0] == 1.0 &&
165-
m[1] == 0.0 &&
185+
if (m[1] == 0.0 &&
166186
m[2] == 0.0 &&
167187
m[3] == 0.0 &&
168188
m[4] == 0.0 &&
169-
m[5] == 1.0 &&
170189
m[6] == 0.0 &&
171190
m[7] == 0.0 &&
172191
m[8] == 0.0 &&
173192
m[9] == 0.0 &&
174193
m[10] == 1.0 &&
175194
m[11] == 0.0 &&
176-
// 12 can be anything
177-
// 13 can be anything
195+
// 12 can be anything (translation)
196+
// 13 can be anything (translation)
178197
m[14] == 0.0 &&
179198
m[15] == 1.0) {
180199
final double tx = m[12];
181200
final double ty = m[13];
182-
return 'translate(${tx}px, ${ty}px)';
201+
if (m[0] == 1.0 &&
202+
m[5] == 1.0) {
203+
return 'translate(${tx}px, ${ty}px)';
204+
} else {
205+
return 'matrix(${m[0]},0,0,${m[5]},${tx},${ty})';
206+
}
183207
} else {
184208
return 'matrix3d(${m[0]},${m[1]},${m[2]},${m[3]},${m[4]},${m[5]},${m[6]},${m[7]},${m[8]},${m[9]},${m[10]},${m[11]},${m[12]},${m[13]},${m[14]},${m[15]})';
185209
}

lib/web_ui/test/engine/util_test.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ final Float64List identityTransform = Matrix4.identity().storage;
1212
final Float64List xTranslation = (Matrix4.identity()..translate(10)).storage;
1313
final Float64List yTranslation = (Matrix4.identity()..translate(0, 10)).storage;
1414
final Float64List zTranslation = (Matrix4.identity()..translate(0, 0, 10)).storage;
15+
final Float64List scaleAndTransform2d = (Matrix4.identity()..scale(2, 3, 1)..translate(4, 5, 0)).storage;
1516

1617
void main() {
1718
test('transformKindOf and isIdentityFloat64ListTransform identify matrix kind', () {
@@ -26,5 +27,8 @@ void main() {
2627

2728
expect(transformKindOf(zTranslation), TransformKind.complex);
2829
expect(isIdentityFloat64ListTransform(zTranslation), isFalse);
30+
31+
expect(transformKindOf(scaleAndTransform2d), TransformKind.scaleAndTranslate2d);
32+
expect(isIdentityFloat64ListTransform(scaleAndTransform2d), isFalse);
2933
});
3034
}

0 commit comments

Comments
 (0)