| // 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. |
| |
| /// This library defines the web equivalent of the native dart:ui. |
| /// |
| /// All types in this library are public. |
| // @dart = 2.12 |
| library ui; |
| |
| import 'dart:async'; |
| import 'dart:collection' as collection; |
| import 'dart:convert'; |
| import 'dart:html' as html; |
| import 'dart:math' as math; |
| import 'dart:typed_data'; |
| |
| import 'src/engine.dart' as engine; |
| |
| part 'src/ui/annotations.dart'; |
| part 'src/ui/canvas.dart'; |
| part 'src/ui/channel_buffers.dart'; |
| part 'src/ui/compositing.dart'; |
| part 'src/ui/geometry.dart'; |
| part 'src/ui/hash_codes.dart'; |
| part 'src/ui/initialization.dart'; |
| part 'src/ui/key.dart'; |
| part 'src/ui/lerp.dart'; |
| part 'src/ui/natives.dart'; |
| part 'src/ui/painting.dart'; |
| part 'src/ui/path.dart'; |
| part 'src/ui/path_metrics.dart'; |
| part 'src/ui/platform_dispatcher.dart'; |
| part 'src/ui/pointer.dart'; |
| part 'src/ui/semantics.dart'; |
| part 'src/ui/test_embedding.dart'; |
| part 'src/ui/text.dart'; |
| part 'src/ui/tile_mode.dart'; |
| part 'src/ui/window.dart'; |
| |
| /// Provides a compile time constant to customize flutter framework and other |
| /// users of ui engine for web runtime. |
| const bool isWeb = true; |
| |
| /// Web specific SMI. Used by bitfield. The 0x3FFFFFFFFFFFFFFF used on VM |
| /// is not supported on Web platform. |
| const int kMaxUnsignedSMI = -1; |
| |
| void webOnlyInitializeEngine() { |
| engine.initializeEngine(); |
| } |
| |
| void webOnlySetPluginHandler(Future<void> Function(String, ByteData?, PlatformMessageResponseCallback?) handler) { |
| engine.pluginMessageCallHandler = handler; |
| } |
| |
| // TODO(yjbanov): The code below was temporarily moved from lib/web_ui/lib/src/engine/platform_views.dart |
| // during the NNBD migration so that `dart:ui` does not have to export `dart:_engine`. NNBD |
| // does not allow exported non-migrated libraries from migrated libraries. When `dart:_engine` |
| // is migrated, we can move it back. |
| |
| /// A registry for factories that create platform views. |
| class PlatformViewRegistry { |
| final Map<String, PlatformViewFactory> registeredFactories = |
| <String, PlatformViewFactory>{}; |
| |
| final Map<int, html.Element> _createdViews = <int, html.Element>{}; |
| |
| /// Private constructor so this class can be a singleton. |
| PlatformViewRegistry._(); |
| |
| /// Register [viewTypeId] as being creating by the given [factory]. |
| bool registerViewFactory(String viewTypeId, PlatformViewFactory factory) { |
| if (registeredFactories.containsKey(viewTypeId)) { |
| return false; |
| } |
| registeredFactories[viewTypeId] = factory; |
| return true; |
| } |
| |
| /// Returns the view that has been created with the given [id], or `null` if |
| /// no such view exists. |
| html.Element? getCreatedView(int id) { |
| return _createdViews[id]; |
| } |
| } |
| |
| /// A function which takes a unique [id] and creates an HTML element. |
| typedef PlatformViewFactory = html.Element Function(int viewId); |
| |
| /// The platform view registry for this app. |
| final PlatformViewRegistry platformViewRegistry = PlatformViewRegistry._(); |
| |
| /// Handles a platform call to `flutter/platform_views`. |
| /// |
| /// Used to create platform views. |
| void handlePlatformViewCall( |
| ByteData data, |
| PlatformMessageResponseCallback callback, |
| ) { |
| const engine.MethodCodec codec = engine.StandardMethodCodec(); |
| final engine.MethodCall decoded = codec.decodeMethodCall(data); |
| |
| switch (decoded.method) { |
| case 'create': |
| _createPlatformView(decoded, callback); |
| return; |
| case 'dispose': |
| _disposePlatformView(decoded, callback); |
| return; |
| } |
| callback(null); |
| } |
| |
| void _createPlatformView( |
| engine.MethodCall methodCall, PlatformMessageResponseCallback callback) { |
| final Map<dynamic, dynamic> args = methodCall.arguments; |
| final int id = args['id']; |
| final String viewType = args['viewType']; |
| const engine.MethodCodec codec = engine.StandardMethodCodec(); |
| |
| // TODO(het): Use 'direction', 'width', and 'height'. |
| final PlatformViewFactory? platformViewFactory = platformViewRegistry.registeredFactories[viewType]; |
| if (platformViewFactory == null) { |
| callback(codec.encodeErrorEnvelope( |
| code: 'Unregistered factory', |
| message: "No factory registered for viewtype '$viewType'", |
| )); |
| return; |
| } |
| // TODO(het): Use creation parameters. |
| final html.Element element = platformViewFactory(id); |
| |
| platformViewRegistry._createdViews[id] = element; |
| callback(codec.encodeSuccessEnvelope(null)); |
| } |
| |
| void _disposePlatformView( |
| engine.MethodCall methodCall, PlatformMessageResponseCallback callback) { |
| final int id = methodCall.arguments; |
| const engine.MethodCodec codec = engine.StandardMethodCodec(); |
| |
| // Remove the root element of the view from the DOM. |
| platformViewRegistry._createdViews[id]?.remove(); |
| platformViewRegistry._createdViews.remove(id); |
| |
| callback(codec.encodeSuccessEnvelope(null)); |
| } |
| |
| // TODO(yjbanov): remove _Callback, _Callbacker, and _futurize. They are here only |
| // because the analyzer wasn't able to infer the correct types during |
| // NNBD migration. |
| typedef _Callback<T> = void Function(T result); |
| typedef _Callbacker<T> = String? Function(_Callback<T> callback); |
| Future<T> _futurize<T>(_Callbacker<T> callbacker) { |
| final Completer<T> completer = Completer<T>.sync(); |
| final String? error = callbacker((T t) { |
| if (t == null) { |
| completer.completeError(Exception('operation failed')); |
| } else { |
| completer.complete(t); |
| } |
| }); |
| if (error != null) { |
| throw Exception(error); |
| } |
| return completer.future; |
| } |