fix implicit dynamic and two lints everywhere; implicit cast in dev/ (flutter/engine#17372)

This commit is contained in:
Yegor 2020-03-29 19:23:37 -07:00 committed by GitHub
parent 317c96c3ce
commit 97bf969dc0
38 changed files with 303 additions and 186 deletions

View File

@ -3,9 +3,9 @@
# uncommented, we'll delete this file and simply inherit the root options.
analyzer:
# TODO(uncomment) strong-mode:
strong-mode:
# TODO(uncomment) implicit-casts: false
# TODO(uncomment) implicit-dynamic: false
implicit-dynamic: false
errors:
missing_required_param: warning
missing_return: warning
@ -15,7 +15,7 @@ analyzer:
linter:
rules:
- always_declare_return_types
# TODO(uncomment) - always_put_control_body_on_new_line
- always_put_control_body_on_new_line
# TODO(uncomment) - always_specify_types
# TODO(uncomment) - annotate_overrides
# TODO(uncomment) - avoid_classes_with_only_static_members

View File

@ -0,0 +1,7 @@
# This is a temporary file used to clean up dev/ before other directories
include: ../analysis_options.yaml
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false

View File

@ -51,8 +51,8 @@ abstract class Browser {
///
/// If there's a problem starting or running the browser, this will complete
/// with an error.
Future get onExit => _onExitCompleter.future;
final _onExitCompleter = Completer();
Future<void> get onExit => _onExitCompleter.future;
final _onExitCompleter = Completer<void>();
/// Standard IO streams for the underlying browser process.
final _ioSubscriptions = <StreamSubscription>[];
@ -96,7 +96,7 @@ abstract class Browser {
// resolve the ambiguity is to wait a brief amount of time and see if this
// browser is actually closed.
if (!_closed && exitCode < 0) {
await Future.delayed(Duration(milliseconds: 200));
await Future<void>.delayed(Duration(milliseconds: 200));
}
if (!_closed && exitCode != 0) {
@ -110,15 +110,21 @@ abstract class Browser {
}
_onExitCompleter.complete();
}, onError: (error, StackTrace stackTrace) {
}, onError: (dynamic error, StackTrace stackTrace) {
// Ignore any errors after the browser has been closed.
if (_closed) return;
if (_closed) {
return;
}
// Make sure the process dies even if the error wasn't fatal.
_process.then((process) => process.kill());
if (stackTrace == null) stackTrace = Trace.current();
if (_onExitCompleter.isCompleted) return;
if (stackTrace == null) {
stackTrace = Trace.current();
}
if (_onExitCompleter.isCompleted) {
return;
}
_onExitCompleter.completeError(
Exception('Failed to run $name: ${getErrorMessage(error)}.'),
stackTrace);
@ -142,6 +148,6 @@ abstract class Browser {
(await _process).kill();
// Swallow exceptions. The user should explicitly use [onExit] for these.
return onExit.catchError((_) {});
return onExit.catchError((dynamic _) {});
}
}

View File

@ -13,7 +13,7 @@ import 'package:watcher/watcher.dart';
import 'environment.dart';
import 'utils.dart';
class BuildCommand extends Command<bool> {
class BuildCommand extends Command<bool> with ArgUtils {
BuildCommand() {
argParser
..addFlag(
@ -35,15 +35,9 @@ class BuildCommand extends Command<bool> {
@override
String get description => 'Build the Flutter web engine.';
bool get isWatchMode => argResults['watch'];
bool get isWatchMode => boolArg('watch');
int getNinjaJobCount() {
final String ninjaJobsArg = argResults['ninja-jobs'];
if (ninjaJobsArg != null) {
return int.tryParse(ninjaJobsArg);
}
return null;
}
int getNinjaJobCount() => intArg('ninja-jobs');
@override
FutureOr<bool> run() async {

View File

@ -45,7 +45,7 @@ class ChromeArgParser extends BrowserArgParser {
@override
void parseOptions(ArgResults argResults) {
_version = argResults['chrome-version'];
_version = argResults['chrome-version'] as String;
}
@override
@ -108,7 +108,7 @@ Future<String> _findSystemChromeExecutable() async {
'Failed to locate system Chrome installation.');
}
return which.stdout;
return which.stdout as String;
}
/// Manages the installation of a particular [version] of Chrome.

View File

@ -10,8 +10,9 @@ import 'package:args/command_runner.dart';
import 'package:path/path.dart' as path;
import 'environment.dart';
import 'utils.dart';
class CleanCommand extends Command<bool> {
class CleanCommand extends Command<bool> with ArgUtils {
CleanCommand() {
argParser
..addFlag(
@ -24,7 +25,7 @@ class CleanCommand extends Command<bool> {
@override
String get name => 'clean';
bool get _alsoCleanNinja => argResults['ninja'];
bool get _alsoCleanNinja => boolArg('ninja');
@override
String get description => 'Deletes build caches and artifacts.';

View File

@ -71,8 +71,8 @@ const String _kBaseDownloadUrl =
class _WindowsBinding implements PlatformBinding {
@override
int getChromeBuild(YamlMap browserLock) {
final YamlMap chromeMap = browserLock['chrome'];
return chromeMap['Win'];
final YamlMap chromeMap = browserLock['chrome'] as YamlMap;
return chromeMap['Win'] as int;
}
@override
@ -110,8 +110,8 @@ class _WindowsBinding implements PlatformBinding {
class _LinuxBinding implements PlatformBinding {
@override
int getChromeBuild(YamlMap browserLock) {
final YamlMap chromeMap = browserLock['chrome'];
return chromeMap['Linux'];
final YamlMap chromeMap = browserLock['chrome'] as YamlMap;
return chromeMap['Linux'] as int;
}
@override
@ -151,8 +151,8 @@ class _LinuxBinding implements PlatformBinding {
class _MacBinding implements PlatformBinding {
@override
int getChromeBuild(YamlMap browserLock) {
final YamlMap chromeMap = browserLock['chrome'];
return chromeMap['Mac'];
final YamlMap chromeMap = browserLock['chrome'] as YamlMap;
return chromeMap['Mac'] as int;
}
@override
@ -192,10 +192,10 @@ class _MacBinding implements PlatformBinding {
}
class BrowserInstallation {
const BrowserInstallation(
{@required this.version,
@required this.executable,
fetchLatestChromeVersion});
const BrowserInstallation({
@required this.version,
@required this.executable,
});
/// Browser version.
final String version;
@ -230,7 +230,7 @@ class BrowserLock {
BrowserLock._() {
final io.File lockFile = io.File(
path.join(environment.webUiRootDir.path, 'dev', 'browser_lock.yaml'));
this._configuration = loadYaml(lockFile.readAsStringSync());
this._configuration = loadYaml(lockFile.readAsStringSync()) as YamlMap;
}
}

View File

@ -36,7 +36,7 @@ class EdgeArgParser extends BrowserArgParser {
@override
void parseOptions(ArgResults argResults) {
_version = argResults['edge-version'];
_version = argResults['edge-version'] as String;
assert(_version == 'system');
}
@ -124,7 +124,7 @@ class EdgeLauncher {
EdgeLauncher()
: version =
BrowserLock.instance.configuration['edge']['launcher_version'];
BrowserLock.instance.configuration['edge']['launcher_version'] as String;
/// Install the launcher if it does not exist in this system.
void install() async {

View File

@ -32,7 +32,7 @@ void main(List<String> args) async {
_listenToShutdownSignals();
try {
final bool result = await runner.run(args);
final bool result = (await runner.run(args)) as bool;
if (result == false) {
print('Sub-command returned false: `${args.join(' ')}`');
_cleanup();

View File

@ -26,7 +26,7 @@ class FirefoxArgParser extends BrowserArgParser {
@override
void populateOptions(ArgParser argParser) {
final YamlMap browserLock = BrowserLock.instance.configuration;
String firefoxVersion = browserLock['firefox']['version'];
String firefoxVersion = browserLock['firefox']['version'] as String;
argParser
..addOption(
@ -42,7 +42,7 @@ class FirefoxArgParser extends BrowserArgParser {
@override
void parseOptions(ArgResults argResults) {
_version = argResults['firefox-version'];
_version = argResults['firefox-version'] as String;
}
@override
@ -260,7 +260,7 @@ class FirefoxInstaller {
'Exit code ${mountResult.exitCode}.\n${mountResult.stderr}');
}
List<String> processOutput = mountResult.stdout.split('\n');
List<String> processOutput = (mountResult.stdout as String).split('\n');
String volumePath = _volumeFromMountResult(processOutput);
if (volumePath == null) {
throw BrowserInstallerException(
@ -313,7 +313,7 @@ Future<String> _findSystemFirefoxExecutable() async {
throw BrowserInstallerException(
'Failed to locate system Firefox installation.');
}
return which.stdout;
return which.stdout as String;
}
/// Fetches the latest available Firefox build version on Linux.

View File

@ -72,10 +72,10 @@ class ImageDiff {
/// That would be the distance between black and white.
static final double _maxTheoreticalColorDistance = Color.distance(
<int>[255, 255, 255], // white
<int>[0, 0, 0], // black
<num>[255, 255, 255], // white
<num>[0, 0, 0], // black
false,
);
).toDouble();
// If the normalized color difference of a pixel is greater than this number,
// we consider it a wrong pixel.
@ -203,9 +203,9 @@ class _GoldensRepoFetcher {
final io.File lockFile = io.File(
path.join(environment.webUiDevDir.path, 'goldens_lock.yaml')
);
final YamlMap lock = loadYaml(lockFile.readAsStringSync());
_repository = lock['repository'];
_revision = lock['revision'];
final YamlMap lock = loadYaml(lockFile.readAsStringSync()) as YamlMap;
_repository = lock['repository'] as String;
_revision = lock['revision'] as String;
final String localRevision = await _getLocalRevision();
if (localRevision == _revision) {

View File

@ -133,7 +133,7 @@ class IntegrationTestsManager {
Future<bool> _runTestsInDirectory(io.Directory directory) async {
final io.Directory testDirectory =
io.Directory(pathlib.join(directory.path, 'test_driver'));
final List<io.FileSystemEntity> entities = testDirectory
final List<io.File> entities = testDirectory
.listSync(followLinks: false)
.whereType<io.File>()
.toList();

View File

@ -35,7 +35,7 @@ class SafariArgParser extends BrowserArgParser {
@override
void parseOptions(ArgResults argResults) {
_version = argResults['safari-version'];
_version = argResults['safari-version'] as String;
assert(_version == 'system');
}

View File

@ -152,21 +152,29 @@ class BrowserPlatform extends PlatformPlugin {
}
final String payload = await request.readAsString();
final Map<String, dynamic> requestData = json.decode(payload);
final String filename = requestData['filename'];
final bool write = requestData['write'];
final Map<String, dynamic> requestData =
json.decode(payload) as Map<String, dynamic>;
final String filename = requestData['filename'] as String;
final bool write = requestData['write'] as bool;
final double maxDiffRate = requestData.containsKey('maxdiffrate')
? requestData['maxdiffrate'].toDouble() // can be parsed as either int or double
: kMaxDiffRateFailure;
final Map<String, dynamic> region = requestData['region'];
final PixelComparison pixelComparison = PixelComparison.values.firstWhere((value) => value.toString() == requestData['pixelComparison']);
final String result = await _diffScreenshot(filename, write, maxDiffRate, region, pixelComparison);
? (requestData['maxdiffrate'] as num)
.toDouble() // can be parsed as either int or double
: kMaxDiffRateFailure;
final Map<String, dynamic> region =
requestData['region'] as Map<String, dynamic>;
final PixelComparison pixelComparison = PixelComparison.values.firstWhere(
(value) => value.toString() == requestData['pixelComparison']);
final String result = await _diffScreenshot(
filename, write, maxDiffRate, region, pixelComparison);
return shelf.Response.ok(json.encode(result));
}
Future<String> _diffScreenshot(
String filename, bool write, double maxDiffRateFailure,
Map<String, dynamic> region, PixelComparison pixelComparison) async {
String filename,
bool write,
double maxDiffRateFailure,
Map<String, dynamic> region,
PixelComparison pixelComparison) async {
if (doUpdateScreenshotGoldens) {
write = true;
}
@ -209,9 +217,9 @@ To automatically create this file call matchGoldenFile('$filename', write: true)
Map<String, dynamic> captureScreenshotParameters = null;
if (region != null) {
captureScreenshotParameters = {
captureScreenshotParameters = <String, dynamic>{
'format': 'png',
'clip': {
'clip': <String, dynamic>{
'x': region['x'],
'y': region['y'],
'width': region['width'],
@ -224,7 +232,8 @@ To automatically create this file call matchGoldenFile('$filename', write: true)
// Setting hardware-independent screen parameters:
// https://chromedevtools.github.io/devtools-protocol/tot/Emulation
await wipConnection.sendCommand('Emulation.setDeviceMetricsOverride', {
await wipConnection
.sendCommand('Emulation.setDeviceMetricsOverride', <String, dynamic>{
'width': kMaxScreenshotWidth,
'height': kMaxScreenshotHeight,
'deviceScaleFactor': 1,
@ -234,7 +243,8 @@ To automatically create this file call matchGoldenFile('$filename', write: true)
'Page.captureScreenshot', captureScreenshotParameters);
// Compare screenshots
final Image screenshot = decodePng(base64.decode(response.result['data']));
final Image screenshot =
decodePng(base64.decode(response.result['data'] as String));
if (write) {
// Don't even bother with the comparison, just write and return
@ -406,17 +416,25 @@ Golden file $filename did not match the image generated by the test.
'</script>.');
}
if (_closed) return null;
if (_closed) {
return null;
}
Uri suiteUrl = url.resolveUri(
p.toUri(p.withoutExtension(p.relative(path, from: _root)) + '.html'));
if (_closed) return null;
if (_closed) {
return null;
}
var browserManager = await _browserManagerFor(browser);
if (_closed || browserManager == null) return null;
if (_closed || browserManager == null) {
return null;
}
var suite = await browserManager.load(path, suiteUrl, suiteConfig, message);
if (_closed) return null;
if (_closed) {
return null;
}
return suite;
}
@ -429,14 +447,16 @@ Golden file $filename did not match the image generated by the test.
///
/// If no browser manager is running yet, starts one.
Future<BrowserManager> _browserManagerFor(Runtime browser) {
if (_browserManager != null) return _browserManager;
if (_browserManager != null) {
return _browserManager;
}
var completer = Completer<WebSocketChannel>.sync();
var path = _webSocketHandler.create(webSocketHandler(completer.complete));
var webSocketUrl = url.replace(scheme: 'ws').resolve(path);
var hostUrl = (_config.pubServeUrl == null ? url : _config.pubServeUrl)
.resolve('packages/web_engine_tester/static/index.html')
.replace(queryParameters: {
.replace(queryParameters: <String, dynamic>{
'managerUrl': webSocketUrl.toString(),
'debug': _config.pauseAfterLoad.toString()
});
@ -446,7 +466,7 @@ Golden file $filename did not match the image generated by the test.
// Store null values for browsers that error out so we know not to load them
// again.
_browserManager = future.catchError((_) => null);
_browserManager = future.catchError((dynamic _) => null);
return future;
}
@ -485,7 +505,7 @@ Golden file $filename did not match the image generated by the test.
});
}
final _closeMemo = AsyncMemoizer();
final AsyncMemoizer<dynamic> _closeMemo = AsyncMemoizer<dynamic>();
}
/// A Shelf handler that provides support for one-time handlers.
@ -518,11 +538,15 @@ class OneOffHandler {
/// Dispatches [request] to the appropriate handler.
FutureOr<shelf.Response> _onRequest(shelf.Request request) {
var components = p.url.split(request.url.path);
if (components.isEmpty) return shelf.Response.notFound(null);
if (components.isEmpty) {
return shelf.Response.notFound(null);
}
var path = components.removeAt(0);
var handler = _handlers.remove(path);
if (handler == null) return shelf.Response.notFound(null);
if (handler == null) {
return shelf.Response.notFound(null);
}
return handler(request.change(path: path));
}
}
@ -563,13 +587,19 @@ class PathHandler {
var components = p.url.split(request.url.path);
for (var i = 0; i < components.length; i++) {
node = node.children[components[i]];
if (node == null) break;
if (node.handler == null) continue;
if (node == null) {
break;
}
if (node.handler == null) {
continue;
}
handler = node.handler;
handlerIndex = i;
}
if (handler == null) return shelf.Response.notFound('Not found.');
if (handler == null) {
return shelf.Response.notFound('Not found.');
}
return handler(
request.change(path: p.url.joinAll(components.take(handlerIndex + 1))));
@ -623,7 +653,7 @@ class BrowserManager {
CancelableCompleter _pauseCompleter;
/// The controller for [_BrowserEnvironment.onRestart].
final _onRestartController = StreamController.broadcast();
final _onRestartController = StreamController<dynamic>.broadcast();
/// The environment to attach to each suite.
Future<_BrowserEnvironment> _environment;
@ -660,17 +690,23 @@ class BrowserManager {
browser.onExit.then((_) {
throw Exception('${runtime.name} exited before connecting.');
}).catchError((error, StackTrace stackTrace) {
if (completer.isCompleted) return;
}).catchError((dynamic error, StackTrace stackTrace) {
if (completer.isCompleted) {
return;
}
completer.completeError(error, stackTrace);
});
future.then((webSocket) {
if (completer.isCompleted) return;
if (completer.isCompleted) {
return;
}
completer.complete(BrowserManager._(browser, runtime, webSocket));
}).catchError((error, StackTrace stackTrace) {
}).catchError((dynamic error, StackTrace stackTrace) {
browser.close();
if (completer.isCompleted) return;
if (completer.isCompleted) {
return;
}
completer.completeError(error, stackTrace);
});
@ -683,8 +719,7 @@ class BrowserManager {
/// Starts the browser identified by [browser] using [settings] and has it load [url].
///
/// If [debug] is true, starts the browser in debug mode.
static Browser _newBrowser(Uri url, Runtime browser,
{bool debug = false}) {
static Browser _newBrowser(Uri url, Runtime browser, {bool debug = false}) {
return SupportedBrowsers.instance.getBrowser(browser, url, debug: debug);
}
@ -706,10 +741,12 @@ class BrowserManager {
// Whenever we get a message, no matter which child channel it's for, we the
// know browser is still running code which means the user isn't debugging.
_channel = MultiChannel(
_channel = MultiChannel<dynamic>(
webSocket.cast<String>().transform(jsonDocument).changeStream((stream) {
return stream.map((message) {
if (!_closed) _timer.reset();
if (!_closed) {
_timer.reset();
}
for (var controller in _controllers) {
controller.setDebugging(false);
}
@ -720,7 +757,7 @@ class BrowserManager {
_environment = _loadBrowserEnvironment();
_channel.stream
.listen((message) => _onMessage(message as Map), onDone: close);
.listen((dynamic message) => _onMessage(message as Map), onDone: close);
}
/// Loads [_BrowserEnvironment].
@ -737,7 +774,7 @@ class BrowserManager {
Future<RunnerSuite> load(String path, Uri url, SuiteConfiguration suiteConfig,
Object message) async {
url = url.replace(
fragment: Uri.encodeFull(jsonEncode({
fragment: Uri.encodeFull(jsonEncode(<String, dynamic>{
'metadata': suiteConfig.metadata.serialize(),
'browser': _runtime.identifier
})));
@ -745,7 +782,9 @@ class BrowserManager {
var suiteID = _suiteID++;
RunnerSuiteController controller;
void closeIframe() {
if (_closed) return;
if (_closed) {
return;
}
_controllers.remove(controller);
_channel.sink.add({'command': 'closeSuite', 'id': suiteID});
}
@ -754,8 +793,8 @@ class BrowserManager {
// case we should unload the iframe.
var virtualChannel = _channel.virtualChannel();
var suiteChannelID = virtualChannel.id;
var suiteChannel = virtualChannel
.transformStream(StreamTransformer.fromHandlers(handleDone: (sink) {
var suiteChannel = virtualChannel.transformStream(
StreamTransformer<dynamic, dynamic>.fromHandlers(handleDone: (sink) {
closeIframe();
sink.close();
}));
@ -797,9 +836,11 @@ class BrowserManager {
/// An implementation of [Environment.displayPause].
CancelableOperation _displayPause() {
if (_pauseCompleter != null) return _pauseCompleter.operation;
if (_pauseCompleter != null) {
return _pauseCompleter.operation;
}
_pauseCompleter = CancelableCompleter(onCancel: () {
_pauseCompleter = CancelableCompleter<void>(onCancel: () {
_channel.sink.add({'command': 'resume'});
_pauseCompleter = null;
});
@ -824,7 +865,9 @@ class BrowserManager {
break;
case 'resume':
if (_pauseCompleter != null) _pauseCompleter.complete();
if (_pauseCompleter != null) {
_pauseCompleter.complete();
}
break;
default:
@ -839,12 +882,14 @@ class BrowserManager {
Future close() => _closeMemoizer.runOnce(() {
_closed = true;
_timer.cancel();
if (_pauseCompleter != null) _pauseCompleter.complete();
if (_pauseCompleter != null) {
_pauseCompleter.complete();
}
_pauseCompleter = null;
_controllers.clear();
return _browser.close();
});
final _closeMemoizer = AsyncMemoizer();
final AsyncMemoizer<dynamic> _closeMemoizer = AsyncMemoizer<dynamic>();
}
/// An implementation of [Environment] for the browser.

View File

@ -33,7 +33,7 @@ enum TestTypesRequested {
all,
}
class TestCommand extends Command<bool> {
class TestCommand extends Command<bool> with ArgUtils {
TestCommand() {
argParser
..addFlag(
@ -84,13 +84,13 @@ class TestCommand extends Command<bool> {
/// Check the flags to see what type of tests are requested.
TestTypesRequested findTestType() {
if (argResults['unit-tests-only'] && argResults['integration-tests-only']) {
if (boolArg('unit-tests-only') && boolArg('integration-tests-only')) {
throw ArgumentError('Conflicting arguments: unit-tests-only and '
'integration-tests-only are both set');
} else if (argResults['unit-tests-only']) {
} else if (boolArg('unit-tests-only')) {
print('Running the unit tests only');
return TestTypesRequested.unit;
} else if (argResults['integration-tests-only']) {
} else if (boolArg('integration-tests-only')) {
if (!isChrome) {
throw UnimplementedError(
'Integration tests are only available on Chrome Desktop for now');
@ -163,7 +163,7 @@ class TestCommand extends Command<bool> {
///
/// In this mode the browser pauses before running the test to allow
/// you set breakpoints or inspect the code.
bool get isDebug => argResults['debug'];
bool get isDebug => boolArg('debug');
/// Paths to targets to run, e.g. a single test.
List<String> get targets => argResults.rest;
@ -178,13 +178,15 @@ class TestCommand extends Command<bool> {
/// Whether all tests should run.
bool get runAllTests => targets.isEmpty;
String get browser => argResults['browser'];
/// The name of the browser to run tests in.
String get browser => stringArg('browser');
bool get isChrome => argResults['browser'] == 'chrome';
/// Whether [browser] is set to "chrome".
bool get isChrome => browser == 'chrome';
/// When running screenshot tests writes them to the file system into
/// ".dart_tool/goldens".
bool get doUpdateScreenshotGoldens => argResults['update-screenshot-goldens'];
bool get doUpdateScreenshotGoldens => boolArg('update-screenshot-goldens');
Future<void> _runTargetTests(List<FilePath> targets) async {
await _runTestBatch(targets, concurrency: 1, expectFailure: false);

View File

@ -6,6 +6,7 @@
import 'dart:async';
import 'dart:io' as io;
import 'package:args/command_runner.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
@ -97,14 +98,14 @@ Future<String> evalProcess(
);
if (result.exitCode != 0) {
throw ProcessException(
description: result.stderr,
description: result.stderr as String,
executable: executable,
arguments: arguments,
workingDirectory: workingDirectory,
exitCode: result.exitCode,
);
}
return result.stdout;
return result.stdout as String;
}
@immutable
@ -134,3 +135,29 @@ class ProcessException implements Exception {
return '$message';
}
}
/// Adds utility methods
mixin ArgUtils<T> on Command<T> {
/// Extracts a boolean argument from [argResults].
bool boolArg(String name) => argResults[name] as bool;
/// Extracts a string argument from [argResults].
String stringArg(String name) => argResults[name] as String;
/// Extracts a integer argument from [argResults].
///
/// If the argument value cannot be parsed as [int] throws an [ArgumentError].
int intArg(String name) {
final String rawValue = stringArg(name);
if (rawValue == null) {
return null;
}
final int value = int.tryParse(rawValue);
if (value == null) {
throw ArgumentError(
'Argument $name should be an integer value but was "$rawValue"',
);
}
return value;
}
}

View File

@ -768,6 +768,8 @@ List<html.Element> _clipContent(List<_SaveClipEntry> clipStack,
}
String _maskFilterToCss(ui.MaskFilter maskFilter) {
if (maskFilter == null) return 'none';
if (maskFilter == null) {
return 'none';
}
return 'blur(${maskFilter.webOnlySigma}px)';
}

View File

@ -27,7 +27,7 @@ class ClipboardMessageHandler {
callback(codec.encodeErrorEnvelope(
code: 'copy_fail', message: 'Clipboard.setData failed'));
}
}).catchError((_) {
}).catchError((dynamic _) {
callback(codec.encodeErrorEnvelope(
code: 'copy_fail', message: 'Clipboard.setData failed'));
});
@ -37,9 +37,9 @@ class ClipboardMessageHandler {
void getDataMethodCall(ui.PlatformMessageResponseCallback callback) {
const MethodCodec codec = JSONMethodCodec();
_pasteFromClipboardStrategy.getData().then((String data) {
final Map<String, dynamic> map = {'text': data};
final Map<String, dynamic> map = <String, dynamic>{'text': data};
callback(codec.encodeSuccessEnvelope(map));
}).catchError((error) {
}).catchError((dynamic error) {
print('Could not get text from clipboard: $error');
callback(codec.encodeErrorEnvelope(
code: 'paste_fail', message: 'Clipboard.getData failed'));

View File

@ -145,7 +145,7 @@ class CanvasKitCanvas implements ui.Canvas {
_drawLine(p1, p2, paint);
}
void _drawLine(ui.Offset p1, ui.Offset p2, paint) {
void _drawLine(ui.Offset p1, ui.Offset p2, ui.Paint paint) {
_canvas.drawLine(p1, p2, paint);
}

View File

@ -19,7 +19,7 @@ class SkColorFilter {
SkColorFilter.matrix(EngineColorFilter filter) {
// TODO(het): Find a way to remove these array conversions.
final js.JsArray colorMatrix = js.JsArray();
final js.JsArray<double> colorMatrix = js.JsArray<double>();
colorMatrix.length = 20;
for (int i = 0; i < 20; i++) {
colorMatrix[i] = filter._matrix[i];

View File

@ -316,7 +316,9 @@ class HtmlViewEmbedder {
/// Ensures we add a container of SVG path defs to the DOM so they can
/// be referred to in clip-path: url(#blah).
void _ensureSvgPathDefs() {
if (_svgPathDefs != null) return;
if (_svgPathDefs != null) {
return;
}
_svgPathDefs = html.Element.html(
'<svg width="0" height="0"><defs id="sk_path_defs"></defs></svg>',
treeSanitizer: _NullTreeSanitizer(),
@ -399,8 +401,12 @@ class EmbeddedViewParams {
final MutatorsStack mutators;
bool operator ==(dynamic other) {
if (identical(this, other)) return true;
if (other is! EmbeddedViewParams) return false;
if (identical(this, other)) {
return true;
}
if (other is! EmbeddedViewParams) {
return false;
}
EmbeddedViewParams typedOther = other;
return offset == typedOther.offset &&
@ -456,8 +462,12 @@ class Mutator {
double get alphaFloat => alpha / 255.0;
bool operator ==(dynamic other) {
if (identical(this, other)) return true;
if (other is! Mutator) return false;
if (identical(this, other)) {
return true;
}
if (other is! Mutator) {
return false;
}
final Mutator typedOther = other;
if (type != typedOther.type) {
@ -517,8 +527,12 @@ class MutatorsStack extends Iterable<Mutator> {
}
bool operator ==(dynamic other) {
if (identical(other, this)) return true;
if (other is! MutatorsStack) return false;
if (identical(other, this)) {
return true;
}
if (other is! MutatorsStack) {
return false;
}
final MutatorsStack typedOther = other;
if (_mutators.length != typedOther._mutators.length) {

View File

@ -47,7 +47,9 @@ class SkiaFontCollection {
/// Loads all of the unloaded fonts in [_unloadedFonts] and adds them
/// to [_registeredFonts].
Future<void> _loadFonts() async {
if (_unloadedFonts.isEmpty) return;
if (_unloadedFonts.isEmpty) {
return;
}
final List<_RegisteredFont> loadedFonts = await Future.wait(_unloadedFonts);
_registeredFonts.addAll(loadedFonts.where((x) => x != null));
@ -174,7 +176,8 @@ class SkiaFontCollection {
}
Future<ByteBuffer> _getArrayBuffer(dynamic fetchResult) {
return fetchResult.arrayBuffer().then<ByteBuffer>((x) => x as ByteBuffer);
// TODO(yjbanov): fetchResult.arrayBuffer is a dynamic invocation. Clean it up.
return fetchResult.arrayBuffer().then<ByteBuffer>((dynamic x) => x as ByteBuffer);
}
js.JsObject skFontMgr;

View File

@ -50,7 +50,9 @@ class Surface {
final SkSurface surface = acquireRenderSurface(size);
canvasKit.callMethod('setCurrentContext', <int>[surface.context]);
if (surface == null) return null;
if (surface == null) {
return null;
}
SubmitCallback submitCallback =
(SurfaceFrame surfaceFrame, SkCanvas canvas) {
@ -115,7 +117,7 @@ class Surface {
final int glContext = canvasKit
.callMethod('GetWebGLContext', <html.CanvasElement>[htmlCanvas]);
final js.JsObject grContext =
canvasKit.callMethod('MakeGrContext', [glContext]);
canvasKit.callMethod('MakeGrContext', <dynamic>[glContext]);
final js.JsObject skSurface =
canvasKit.callMethod('MakeOnScreenGLSurface', <dynamic>[
grContext,
@ -137,7 +139,7 @@ class Surface {
return false;
}
canvasKit.callMethod('setCurrentContext', [_surface.context]);
canvasKit.callMethod('setCurrentContext', <dynamic>[_surface.context]);
_surface.getCanvas().flush();
return true;
}

View File

@ -8,7 +8,9 @@ part of engine;
Int32List _encodeColorList(List<ui.Color> colors) {
final int colorCount = colors.length;
final Int32List result = Int32List(colorCount);
for (int i = 0; i < colorCount; ++i) result[i] = colors[i].value;
for (int i = 0; i < colorCount; ++i) {
result[i] = colors[i].value;
}
return result;
}
@ -117,7 +119,9 @@ class SkVertices implements ui.Vertices {
}
static js.JsArray<js.JsArray<double>> _encodePoints(List<double> points) {
if (points == null) return null;
if (points == null) {
return null;
}
js.JsArray<js.JsArray<double>> encodedPoints =
js.JsArray<js.JsArray<double>>();

View File

@ -71,7 +71,7 @@ class DomRenderer {
/// This getter calls the `hasFocus` method of the `Document` interface.
/// See for more details:
/// https://developer.mozilla.org/en-US/docs/Web/API/Document/hasFocus
bool get windowHasFocus => js_util.callMethod(html.document, 'hasFocus', []);
bool get windowHasFocus => js_util.callMethod(html.document, 'hasFocus', <dynamic>[]);
void _setupHotRestart() {
// This persists across hot restarts to clear stale DOM.

View File

@ -49,7 +49,7 @@ class HtmlCodec implements ui.Codec {
imgElement.naturalHeight,
);
completer.complete(SingleFrameInfo(image));
}).catchError((e) {
}).catchError((dynamic e) {
// This code path is hit on Chrome 80.0.3987.16 when too many
// images are on the page (~1000).
// Fallback here is to load using onLoad instead.

View File

@ -145,7 +145,7 @@ class _WebGlRenderer implements _GlRenderer {
gl.bindArrayBuffer(positionsBuffer);
gl.bufferData(positions, gl.kStaticDraw);
js_util.callMethod(
gl.glContext, 'vertexAttribPointer', [0, 2, gl.kFloat, false, 0, 0]);
gl.glContext, 'vertexAttribPointer', <dynamic>[0, 2, gl.kFloat, false, 0, 0]);
gl.enableVertexAttribArray(0);
// Setup color buffer.
@ -155,7 +155,7 @@ class _WebGlRenderer implements _GlRenderer {
gl.bufferData(vertices.colors, gl.kStaticDraw);
js_util.callMethod(gl.glContext, 'vertexAttribPointer',
[1, 4, gl.kUnsignedByte, true, 0, 0]);
<dynamic>[1, 4, gl.kUnsignedByte, true, 0, 0]);
gl.enableVertexAttribArray(1);
gl.clear();
final int vertexCount = positions.length ~/ 2;
@ -317,7 +317,7 @@ class _GlContext {
static Map<String, _GlProgram> _programCache;
_GlContext.fromOffscreenCanvas(html.OffscreenCanvas canvas)
: glContext = canvas.getContext('webgl2', {'premultipliedAlpha': false}),
: glContext = canvas.getContext('webgl2', <String, dynamic>{'premultipliedAlpha': false}),
isOffscreen = true {
_programCache = <String, _GlProgram>{};
_canvas = canvas;
@ -325,7 +325,7 @@ class _GlContext {
_GlContext.fromCanvas(html.CanvasElement canvas, bool useWebGl1)
: glContext = canvas.getContext(useWebGl1 ? 'webgl' : 'webgl2',
{'premultipliedAlpha': false}),
<String, dynamic>{'premultipliedAlpha': false}),
isOffscreen = false {
_programCache = <String, _GlProgram>{};
_canvas = canvas;
@ -342,7 +342,7 @@ class _GlContext {
// Actual size of canvas may be larger than viewport size. Use
// source/destination to draw part of the image data.
js_util.callMethod(context, 'drawImage',
[_canvas, 0, 0, _widthInPixels, _heightInPixels,
<dynamic>[_canvas, 0, 0, _widthInPixels, _heightInPixels,
left, top, _widthInPixels, _heightInPixels]);
}
@ -372,10 +372,10 @@ class _GlContext {
if (shader == null) {
throw Exception(error);
}
js_util.callMethod(glContext, 'shaderSource', [shader, source]);
js_util.callMethod(glContext, 'compileShader', [shader]);
js_util.callMethod(glContext, 'shaderSource', <dynamic>[shader, source]);
js_util.callMethod(glContext, 'compileShader', <dynamic>[shader]);
bool shaderStatus = js_util
.callMethod(glContext, 'getShaderParameter', [shader, compileStatus]);
.callMethod(glContext, 'getShaderParameter', <dynamic>[shader, compileStatus]);
if (!shaderStatus) {
throw Exception('Shader compilation failed: ${getShaderInfoLog(shader)}');
}
@ -383,73 +383,73 @@ class _GlContext {
}
Object createProgram() =>
js_util.callMethod(glContext, 'createProgram', const []);
js_util.callMethod(glContext, 'createProgram', const <dynamic>[]);
void attachShader(Object program, Object shader) {
js_util.callMethod(glContext, 'attachShader', [program, shader]);
js_util.callMethod(glContext, 'attachShader', <dynamic>[program, shader]);
}
void linkProgram(Object program) {
js_util.callMethod(glContext, 'linkProgram', [program]);
js_util.callMethod(glContext, 'linkProgram', <dynamic>[program]);
if (!js_util
.callMethod(glContext, 'getProgramParameter', [program, kLinkStatus])) {
.callMethod(glContext, 'getProgramParameter', <dynamic>[program, kLinkStatus])) {
throw Exception(getProgramInfoLog(program));
}
}
void useProgram(Object program) {
js_util.callMethod(glContext, 'useProgram', [program]);
js_util.callMethod(glContext, 'useProgram', <dynamic>[program]);
}
Object createBuffer() =>
js_util.callMethod(glContext, 'createBuffer', const []);
js_util.callMethod(glContext, 'createBuffer', const <dynamic>[]);
void bindArrayBuffer(Object buffer) {
js_util.callMethod(glContext, 'bindBuffer', [kArrayBuffer, buffer]);
js_util.callMethod(glContext, 'bindBuffer', <dynamic>[kArrayBuffer, buffer]);
}
void deleteBuffer(Object buffer) {
js_util.callMethod(glContext, 'deleteBuffer', [buffer]);
js_util.callMethod(glContext, 'deleteBuffer', <dynamic>[buffer]);
}
void bufferData(TypedData data, dynamic type) {
js_util.callMethod(glContext, 'bufferData', [kArrayBuffer, data, type]);
js_util.callMethod(glContext, 'bufferData', <dynamic>[kArrayBuffer, data, type]);
}
void enableVertexAttribArray(int index) {
js_util.callMethod(glContext, 'enableVertexAttribArray', [index]);
js_util.callMethod(glContext, 'enableVertexAttribArray', <dynamic>[index]);
}
/// Clear background.
void clear() {
js_util.callMethod(glContext, 'clear', [kColorBufferBit]);
js_util.callMethod(glContext, 'clear', <dynamic>[kColorBufferBit]);
}
/// Destroys gl context.
void dispose() {
js_util.callMethod(_getExtension('WEBGL_lose_context'), 'loseContext', []);
js_util.callMethod(_getExtension('WEBGL_lose_context'), 'loseContext', const <dynamic>[]);
}
void deleteProgram(Object program) {
js_util.callMethod(glContext, 'deleteProgram', [program]);
js_util.callMethod(glContext, 'deleteProgram', <dynamic>[program]);
}
void deleteShader(Object shader) {
js_util.callMethod(glContext, 'deleteShader', [shader]);
js_util.callMethod(glContext, 'deleteShader', <dynamic>[shader]);
}
dynamic _getExtension(String extensionName) =>
js_util.callMethod(glContext, 'getExtension', [extensionName]);
js_util.callMethod(glContext, 'getExtension', <dynamic>[extensionName]);
void drawTriangles(int triangleCount, ui.VertexMode vertexMode) {
dynamic mode = _triangleTypeFromMode(vertexMode);
js_util.callMethod(glContext, 'drawArrays', [mode, 0, triangleCount]);
js_util.callMethod(glContext, 'drawArrays', <dynamic>[mode, 0, triangleCount]);
}
/// Sets affine transformation from normalized device coordinates
/// to window coordinates
void viewport(double x, double y, double width, double height) {
js_util.callMethod(glContext, 'viewport', [x, y, width, height]);
js_util.callMethod(glContext, 'viewport', <dynamic>[x, y, width, height]);
}
dynamic _triangleTypeFromMode(ui.VertexMode mode) {
@ -467,10 +467,10 @@ class _GlContext {
}
Object _createShader(String shaderType) => js_util.callMethod(
glContext, 'createShader', [js_util.getProperty(glContext, shaderType)]);
glContext, 'createShader', <dynamic>[js_util.getProperty(glContext, shaderType)]);
/// Error state of gl context.
dynamic get error => js_util.callMethod(glContext, 'getError', const []);
dynamic get error => js_util.callMethod(glContext, 'getError', const <dynamic>[]);
/// Shader compiler error, if this returns [kFalse], to get details use
/// [getShaderInfoLog].
@ -508,37 +508,37 @@ class _GlContext {
/// Returns reference to uniform in program.
Object getUniformLocation(Object program, String uniformName) {
return js_util
.callMethod(glContext, 'getUniformLocation', [program, uniformName]);
.callMethod(glContext, 'getUniformLocation', <dynamic>[program, uniformName]);
}
/// Sets vec2 uniform values.
void setUniform2f(Object uniform, double value1, double value2) {
return js_util
.callMethod(glContext, 'uniform2f', [uniform, value1, value2]);
.callMethod(glContext, 'uniform2f', <dynamic>[uniform, value1, value2]);
}
/// Sets vec4 uniform values.
void setUniform4f(Object uniform, double value1, double value2, double value3,
double value4) {
return js_util.callMethod(
glContext, 'uniform4f', [uniform, value1, value2, value3, value4]);
glContext, 'uniform4f', <dynamic>[uniform, value1, value2, value3, value4]);
}
/// Sets mat4 uniform values.
void setUniformMatrix4fv(Object uniform, bool transpose, Float64List value) {
return js_util.callMethod(
glContext, 'uniformMatrix4fv', [uniform, transpose, value]);
glContext, 'uniformMatrix4fv', <dynamic>[uniform, transpose, value]);
}
/// Shader compile error log.
dynamic getShaderInfoLog(Object glShader) {
return js_util.callMethod(glContext, 'getShaderInfoLog', [glShader]);
return js_util.callMethod(glContext, 'getShaderInfoLog', <dynamic>[glShader]);
}
/// Errors that occurred during failed linking or validation of program
/// objects. Typically called after [linkProgram].
String getProgramInfoLog(Object glProgram) {
return js_util.callMethod(glContext, 'getProgramInfoLog', [glProgram]);
return js_util.callMethod(glContext, 'getProgramInfoLog', <dynamic>[glProgram]);
}
int get drawingBufferWidth =>
@ -555,7 +555,7 @@ class _GlContext {
final Uint8List pixels =
Uint8List(bufferWidth * bufferHeight * kBytesPerPixel);
js_util.callMethod(glContext, 'readPixels',
[0, 0, bufferWidth, bufferHeight, kRGBA, kUnsignedByte, pixels]);
<dynamic>[0, 0, bufferWidth, bufferHeight, kRGBA, kUnsignedByte, pixels]);
return html.ImageData(
Uint8ClampedList.fromList(pixels), bufferWidth, bufferHeight);
} else {
@ -565,7 +565,7 @@ class _GlContext {
final Uint8ClampedList pixels =
Uint8ClampedList(bufferWidth * bufferHeight * kBytesPerPixel);
js_util.callMethod(glContext, 'readPixels',
[0, 0, bufferWidth, bufferHeight, kRGBA, kUnsignedByte, pixels]);
<dynamic>[0, 0, bufferWidth, bufferHeight, kRGBA, kUnsignedByte, pixels]);
return html.ImageData(pixels, bufferWidth, bufferHeight);
}
}

View File

@ -45,7 +45,7 @@ const double kLightOffsetY = -400.0;
/// This is not a complete physical model. For example, this does not take into
/// account the size of the shape (this function doesn't even take the shape as
/// a parameter). It's just a good enough approximation.
ui.Offset computeShadowOffset(elevation) {
ui.Offset computeShadowOffset(double elevation) {
if (elevation == 0.0) {
return ui.Offset.zero;
}

View File

@ -924,8 +924,8 @@ class MeasurementResult {
@required this.alphabeticBaseline,
@required this.ideographicBaseline,
@required this.lines,
@required textAlign,
@required textDirection,
@required ui.TextAlign textAlign,
@required ui.TextDirection textDirection,
}) : assert(constraintWidth != null),
assert(isSingleLine != null),
assert(width != null),

View File

@ -963,7 +963,9 @@ class Canvas {
}
void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) {
if (vertices == null) return;
if (vertices == null) {
return;
}
//assert(vertices != null); // vertices is checked on the engine side
assert(paint != null);
assert(blendMode != null);

View File

@ -1105,8 +1105,12 @@ class TextRange {
@override
bool operator ==(dynamic other) {
if (identical(this, other)) return true;
if (other is! TextRange) return false;
if (identical(this, other)) {
return true;
}
if (other is! TextRange) {
return false;
}
final TextRange typedOther = other;
return typedOther.start == start && typedOther.end == end;
}

View File

@ -485,8 +485,12 @@ class Locale {
String _rawToString(String separator) {
final StringBuffer out = StringBuffer(languageCode);
if (scriptCode != null) out.write('$separator$scriptCode');
if (_countryCode != null) out.write('$separator$countryCode');
if (scriptCode != null) {
out.write('$separator$scriptCode');
}
if (_countryCode != null) {
out.write('$separator$countryCode');
}
return out.toString();
}
}

View File

@ -171,7 +171,7 @@ void main() {
await _strategy.simulateUserTypingUrl('/page3');
// This delay is necessary to wait for [BrowserHistory] because it
// performs a `back` operation which results in a new event loop.
await Future.delayed(Duration.zero);
await Future<void>.delayed(Duration.zero);
// 1. The engine sends a `pushRoute` platform message.
expect(spy.messages, hasLength(1));
expect(spy.messages[0].channel, 'flutter/navigation');
@ -212,7 +212,7 @@ void main() {
await _strategy.simulateUserTypingUrl('/unknown');
// This delay is necessary to wait for [BrowserHistory] because it
// performs a `back` operation which results in a new event loop.
await Future.delayed(Duration.zero);
await Future<void>.delayed(Duration.zero);
// 1. The engine sends a `pushRoute` platform message.
expect(spy.messages, hasLength(1));
expect(spy.messages[0].channel, 'flutter/navigation');

View File

@ -1970,7 +1970,7 @@ class _TouchEventContext extends _BasicEventContext with _MultiPointerEventMixin
double clientX,
double clientY,
}) {
return html.Touch({
return html.Touch(<String, dynamic>{
'identifier': identifier,
'clientX': clientX,
'clientY': clientY,
@ -1979,7 +1979,7 @@ class _TouchEventContext extends _BasicEventContext with _MultiPointerEventMixin
}
html.TouchEvent _createTouchEvent(String eventType, List<_TouchDetails> touches) {
return html.TouchEvent(eventType, {
return html.TouchEvent(eventType, <String, dynamic>{
'changedTouches': touches.map(
(_TouchDetails details) =>
_createTouch(
@ -2138,7 +2138,7 @@ class _PointerEventContext extends _BasicEventContext with _ButtonedEventMixin i
}
html.Event _downWithFullDetails({double clientX, double clientY, int button, int buttons, int pointer, String pointerType}) {
return html.PointerEvent('pointerdown', {
return html.PointerEvent('pointerdown', <String, dynamic>{
'pointerId': pointer,
'button': button,
'buttons': buttons,
@ -2173,7 +2173,7 @@ class _PointerEventContext extends _BasicEventContext with _ButtonedEventMixin i
}
html.Event _moveWithFullDetails({double clientX, double clientY, int button, int buttons, int pointer, String pointerType}) {
return html.PointerEvent('pointermove', {
return html.PointerEvent('pointermove', <String, dynamic>{
'pointerId': pointer,
'button': button,
'buttons': buttons,
@ -2206,7 +2206,7 @@ class _PointerEventContext extends _BasicEventContext with _ButtonedEventMixin i
}
html.Event _upWithFullDetails({double clientX, double clientY, int button, int pointer, String pointerType}) {
return html.PointerEvent('pointerup', {
return html.PointerEvent('pointerup', <String, dynamic>{
'pointerId': pointer,
'button': button,
'buttons': 0,
@ -2218,7 +2218,7 @@ class _PointerEventContext extends _BasicEventContext with _ButtonedEventMixin i
@override
List<html.Event> multiTouchCancel(List<_TouchDetails> touches) {
return touches.map((_TouchDetails details) => html.PointerEvent('pointercancel', {
return touches.map((_TouchDetails details) => html.PointerEvent('pointercancel', <String, dynamic>{
'pointerId': details.pointer,
'button': 0,
'buttons': 0,

View File

@ -27,7 +27,7 @@ void main() {
underTest.drawDRRect(rrect, rrect.deflate(1), somePaint);
underTest.apply(mockCanvas);
_expectDrawCall(mockCanvas, {
_expectDrawCall(mockCanvas, <String, dynamic>{
'outer': rrect,
'inner': rrect.deflate(1),
'paint': somePaint.paintData,
@ -75,7 +75,7 @@ void main() {
underTest.apply(mockCanvas);
// Expect to draw, even when inner has negative radii (which get ignored by canvas)
_expectDrawCall(mockCanvas, {
_expectDrawCall(mockCanvas, <String, dynamic>{
'outer': outer,
'inner': inner,
'paint': somePaint.paintData,
@ -91,7 +91,7 @@ void main() {
underTest.drawDRRect(outer, inner, somePaint);
underTest.apply(mockCanvas);
_expectDrawCall(mockCanvas, {
_expectDrawCall(mockCanvas, <String, dynamic>{
'outer': outer,
'inner': inner,
'paint': somePaint.paintData,

View File

@ -135,6 +135,6 @@ HtmlImage createTestImage() {
ctx.fillRect(66, 0, 33, 50);
ctx.fill();
html.ImageElement imageElement = html.ImageElement();
imageElement.src = js_util.callMethod(canvas, 'toDataURL', []);
imageElement.src = js_util.callMethod(canvas, 'toDataURL', <dynamic>[]);
return HtmlImage(imageElement, width, height);
}

View File

@ -101,6 +101,6 @@ engine.HtmlImage createTestImage({int width = 200, int height = 150}) {
ctx.fillRect(2 * width / 3, 0, width / 3, height);
ctx.fill();
html.ImageElement imageElement = html.ImageElement();
imageElement.src = js_util.callMethod(canvas, 'toDataURL', []);
imageElement.src = js_util.callMethod(canvas, 'toDataURL', <dynamic>[]);
return engine.HtmlImage(imageElement, width, height);
}

View File

@ -326,6 +326,6 @@ HtmlImage createTestImage({int width = 100, int height = 50}) {
ctx.fillRect(66, 0, 33, 50);
ctx.fill();
html.ImageElement imageElement = html.ImageElement();
imageElement.src = js_util.callMethod(canvas, 'toDataURL', []);
imageElement.src = js_util.callMethod(canvas, 'toDataURL', <dynamic>[]);
return HtmlImage(imageElement, width, height);
}