Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
65fb5d3
Switch ui.window.devicePixelRatio to browser dpi
ferhatb Mar 18, 2020
bd58d35
Rename debugOverrideDevicePixelRation to override. Add integration te…
ferhatb Mar 19, 2020
2165d86
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 19, 2020
542be23
Update cirrus for new integration test
ferhatb Mar 19, 2020
8705651
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 19, 2020
aab46b4
update canvas golden test root transform
ferhatb Mar 19, 2020
101083d
Update compositing golden test with dpr transform
ferhatb Mar 19, 2020
a328874
Address review comment
ferhatb Mar 19, 2020
3af31ef
remove print
ferhatb Mar 19, 2020
472615b
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 20, 2020
489ad43
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 20, 2020
7d31069
update test
ferhatb Mar 20, 2020
3ae5e40
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 20, 2020
16a0f0f
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 23, 2020
d8907b0
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 23, 2020
a2aaafb
Addressed review comments/replyChannel
ferhatb Mar 23, 2020
19da8b6
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 23, 2020
2b99962
Fix missing platform replymessage
ferhatb Mar 23, 2020
6ff40c2
Don't reply when callback is null
ferhatb Mar 23, 2020
8d087b4
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 23, 2020
44d045c
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 24, 2020
e456f3d
update test embedding for flutter framework tests
ferhatb Mar 24, 2020
c34111b
fix assert return
ferhatb Mar 24, 2020
47da9ce
CI test
ferhatb Mar 24, 2020
81fd917
CI test
ferhatb Mar 24, 2020
940e44d
CI test
ferhatb Mar 24, 2020
1d864dc
CI test
ferhatb Mar 24, 2020
2419fdb
CI Test
ferhatb Mar 24, 2020
d455d74
CI Test
ferhatb Mar 24, 2020
be2113d
Test CI
ferhatb Mar 24, 2020
6b227a7
Test CI
ferhatb Mar 24, 2020
5f21300
rename override to debugOverride
ferhatb Mar 24, 2020
2eaae7e
Revert to pre CI test code that was reviewed
ferhatb Mar 24, 2020
50f6c64
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 24, 2020
158533c
fix typo and address review comment
ferhatb Mar 24, 2020
de3b6a7
Fix check for top level matrix
ferhatb Mar 25, 2020
fcffbec
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 25, 2020
b710b87
Update assert for top level matrix to allow subclassing of window in …
ferhatb Mar 25, 2020
68e85ca
Merge remote-tracking branch 'upstream/master' into devicepixels
ferhatb Mar 25, 2020
01c5bf5
update assert to handle null _debugDevicePixels
ferhatb Mar 25, 2020
47a11e5
Restrict top level transform check
ferhatb Mar 25, 2020
ea15a3c
address review comments
ferhatb Mar 25, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ task:
- $FRAMEWORK_PATH/flutter/bin/flutter config --local-engine=host_debug_unopt --no-analytics --enable-web
- $FRAMEWORK_PATH/flutter/bin/flutter pub get --local-engine=host_debug_unopt
- $FRAMEWORK_PATH/flutter/bin/flutter drive -v --target=test_driver/text_editing_e2e.dart -d web-server --release --browser-name=chrome --local-engine=host_debug_unopt
- $FRAMEWORK_PATH/flutter/bin/flutter drive -v --target=test_driver/image_loading_e2e.dart -d web-server --release --browser-name=chrome --local-engine=host_debug_unopt

- name: build_and_test_web_linux_firefox
compile_host_script: |
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions e2etests/web/regular_integration_tests/lib/image_loading_main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() async {
const MethodChannel channel =
OptionalMethodChannel('flutter/web_test_e2e', JSONMethodCodec());
await channel.invokeMethod<void>(
'setDevicePixelRatio',
'1.5',
);
runApp(MyApp());
}

class MyApp extends StatefulWidget {
@override
MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
key: const Key('mainapp'),
title: 'Integration Test App',
home: Image.asset('assets/images/sample_image1.png')
);
}
}
4 changes: 4 additions & 0 deletions e2etests/web/regular_integration_tests/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ dev_dependencies:
e2e: 0.2.4+4
http: 0.12.0+2
test: any

flutter:
assets:
- assets/images/
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:html' as html;
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:regular_integration_tests/image_loading_main.dart' as app;

import 'package:e2e/e2e.dart';

void main() {
E2EWidgetsFlutterBinding.ensureInitialized() as E2EWidgetsFlutterBinding;

testWidgets('Image loads asset variant based on device pixel ratio',
(WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
final html.ImageElement imageElement = html.querySelector('img') as html.ImageElement;
expect(imageElement.naturalWidth, 1.5 * 100);
expect(imageElement.naturalHeight, 1.5 * 100);
expect(imageElement.width, 100);
expect(imageElement.height, 100);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:io';

import 'package:flutter_driver/flutter_driver.dart';

Future<void> main() async {
final FlutterDriver driver = await FlutterDriver.connect();

final String dataRequest =
await driver.requestData(null, timeout: const Duration(seconds: 1));
await driver.close();

exit(dataRequest == 'pass' ? 0 : 1);
}
2 changes: 2 additions & 0 deletions lib/web_ui/lib/src/engine/compositor/embedded_views.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ class HtmlViewEmbedder {
switch (decoded.method) {
case 'create':
_create(decoded, callback);
window._replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
case 'dispose':
_dispose(decoded, callback);
window._replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
}
callback(null);
Expand Down
6 changes: 0 additions & 6 deletions lib/web_ui/lib/src/engine/dom_renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,6 @@ flt-glass-pane * {
// DOM tree.
setElementAttribute(_sceneHostElement, 'aria-hidden', 'true');

// We treat browser pixels as device pixels because pointer events,
// position, and sizes all use browser pixel as the unit (i.e. "px" in CSS).
// Therefore, as far as the framework is concerned the device pixel ratio
// is 1.0.
window.debugOverrideDevicePixelRatio(1.0);

if (html.window.visualViewport == null && isWebKit) {
// Safari sometimes gives us bogus innerWidth/innerHeight values when the
// page loads. When it changes the values to correct ones it does not
Expand Down
2 changes: 2 additions & 0 deletions lib/web_ui/lib/src/engine/platform_views.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ void handlePlatformViewCall(
switch (decoded.method) {
case 'create':
_createPlatformView(decoded, callback);
window._replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
case 'dispose':
_disposePlatformView(decoded, callback);
window._replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
}
callback(null);
Expand Down
4 changes: 2 additions & 2 deletions lib/web_ui/lib/src/engine/semantics/accessibility.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ class AccessibilityAnnouncements {
html.HtmlElement get _domElement => _element ??= _createElement();

/// Decodes the message coming from the 'flutter/accessibility' channel.
void handleMessage(ByteData data) {
void handleMessage(StandardMessageCodec codec, ByteData data) {
final Map<dynamic, dynamic> inputMap =
const StandardMessageCodec().decodeMessage(data);
codec.decodeMessage(data);
final Map<dynamic, dynamic> dataMap = inputMap['data'];
final String message = dataMap['message'];
if (message != null && message.isNotEmpty) {
Expand Down
31 changes: 24 additions & 7 deletions lib/web_ui/lib/src/engine/surface/scene_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
_surfaceStack.add(PersistedScene(_lastFrameScene));
}

final List<PersistedContainerSurface> _surfaceStack = <PersistedContainerSurface>[];
final List<PersistedContainerSurface> _surfaceStack =
<PersistedContainerSurface>[];

/// The scene built by this scene builder.
///
Expand All @@ -19,7 +20,8 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
assert(() {
if (_surfaceStack.length != 1) {
final String surfacePrintout = _surfaceStack
.map<Type>((PersistedContainerSurface surface) => surface.runtimeType)
.map<Type>(
(PersistedContainerSurface surface) => surface.runtimeType)
.toList()
.join(', ');
throw Exception('Incorrect sequence of push/pop operations while '
Expand All @@ -42,7 +44,8 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
// the live tree.
if (surface.oldLayer != null) {
assert(surface.oldLayer.runtimeType == surface.runtimeType);
assert(debugAssertSurfaceState(surface.oldLayer, PersistedSurfaceState.active));
assert(debugAssertSurfaceState(
surface.oldLayer, PersistedSurfaceState.active));
surface.oldLayer.state = PersistedSurfaceState.pendingUpdate;
}
_adoptSurface(surface);
Expand Down Expand Up @@ -97,6 +100,16 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
if (matrix4.length != 16) {
throw ArgumentError('"matrix4" must have 16 entries.');
}
if (_surfaceStack.length == 1) {
// Top level transform contains view configuration to scale
// scene to devicepixelratio. Use identity instead since CSS uses
// logical device pixels.
if (!ui.debugEmulateFlutterTesterEnvironment) {
assert(matrix4[0] == window.devicePixelRatio &&
matrix4[5] == window.devicePixelRatio);
}
matrix4 = Matrix4.identity().storage;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, now that I think about it, the correct fix would be to inject a transform that scales by 1/DPR. This way we don't have to rely on a particular framework behavior. To avoid extra div nodes we can do something like:

if (the scene contains a root transform) {
  reuse the root transform by scale it by 1/DPR.
} else {
  apply 1/DPR to the `<flt-scene>` element.
}

In most cases we'll hit the if branch, not the else branch. Also in most cases the root transform will be scale by DPR. So the resulting root transform will automatically become identity and we won't apply any transform at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The framework itself injects pushTransform using ViewConfiguration. Ideally this code would not live in framework but in engine. See view.dart:39. Or instead of calling pushTransform , framework would call SceneBuilder.setViewConfiguration in engine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but you can use dart:ui without the Flutter framework where you can paint a scene without a root transform. This typically happens in tests and benchmarks. I don't expect there to be many apps that don't use the framework.

}
return _pushSurface(PersistedTransform(oldLayer, matrix4));
}

Expand Down Expand Up @@ -276,7 +289,8 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
void addRetained(ui.EngineLayer retainedLayer) {
final PersistedContainerSurface retainedSurface = retainedLayer;
if (assertionsEnabled) {
assert(debugAssertSurfaceState(retainedSurface, PersistedSurfaceState.active, PersistedSurfaceState.released));
assert(debugAssertSurfaceState(retainedSurface,
PersistedSurfaceState.active, PersistedSurfaceState.released));
}
retainedSurface.tryRetain();
_adoptSurface(retainedSurface);
Expand Down Expand Up @@ -319,7 +333,8 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
/// for more details.
@override
void addPerformanceOverlay(int enabledOptions, ui.Rect bounds) {
_addPerformanceOverlay(enabledOptions, bounds.left, bounds.right, bounds.top, bounds.bottom);
_addPerformanceOverlay(
enabledOptions, bounds.left, bounds.right, bounds.top, bounds.bottom);
}

/// Whether we've already warned the user about the lack of the performance
Expand All @@ -337,7 +352,8 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
) {
if (!_webOnlyDidWarnAboutPerformanceOverlay) {
_webOnlyDidWarnAboutPerformanceOverlay = true;
html.window.console.warn('The performance overlay isn\'t supported on the web');
html.window.console
.warn('The performance overlay isn\'t supported on the web');
}
}

Expand Down Expand Up @@ -377,7 +393,8 @@ class SurfaceSceneBuilder implements ui.SceneBuilder {
_addTexture(offset.dx, offset.dy, width, height, textureId);
}

void _addTexture(double dx, double dy, double width, double height, int textureId) {
void _addTexture(
double dx, double dy, double width, double height, int textureId) {
// In test mode, allow this to be a no-op.
if (!ui.debugEmulateFlutterTesterEnvironment) {
throw UnimplementedError('Textures are not supported in Flutter Web');
Expand Down
8 changes: 6 additions & 2 deletions lib/web_ui/lib/src/engine/text_editing/text_editing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,11 @@ class TextEditingChannel {
final HybridTextEditing implementation;

/// Handles "flutter/textinput" platform messages received from the framework.
void handleTextInput(ByteData data) {
final MethodCall call = const JSONMethodCodec().decodeMethodCall(data);
void handleTextInput(
ByteData data,
ui.PlatformMessageResponseCallback callback) {
const JSONMethodCodec codec = JSONMethodCodec();
final MethodCall call = codec.decodeMethodCall(data);
switch (call.method) {
case 'TextInput.setClient':
implementation.setClient(
Expand Down Expand Up @@ -815,6 +818,7 @@ class TextEditingChannel {
default:
throw StateError('Unsupported method call on the flutter/textinput channel: ${call.method}');
}
window._replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
}

/// Sends the 'TextInputClient.updateEditingState' message to the framework.
Expand Down
59 changes: 40 additions & 19 deletions lib/web_ui/lib/src/engine/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,11 @@ class EngineWindow extends ui.Window {
}

@override
double get devicePixelRatio {
if (_debugDevicePixelRatio != null) {
return _debugDevicePixelRatio;
}
double get devicePixelRatio => _debugDevicePixelRatio != null
? _debugDevicePixelRatio
: browserDevicePixelRatio;

if (experimentalUseSkia) {
return browserDevicePixelRatio;
} else {
return 1.0;
}
}

/// Returns device pixel ratio returns by browser.
/// Returns device pixel ratio returned by browser.
static double get browserDevicePixelRatio {
double ratio = html.window.devicePixelRatio;
// Guard against WebOS returning 0.
Expand All @@ -38,10 +30,7 @@ class EngineWindow extends ui.Window {
///
/// This is useful in tests to emulate screens of different dimensions.
void debugOverrideDevicePixelRatio(double value) {
assert(() {
_debugDevicePixelRatio = value;
return true;
}());
_debugDevicePixelRatio = value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? It's still used only in tests, so the "debug" prefix and assert seem appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is now also used in integration test (the one that loads an image at framework level).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but that's still a test :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do integration tests strip out asserts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they don't, we should add the option to enable them. dart2js supports asserts (we use dart2js for engine unit-test with assertions enabled).

/cc @nturgut

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My comment is non-blocking though. I don't think there's major risk. It just doesn't feel right for a method that's not annotated as "debug" to manipulate a "debug" field without an assertion.

}

double _debugDevicePixelRatio;
Expand Down Expand Up @@ -160,26 +149,38 @@ class EngineWindow extends ui.Window {
case 'HapticFeedback.vibrate':
final String type = decoded.arguments;
domRenderer.vibrate(_getHapticFeedbackDuration(type));
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
case 'SystemChrome.setApplicationSwitcherDescription':
final Map<String, dynamic> arguments = decoded.arguments;
domRenderer.setTitle(arguments['label']);
domRenderer.setThemeColor(ui.Color(arguments['primaryColor']));
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
case 'SystemSound.play':
// There are no default system sounds on web.
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
case 'Clipboard.setData':
ClipboardMessageHandler().setDataMethodCall(decoded, callback);
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
case 'Clipboard.getData':
ClipboardMessageHandler().getDataMethodCall(callback);
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
return;
}
break;

case 'flutter/textinput':
textEditing.channel.handleTextInput(data);
textEditing.channel.handleTextInput(data, callback);
return;

case 'flutter/web_test_e2e':
const MethodCodec codec = JSONMethodCodec();
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(
_handleWebTestEnd2EndMessage(codec, data)
));
return;

case 'flutter/platform_views':
Expand All @@ -192,7 +193,9 @@ class EngineWindow extends ui.Window {

case 'flutter/accessibility':
// In widget tests we want to bypass processing of platform messages.
accessibilityAnnouncements.handleMessage(data);
final StandardMessageCodec codec = StandardMessageCodec();
accessibilityAnnouncements.handleMessage(codec, data);
_replyToPlatformMessage(callback, codec.encodeMessage(true));
return;

case 'flutter/navigation':
Expand All @@ -204,9 +207,11 @@ class EngineWindow extends ui.Window {
case 'routePushed':
case 'routeReplaced':
_browserHistory.setRouteName(message['routeName']);
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
break;
case 'routePopped':
_browserHistory.setRouteName(message['previousRouteName']);
_replyToPlatformMessage(callback, codec.encodeSuccessEnvelope(true));
break;
}
return;
Expand Down Expand Up @@ -250,7 +255,9 @@ class EngineWindow extends ui.Window {
ByteData data,
) {
Future<void>.delayed(Duration.zero).then((_) {
callback(data);
if (callback != null) {
callback(data);
}
});
}

Expand Down Expand Up @@ -315,6 +322,20 @@ class EngineWindow extends ui.Window {
Rasterizer rasterizer = experimentalUseSkia ? Rasterizer(Surface()) : null;
}

bool _handleWebTestEnd2EndMessage(MethodCodec codec, ByteData data) {
final MethodCall decoded = codec.decodeMethodCall(data);
final Map<String, dynamic> message = decoded.arguments;
double ratio = double.parse(decoded.arguments);
bool result = false;
switch(decoded.method) {
case 'setDevicePixelRatio':
window.debugOverrideDevicePixelRatio(ratio);
window.onMetricsChanged();
return true;
}
return false;
}

/// The window singleton.
///
/// `dart:ui` window delegates to this value. However, this value has a wider
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/lib/src/ui/test_embedding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Future<dynamic> ensureTestPlatformInitializedThenRunTest(
/// are available.
Future<void> _platformInitializedFuture;

/// Initializes domRenderer with specific devicePixelRation and physicalSize.
/// Initializes domRenderer with specific devicePixelRatio and physicalSize.
Future<void> webOnlyInitializeTestDomRenderer({double devicePixelRatio = 3.0}) {
// Force-initialize DomRenderer so it doesn't overwrite test pixel ratio.
engine.domRenderer;
Expand Down
Loading