| // 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. |
| |
| part of dart.ui; |
| |
| @pragma('vm:entry-point') |
| void _addView( |
| int viewId, |
| double devicePixelRatio, |
| double width, |
| double height, |
| double viewPaddingTop, |
| double viewPaddingRight, |
| double viewPaddingBottom, |
| double viewPaddingLeft, |
| double viewInsetTop, |
| double viewInsetRight, |
| double viewInsetBottom, |
| double viewInsetLeft, |
| double systemGestureInsetTop, |
| double systemGestureInsetRight, |
| double systemGestureInsetBottom, |
| double systemGestureInsetLeft, |
| double physicalTouchSlop, |
| List<double> displayFeaturesBounds, |
| List<int> displayFeaturesType, |
| List<int> displayFeaturesState, |
| int displayId, |
| ) { |
| final _ViewConfiguration viewConfiguration = _buildViewConfiguration( |
| devicePixelRatio, |
| width, |
| height, |
| viewPaddingTop, |
| viewPaddingRight, |
| viewPaddingBottom, |
| viewPaddingLeft, |
| viewInsetTop, |
| viewInsetRight, |
| viewInsetBottom, |
| viewInsetLeft, |
| systemGestureInsetTop, |
| systemGestureInsetRight, |
| systemGestureInsetBottom, |
| systemGestureInsetLeft, |
| physicalTouchSlop, |
| displayFeaturesBounds, |
| displayFeaturesType, |
| displayFeaturesState, |
| displayId, |
| ); |
| PlatformDispatcher.instance._addView(viewId, viewConfiguration); |
| } |
| |
| @pragma('vm:entry-point') |
| void _removeView(int viewId) { |
| PlatformDispatcher.instance._removeView(viewId); |
| } |
| |
| @pragma('vm:entry-point') |
| void _updateDisplays( |
| List<int> ids, |
| List<double> widths, |
| List<double> heights, |
| List<double> devicePixelRatios, |
| List<double> refreshRates, |
| ) { |
| assert(ids.length == widths.length); |
| assert(ids.length == heights.length); |
| assert(ids.length == devicePixelRatios.length); |
| assert(ids.length == refreshRates.length); |
| final List<Display> displays = <Display>[]; |
| for (int index = 0; index < ids.length; index += 1) { |
| final int displayId = ids[index]; |
| displays.add(Display._( |
| id: displayId, |
| size: Size(widths[index], heights[index]), |
| devicePixelRatio: devicePixelRatios[index], |
| refreshRate: refreshRates[index], |
| )); |
| } |
| |
| PlatformDispatcher.instance._updateDisplays(displays); |
| } |
| |
| List<DisplayFeature> _decodeDisplayFeatures({ |
| required List<double> bounds, |
| required List<int> type, |
| required List<int> state, |
| required double devicePixelRatio, |
| }) { |
| assert(bounds.length / 4 == type.length, 'Bounds are rectangles, requiring 4 measurements each'); |
| assert(type.length == state.length); |
| final List<DisplayFeature> result = <DisplayFeature>[]; |
| for(int i = 0; i < type.length; i++) { |
| final int rectOffset = i * 4; |
| result.add(DisplayFeature( |
| bounds: Rect.fromLTRB( |
| bounds[rectOffset] / devicePixelRatio, |
| bounds[rectOffset + 1] / devicePixelRatio, |
| bounds[rectOffset + 2] / devicePixelRatio, |
| bounds[rectOffset + 3] / devicePixelRatio, |
| ), |
| type: DisplayFeatureType.values[type[i]], |
| state: state[i] < DisplayFeatureState.values.length |
| ? DisplayFeatureState.values[state[i]] |
| : DisplayFeatureState.unknown, |
| )); |
| } |
| return result; |
| } |
| |
| _ViewConfiguration _buildViewConfiguration( |
| double devicePixelRatio, |
| double width, |
| double height, |
| double viewPaddingTop, |
| double viewPaddingRight, |
| double viewPaddingBottom, |
| double viewPaddingLeft, |
| double viewInsetTop, |
| double viewInsetRight, |
| double viewInsetBottom, |
| double viewInsetLeft, |
| double systemGestureInsetTop, |
| double systemGestureInsetRight, |
| double systemGestureInsetBottom, |
| double systemGestureInsetLeft, |
| double physicalTouchSlop, |
| List<double> displayFeaturesBounds, |
| List<int> displayFeaturesType, |
| List<int> displayFeaturesState, |
| int displayId, |
| ) { |
| return _ViewConfiguration( |
| devicePixelRatio: devicePixelRatio, |
| geometry: Rect.fromLTWH(0.0, 0.0, width, height), |
| viewPadding: ViewPadding._( |
| top: viewPaddingTop, |
| right: viewPaddingRight, |
| bottom: viewPaddingBottom, |
| left: viewPaddingLeft, |
| ), |
| viewInsets: ViewPadding._( |
| top: viewInsetTop, |
| right: viewInsetRight, |
| bottom: viewInsetBottom, |
| left: viewInsetLeft, |
| ), |
| padding: ViewPadding._( |
| top: math.max(0.0, viewPaddingTop - viewInsetTop), |
| right: math.max(0.0, viewPaddingRight - viewInsetRight), |
| bottom: math.max(0.0, viewPaddingBottom - viewInsetBottom), |
| left: math.max(0.0, viewPaddingLeft - viewInsetLeft), |
| ), |
| systemGestureInsets: ViewPadding._( |
| top: math.max(0.0, systemGestureInsetTop), |
| right: math.max(0.0, systemGestureInsetRight), |
| bottom: math.max(0.0, systemGestureInsetBottom), |
| left: math.max(0.0, systemGestureInsetLeft), |
| ), |
| gestureSettings: GestureSettings( |
| physicalTouchSlop: physicalTouchSlop == _kUnsetGestureSetting ? null : physicalTouchSlop, |
| ), |
| displayFeatures: _decodeDisplayFeatures( |
| bounds: displayFeaturesBounds, |
| type: displayFeaturesType, |
| state: displayFeaturesState, |
| devicePixelRatio: devicePixelRatio, |
| ), |
| displayId: displayId, |
| ); |
| } |
| |
| @pragma('vm:entry-point') |
| void _updateWindowMetrics( |
| int viewId, |
| double devicePixelRatio, |
| double width, |
| double height, |
| double viewPaddingTop, |
| double viewPaddingRight, |
| double viewPaddingBottom, |
| double viewPaddingLeft, |
| double viewInsetTop, |
| double viewInsetRight, |
| double viewInsetBottom, |
| double viewInsetLeft, |
| double systemGestureInsetTop, |
| double systemGestureInsetRight, |
| double systemGestureInsetBottom, |
| double systemGestureInsetLeft, |
| double physicalTouchSlop, |
| List<double> displayFeaturesBounds, |
| List<int> displayFeaturesType, |
| List<int> displayFeaturesState, |
| int displayId, |
| ) { |
| final _ViewConfiguration viewConfiguration = _buildViewConfiguration( |
| devicePixelRatio, |
| width, |
| height, |
| viewPaddingTop, |
| viewPaddingRight, |
| viewPaddingBottom, |
| viewPaddingLeft, |
| viewInsetTop, |
| viewInsetRight, |
| viewInsetBottom, |
| viewInsetLeft, |
| systemGestureInsetTop, |
| systemGestureInsetRight, |
| systemGestureInsetBottom, |
| systemGestureInsetLeft, |
| physicalTouchSlop, |
| displayFeaturesBounds, |
| displayFeaturesType, |
| displayFeaturesState, |
| displayId, |
| ); |
| PlatformDispatcher.instance._updateWindowMetrics(viewId, viewConfiguration); |
| } |
| |
| typedef _LocaleClosure = String Function(); |
| |
| @pragma('vm:entry-point') |
| _LocaleClosure? _getLocaleClosure() => PlatformDispatcher.instance._localeClosure; |
| |
| @pragma('vm:entry-point') |
| void _updateLocales(List<String> locales) { |
| PlatformDispatcher.instance._updateLocales(locales); |
| } |
| |
| @pragma('vm:entry-point') |
| void _updateUserSettingsData(String jsonData) { |
| PlatformDispatcher.instance._updateUserSettingsData(jsonData); |
| } |
| |
| @pragma('vm:entry-point') |
| void _updateInitialLifecycleState(String state) { |
| PlatformDispatcher.instance._updateInitialLifecycleState(state); |
| } |
| |
| @pragma('vm:entry-point') |
| void _updateSemanticsEnabled(bool enabled) { |
| PlatformDispatcher.instance._updateSemanticsEnabled(enabled); |
| } |
| |
| @pragma('vm:entry-point') |
| void _updateAccessibilityFeatures(int values) { |
| PlatformDispatcher.instance._updateAccessibilityFeatures(values); |
| } |
| |
| @pragma('vm:entry-point') |
| void _dispatchPlatformMessage(String name, ByteData? data, int responseId) { |
| PlatformDispatcher.instance._dispatchPlatformMessage(name, data, responseId); |
| } |
| |
| @pragma('vm:entry-point') |
| void _dispatchPointerDataPacket(ByteData packet) { |
| PlatformDispatcher.instance._dispatchPointerDataPacket(packet); |
| } |
| |
| @pragma('vm:entry-point') |
| void _dispatchSemanticsAction(int nodeId, int action, ByteData? args) { |
| PlatformDispatcher.instance._dispatchSemanticsAction(nodeId, action, args); |
| } |
| |
| @pragma('vm:entry-point') |
| void _beginFrame(int microseconds, int frameNumber) { |
| PlatformDispatcher.instance._beginFrame(microseconds); |
| PlatformDispatcher.instance._updateFrameData(frameNumber); |
| } |
| |
| @pragma('vm:entry-point') |
| void _reportTimings(List<int> timings) { |
| PlatformDispatcher.instance._reportTimings(timings); |
| } |
| |
| @pragma('vm:entry-point') |
| void _drawFrame() { |
| PlatformDispatcher.instance._drawFrame(); |
| } |
| |
| @pragma('vm:entry-point') |
| bool _onError(Object error, StackTrace? stackTrace) { |
| return PlatformDispatcher.instance._dispatchError(error, stackTrace ?? StackTrace.empty); |
| } |
| |
| typedef _ListStringArgFunction = Object? Function(List<String> args); |
| |
| @pragma('vm:entry-point') |
| void _runMain(Function startMainIsolateFunction, |
| Function userMainFunction, |
| List<String> args) { |
| startMainIsolateFunction(() { // ignore: avoid_dynamic_calls |
| if (userMainFunction is _ListStringArgFunction) { |
| userMainFunction(args); |
| } else { |
| userMainFunction(); // ignore: avoid_dynamic_calls |
| } |
| }, null); |
| } |
| |
| /// Invokes [callback] inside the given [zone]. |
| void _invoke(void Function()? callback, Zone zone) { |
| if (callback == null) { |
| return; |
| } |
| if (identical(zone, Zone.current)) { |
| callback(); |
| } else { |
| zone.runGuarded(callback); |
| } |
| } |
| |
| /// Invokes [callback] inside the given [zone] passing it [arg]. |
| /// |
| /// The 1 in the name refers to the number of arguments expected by |
| /// the callback (and thus passed to this function, in addition to the |
| /// callback itself and the zone in which the callback is executed). |
| void _invoke1<A>(void Function(A a)? callback, Zone zone, A arg) { |
| if (callback == null) { |
| return; |
| } |
| if (identical(zone, Zone.current)) { |
| callback(arg); |
| } else { |
| zone.runUnaryGuarded<A>(callback, arg); |
| } |
| } |
| |
| /// Invokes [callback] inside the given [zone] passing it [arg1] and [arg2]. |
| /// |
| /// The 2 in the name refers to the number of arguments expected by |
| /// the callback (and thus passed to this function, in addition to the |
| /// callback itself and the zone in which the callback is executed). |
| void _invoke2<A1, A2>(void Function(A1 a1, A2 a2)? callback, Zone zone, A1 arg1, A2 arg2) { |
| if (callback == null) { |
| return; |
| } |
| if (identical(zone, Zone.current)) { |
| callback(arg1, arg2); |
| } else { |
| zone.runGuarded(() { |
| callback(arg1, arg2); |
| }); |
| } |
| } |
| |
| /// Invokes [callback] inside the given [zone] passing it [arg1], [arg2], and [arg3]. |
| /// |
| /// The 3 in the name refers to the number of arguments expected by |
| /// the callback (and thus passed to this function, in addition to the |
| /// callback itself and the zone in which the callback is executed). |
| void _invoke3<A1, A2, A3>(void Function(A1 a1, A2 a2, A3 a3)? callback, Zone zone, A1 arg1, A2 arg2, A3 arg3) { |
| if (callback == null) { |
| return; |
| } |
| if (identical(zone, Zone.current)) { |
| callback(arg1, arg2, arg3); |
| } else { |
| zone.runGuarded(() { |
| callback(arg1, arg2, arg3); |
| }); |
| } |
| } |
| |
| bool _isLoopback(String host) { |
| if (host.isEmpty) { |
| return false; |
| } |
| if ('localhost' == host) { |
| return true; |
| } |
| try { |
| return InternetAddress(host).isLoopback; |
| } on ArgumentError { |
| return false; |
| } |
| } |
| |
| /// Loopback connections are always allowed. |
| /// Zone override with 'flutter.io.allow_http' takes first priority. |
| /// If zone override is not provided, engine setting is checked. |
| @pragma('vm:entry-point') |
| void Function(Uri) _getHttpConnectionHookClosure(bool mayInsecurelyConnectToAllDomains) { |
| return (Uri uri) { |
| final Object? zoneOverride = Zone.current[#flutter.io.allow_http]; |
| if (zoneOverride == true) { |
| return; |
| } |
| if (zoneOverride == false && uri.isScheme('http')) { |
| // Going to _isLoopback check before throwing |
| } else if (mayInsecurelyConnectToAllDomains || uri.isScheme('https')) { |
| // In absence of zone override, if engine setting allows the connection |
| // or if connection is to `https`, allow the connection. |
| return; |
| } |
| // Loopback connections are always allowed |
| // Check at last resort to avoid debug annoyance of try/on ArgumentError |
| if (_isLoopback(uri.host)) { |
| return; |
| } |
| throw UnsupportedError( |
| 'Non-https connection "$uri" is not supported by the platform. ' |
| 'Refer to https://flutter.dev/docs/release/breaking-changes/network-policy-ios-android.'); |
| }; |
| } |