Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b65c93e

Browse files
[skwasm] Combine offset and transform properly. (#53967)
Our treatment of the interaction between offset and transform was incorrect. Modified our platform view unit tests to cover more cases of nested offsets and transforms.
1 parent 312b519 commit b65c93e

File tree

4 files changed

+66
-29
lines changed

4 files changed

+66
-29
lines changed

lib/web_ui/lib/src/engine/layers.dart

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -499,18 +499,19 @@ class PlatformViewPosition {
499499
}
500500

501501
// Otherwise, at least one of the positions involves a matrix transform.
502-
final Matrix4 newTransform;
503-
if (outerOffset != null) {
504-
newTransform = Matrix4.translationValues(outerOffset.dx, outerOffset.dy, 0);
502+
final Matrix4 innerTransform;
503+
final Matrix4 outerTransform;
504+
if (innerOffset != null) {
505+
innerTransform = Matrix4.translationValues(innerOffset.dx, innerOffset.dy, 0);
505506
} else {
506-
newTransform = outer.transform!.clone();
507+
innerTransform = inner.transform!;
507508
}
508-
if (innerOffset != null) {
509-
newTransform.translate(innerOffset.dx, innerOffset.dy);
509+
if (outerOffset != null) {
510+
outerTransform = Matrix4.translationValues(outerOffset.dx, outerOffset.dy, 0);
510511
} else {
511-
newTransform.multiply(inner.transform!);
512+
outerTransform = outer.transform!;
512513
}
513-
return PlatformViewPosition.transform(newTransform);
514+
return PlatformViewPosition.transform(outerTransform.multiplied(innerTransform));
514515
}
515516

516517
@override

lib/web_ui/lib/src/engine/scene_view.dart

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -308,26 +308,26 @@ final class PlatformViewContainer extends SliceContainer {
308308
assert(_bounds != null);
309309
if (_dirty) {
310310
final DomCSSStyleDeclaration style = container.style;
311-
final double devicePixelRatio = EngineFlutterDisplay.instance.devicePixelRatio;
312-
final double logicalWidth = _bounds!.width / devicePixelRatio;
313-
final double logicalHeight = _bounds!.height / devicePixelRatio;
314-
style.width = '${logicalWidth}px';
315-
style.height = '${logicalHeight}px';
316311
style.position = 'absolute';
312+
style.width = '${_bounds!.width}px';
313+
style.height = '${_bounds!.height}px';
317314

318-
final PlatformViewPosition position = PlatformViewPosition.combine(
319-
_styling!.position,
320-
PlatformViewPosition.offset(_bounds!.topLeft),
321-
);
322-
323-
final ui.Offset offset = position.offset ?? ui.Offset.zero;
324-
final double logicalLeft = offset.dx / devicePixelRatio;
325-
final double logicalTop = offset.dy / devicePixelRatio;
326-
style.left = '${logicalLeft}px';
327-
style.top = '${logicalTop}px';
315+
final double devicePixelRatio = EngineFlutterDisplay.instance.devicePixelRatio;
316+
final PlatformViewPosition position = _styling!.position;
328317

329-
final Matrix4? transform = position.transform;
330-
style.transform = transform != null ? float64ListToCssTransform3d(transform.storage) : '';
318+
final Matrix4 transform;
319+
if (position.transform != null) {
320+
transform = position.transform!.clone()..translate(_bounds!.left, _bounds!.top);
321+
} else {
322+
final ui.Offset offset = position.offset ?? ui.Offset.zero;
323+
transform = Matrix4.translationValues(_bounds!.left + offset.dx, _bounds!.top + offset.dy, 0);
324+
}
325+
final double inverseScale = 1.0 / devicePixelRatio;
326+
final Matrix4 scaleMatrix =
327+
Matrix4.diagonal3Values(inverseScale, inverseScale, 1);
328+
scaleMatrix.multiply(transform);
329+
style.transform = float64ListToCssTransform(scaleMatrix.storage);
330+
style.transformOrigin = '0 0 0';
331331
style.opacity = _styling!.opacity != 1.0 ? '${_styling!.opacity}' : '';
332332
// TODO(jacksongardner): Implement clip styling for platform views
333333

lib/web_ui/test/engine/scene_view_test.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,13 @@ void testMain() {
167167
containerElement.tagName, equalsIgnoringCase('flt-platform-view-slot'));
168168

169169
final DomCSSStyleDeclaration style = containerElement.style;
170-
expect(style.left, '25px');
171-
expect(style.top, '40px');
172-
expect(style.width, '50px');
173-
expect(style.height, '60px');
170+
expect(style.left, '');
171+
expect(style.top, '');
172+
expect(style.width, '100px');
173+
expect(style.height, '120px');
174+
175+
// The heavy lifting of offsetting and sizing is done by the transform
176+
expect(style.transform, 'matrix(0.5, 0, 0, 0.5, 25, 40)');
174177

175178
debugOverrideDevicePixelRatio(null);
176179
});

lib/web_ui/test/ui/platform_view_test.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,39 @@ Future<void> testMain() async {
132132
await matchGoldenFile('platformview_transformed.png', region: region);
133133
});
134134

135+
test('transformed and offset platformview', () async {
136+
await _createPlatformView(1, platformViewType);
137+
138+
final ui.PictureRecorder recorder = ui.PictureRecorder();
139+
final ui.Canvas canvas = ui.Canvas(recorder);
140+
canvas.drawCircle(
141+
const ui.Offset(50, 50),
142+
50,
143+
ui.Paint()
144+
..style = ui.PaintingStyle.fill
145+
..color = const ui.Color(0xFFFF0000)
146+
);
147+
148+
final ui.SceneBuilder sb = ui.SceneBuilder();
149+
sb.pushOffset(0, 0);
150+
sb.addPicture(const ui.Offset(100, 100), recorder.endRecording());
151+
152+
// Nest offsets both before and after the transform to make sure that they
153+
// are applied properly.
154+
sb.pushOffset(50, 50);
155+
sb.pushTransform(Matrix4.rotationZ(0.1).toFloat64());
156+
sb.pushOffset(25, 25);
157+
sb.addPlatformView(
158+
1,
159+
offset: const ui.Offset(50, 50),
160+
width: 50,
161+
height: 50,
162+
);
163+
await renderScene(sb.build());
164+
165+
await matchGoldenFile('platformview_transformed_offset.png', region: region);
166+
});
167+
135168
test('offset platformview', () async {
136169
await _createPlatformView(1, platformViewType);
137170

0 commit comments

Comments
 (0)