diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 32d23a791d7f8..90b047214086f 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -303,11 +303,10 @@ class HtmlViewEmbedder { // // HTML elements use logical (CSS) pixels, but we have been using physical // pixels, so scale down the head element to match the logical resolution. - final double scale = EnginePlatformDispatcher.browserDevicePixelRatio; + final double scale = window.devicePixelRatio; final double inverseScale = 1 / scale; - final Matrix4 scaleMatrix = - Matrix4.diagonal3Values(inverseScale, inverseScale, 1); - headTransform.multiply(scaleMatrix); + final Matrix4 scaleMatrix = Matrix4.diagonal3Values(inverseScale, inverseScale, 1); + headTransform = scaleMatrix.multiplied(headTransform); head.style.transform = float64ListToCssTransform(headTransform.storage); } diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index 3930e2d43ad19..a1dc4f99f1695 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -15,8 +15,6 @@ import 'package:test/test.dart'; import 'common.dart'; const MethodCodec codec = StandardMethodCodec(); -final EngineSingletonFlutterWindow window = - EngineSingletonFlutterWindow(0, EnginePlatformDispatcher.instance); void main() { internalBootstrapBrowserTest(() => testMain); @@ -26,6 +24,10 @@ void testMain() { group('HtmlViewEmbedder', () { setUpCanvasKitTest(); + setUp(() { + window.debugOverrideDevicePixelRatio(1); + }); + test('embeds interactive platform views', () async { ui.platformViewRegistry.registerViewFactory( 'test-platform-view', @@ -84,6 +86,7 @@ void testMain() { 'url("#svgClip1")', ); }); + test('correctly transforms platform views', () async { ui.platformViewRegistry.registerViewFactory( 'test-platform-view', @@ -115,6 +118,76 @@ void testMain() { ); }); + // Returns the list of CSS transforms applied to the ancestor chain of + // elements starting from `viewHost`, up until and excluding . + List getTransformChain(html.Element viewHost) { + final List chain = []; + html.Element? element = viewHost; + while(element != null && element.tagName.toLowerCase() != 'flt-scene') { + chain.add(element.style.transform); + element = element.parent; + } + return chain; + } + + test('converts device pixels to logical pixels (no clips)', () async { + window.debugOverrideDevicePixelRatio(4); + ui.platformViewRegistry.registerViewFactory( + 'test-platform-view', + (viewId) => html.DivElement()..id = 'view-0', + ); + await _createPlatformView(0, 'test-platform-view'); + + final EnginePlatformDispatcher dispatcher = + ui.window.platformDispatcher as EnginePlatformDispatcher; + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(1, 1); + sb.pushOffset(2, 2); + sb.pushOffset(3, 3); + sb.addPlatformView(0, width: 10, height: 10); + dispatcher.rasterizer!.draw(sb.build().layerTree); + final html.Element viewHost = domRenderer.sceneElement! + .querySelectorAll('#view-0') + .single; + + expect( + getTransformChain(viewHost), + ['matrix(0.25, 0, 0, 0.25, 1.5, 1.5)'], + ); + }); + + test('converts device pixels to logical pixels (with clips)', () async { + window.debugOverrideDevicePixelRatio(4); + ui.platformViewRegistry.registerViewFactory( + 'test-platform-view', + (viewId) => html.DivElement()..id = 'view-0', + ); + await _createPlatformView(0, 'test-platform-view'); + + final EnginePlatformDispatcher dispatcher = + ui.window.platformDispatcher as EnginePlatformDispatcher; + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(3, 3); + sb.pushClipRect(ui.Rect.largest); + sb.pushOffset(6, 6); + sb.pushClipRect(ui.Rect.largest); + sb.pushOffset(9, 9); + sb.addPlatformView(0, width: 10, height: 10); + dispatcher.rasterizer!.draw(sb.build().layerTree); + final html.Element viewHost = domRenderer.sceneElement! + .querySelectorAll('#view-0') + .single; + + expect( + getTransformChain(viewHost), + [ + 'matrix(1, 0, 0, 1, 9, 9)', + 'matrix(1, 0, 0, 1, 6, 6)', + 'matrix(0.25, 0, 0, 0.25, 0.75, 0.75)', + ], + ); + }); + test('renders overlays on top of platform views', () async { expect(OverlayCache.instance.debugLength, 0); final CkPicture testPicture = paintPicture(