• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// TODO(dnfield): Remove unused_import ignores when https://github.com/dart-lang/sdk/issues/35164 is resolved.
6
7part of dart.ui;
8
9// ignore: unused_element
10String _decodeUTF8(ByteData message) {
11  return message != null ? utf8.decoder.convert(message.buffer.asUint8List()) : null;
12}
13
14// ignore: unused_element
15dynamic _decodeJSON(String message) {
16  return message != null ? json.decode(message) : null;
17}
18
19@pragma('vm:entry-point')
20// ignore: unused_element
21void _updateWindowMetrics(
22  double devicePixelRatio,
23  double width,
24  double height,
25  double depth,
26  double viewPaddingTop,
27  double viewPaddingRight,
28  double viewPaddingBottom,
29  double viewPaddingLeft,
30  double viewInsetTop,
31  double viewInsetRight,
32  double viewInsetBottom,
33  double viewInsetLeft,
34  double systemGestureInsetTop,
35  double systemGestureInsetRight,
36  double systemGestureInsetBottom,
37  double systemGestureInsetLeft,
38) {
39  window
40    .._devicePixelRatio = devicePixelRatio
41    .._physicalSize = Size(width, height)
42    .._physicalDepth = depth
43    .._viewPadding = WindowPadding._(
44        top: viewPaddingTop,
45        right: viewPaddingRight,
46        bottom: viewPaddingBottom,
47        left: viewPaddingLeft)
48    .._viewInsets = WindowPadding._(
49        top: viewInsetTop,
50        right: viewInsetRight,
51        bottom: viewInsetBottom,
52        left: viewInsetLeft)
53    .._padding = WindowPadding._(
54        top: math.max(0.0, viewPaddingTop - viewInsetTop),
55        right: math.max(0.0, viewPaddingRight - viewInsetRight),
56        bottom: math.max(0.0, viewPaddingBottom - viewInsetBottom),
57        left: math.max(0.0, viewPaddingLeft - viewInsetLeft))
58    .._systemGestureInsets = WindowPadding._(
59        top: math.max(0.0, systemGestureInsetTop),
60        right: math.max(0.0, systemGestureInsetRight),
61        bottom: math.max(0.0, systemGestureInsetBottom),
62        left: math.max(0.0, systemGestureInsetLeft));
63  _invoke(window.onMetricsChanged, window._onMetricsChangedZone);
64}
65
66typedef _LocaleClosure = String Function();
67
68String _localeClosure() {
69  if (window.locale == null) {
70    return null;
71  }
72  return window.locale.toString();
73}
74
75@pragma('vm:entry-point')
76// ignore: unused_element
77_LocaleClosure _getLocaleClosure() => _localeClosure;
78
79@pragma('vm:entry-point')
80// ignore: unused_element
81void _updateLocales(List<String> locales) {
82  const int stringsPerLocale = 4;
83  final int numLocales = locales.length ~/ stringsPerLocale;
84  window._locales = List<Locale>(numLocales);
85  for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
86    final String countryCode = locales[localeIndex * stringsPerLocale + 1];
87    final String scriptCode = locales[localeIndex * stringsPerLocale + 2];
88
89    window._locales[localeIndex] = Locale.fromSubtags(
90      languageCode: locales[localeIndex * stringsPerLocale],
91      countryCode: countryCode.isEmpty ? null : countryCode,
92      scriptCode: scriptCode.isEmpty ? null : scriptCode,
93    );
94  }
95  _invoke(window.onLocaleChanged, window._onLocaleChangedZone);
96}
97
98@pragma('vm:entry-point')
99// ignore: unused_element
100void _updateUserSettingsData(String jsonData) {
101  final Map<String, dynamic> data = json.decode(jsonData);
102  if (data.isEmpty) {
103    return;
104  }
105  _updateTextScaleFactor(data['textScaleFactor'].toDouble());
106  _updateAlwaysUse24HourFormat(data['alwaysUse24HourFormat']);
107  _updatePlatformBrightness(data['platformBrightness']);
108}
109
110@pragma('vm:entry-point')
111// ignore: unused_element
112void _updateLifecycleState(String state) {
113  // We do not update the state if the state has already been used to initialize
114  // the lifecycleState.
115  if (!window._initialLifecycleStateAccessed)
116    window._initialLifecycleState = state;
117}
118
119
120void _updateTextScaleFactor(double textScaleFactor) {
121  window._textScaleFactor = textScaleFactor;
122  _invoke(window.onTextScaleFactorChanged, window._onTextScaleFactorChangedZone);
123}
124
125void _updateAlwaysUse24HourFormat(bool alwaysUse24HourFormat) {
126  window._alwaysUse24HourFormat = alwaysUse24HourFormat;
127}
128
129void _updatePlatformBrightness(String brightnessName) {
130  window._platformBrightness = brightnessName == 'dark' ? Brightness.dark : Brightness.light;
131  _invoke(window.onPlatformBrightnessChanged, window._onPlatformBrightnessChangedZone);
132}
133
134@pragma('vm:entry-point')
135// ignore: unused_element
136void _updateSemanticsEnabled(bool enabled) {
137  window._semanticsEnabled = enabled;
138  _invoke(window.onSemanticsEnabledChanged, window._onSemanticsEnabledChangedZone);
139}
140
141@pragma('vm:entry-point')
142// ignore: unused_element
143void _updateAccessibilityFeatures(int values) {
144  final AccessibilityFeatures newFeatures = AccessibilityFeatures._(values);
145  if (newFeatures == window._accessibilityFeatures)
146    return;
147  window._accessibilityFeatures = newFeatures;
148  _invoke(window.onAccessibilityFeaturesChanged, window._onAccessibilityFlagsChangedZone);
149}
150
151@pragma('vm:entry-point')
152void _dispatchPlatformMessage(String name, ByteData data, int responseId) {
153  if (window.onPlatformMessage != null) {
154    _invoke3<String, ByteData, PlatformMessageResponseCallback>(
155      window.onPlatformMessage,
156      window._onPlatformMessageZone,
157      name,
158      data,
159      (ByteData responseData) {
160        window._respondToPlatformMessage(responseId, responseData);
161      },
162    );
163  } else {
164    window._respondToPlatformMessage(responseId, null);
165  }
166}
167
168@pragma('vm:entry-point')
169// ignore: unused_element
170void _dispatchPointerDataPacket(ByteData packet) {
171  if (window.onPointerDataPacket != null)
172    _invoke1<PointerDataPacket>(window.onPointerDataPacket, window._onPointerDataPacketZone, _unpackPointerDataPacket(packet));
173}
174
175@pragma('vm:entry-point')
176// ignore: unused_element
177void _dispatchSemanticsAction(int id, int action, ByteData args) {
178  _invoke3<int, SemanticsAction, ByteData>(
179    window.onSemanticsAction,
180    window._onSemanticsActionZone,
181    id,
182    SemanticsAction.values[action],
183    args,
184  );
185}
186
187@pragma('vm:entry-point')
188// ignore: unused_element
189void _beginFrame(int microseconds) {
190  _invoke1<Duration>(window.onBeginFrame, window._onBeginFrameZone, Duration(microseconds: microseconds));
191}
192
193@pragma('vm:entry-point')
194// ignore: unused_element
195void _reportTimings(List<int> timings) {
196  assert(timings.length % FramePhase.values.length == 0);
197  final List<FrameTiming> frameTimings = <FrameTiming>[];
198  for (int i = 0; i < timings.length; i += FramePhase.values.length) {
199    frameTimings.add(FrameTiming(timings.sublist(i, i + FramePhase.values.length)));
200  }
201  _invoke1(window.onReportTimings, window._onReportTimingsZone, frameTimings);
202}
203
204@pragma('vm:entry-point')
205// ignore: unused_element
206void _drawFrame() {
207  _invoke(window.onDrawFrame, window._onDrawFrameZone);
208}
209
210// ignore: always_declare_return_types, prefer_generic_function_type_aliases
211typedef _UnaryFunction(Null args);
212// ignore: always_declare_return_types, prefer_generic_function_type_aliases
213typedef _BinaryFunction(Null args, Null message);
214
215@pragma('vm:entry-point')
216// ignore: unused_element
217void _runMainZoned(Function startMainIsolateFunction,
218                   Function userMainFunction,
219                   List<String> args) {
220  startMainIsolateFunction((){
221    runZoned<void>(() {
222      if (userMainFunction is _BinaryFunction) {
223        // This seems to be undocumented but supported by the command line VM.
224        // Let's do the same in case old entry-points are ported to Flutter.
225        (userMainFunction as dynamic)(args, '');
226      } else if (userMainFunction is _UnaryFunction) {
227        (userMainFunction as dynamic)(args);
228      } else {
229        userMainFunction();
230      }
231    }, onError: (Object error, StackTrace stackTrace) {
232      _reportUnhandledException(error.toString(), stackTrace.toString());
233    });
234  }, null);
235}
236
237void _reportUnhandledException(String error, String stackTrace) native 'Window_reportUnhandledException';
238
239/// Invokes [callback] inside the given [zone].
240void _invoke(void callback(), Zone zone) {
241  if (callback == null)
242    return;
243
244  assert(zone != null);
245
246  if (identical(zone, Zone.current)) {
247    callback();
248  } else {
249    zone.runGuarded(callback);
250  }
251}
252
253/// Invokes [callback] inside the given [zone] passing it [arg].
254void _invoke1<A>(void callback(A a), Zone zone, A arg) {
255  if (callback == null)
256    return;
257
258  assert(zone != null);
259
260  if (identical(zone, Zone.current)) {
261    callback(arg);
262  } else {
263    zone.runUnaryGuarded<A>(callback, arg);
264  }
265}
266
267/// Invokes [callback] inside the given [zone] passing it [arg1] and [arg2].
268// ignore: unused_element
269void _invoke2<A1, A2>(void callback(A1 a1, A2 a2), Zone zone, A1 arg1, A2 arg2) {
270  if (callback == null)
271    return;
272
273  assert(zone != null);
274
275  if (identical(zone, Zone.current)) {
276    callback(arg1, arg2);
277  } else {
278    zone.runBinaryGuarded<A1, A2>(callback, arg1, arg2);
279  }
280}
281
282/// Invokes [callback] inside the given [zone] passing it [arg1], [arg2] and [arg3].
283void _invoke3<A1, A2, A3>(void callback(A1 a1, A2 a2, A3 a3), Zone zone, A1 arg1, A2 arg2, A3 arg3) {
284  if (callback == null)
285    return;
286
287  assert(zone != null);
288
289  if (identical(zone, Zone.current)) {
290    callback(arg1, arg2, arg3);
291  } else {
292    zone.runGuarded(() {
293      callback(arg1, arg2, arg3);
294    });
295  }
296}
297
298// If this value changes, update the encoding code in the following files:
299//
300//  * pointer_data.cc
301//  * FlutterView.java
302const int _kPointerDataFieldCount = 24;
303
304PointerDataPacket _unpackPointerDataPacket(ByteData packet) {
305  const int kStride = Int64List.bytesPerElement;
306  const int kBytesPerPointerData = _kPointerDataFieldCount * kStride;
307  final int length = packet.lengthInBytes ~/ kBytesPerPointerData;
308  assert(length * kBytesPerPointerData == packet.lengthInBytes);
309  final List<PointerData> data = List<PointerData>(length);
310  for (int i = 0; i < length; ++i) {
311    int offset = i * _kPointerDataFieldCount;
312    data[i] = PointerData(
313      timeStamp: Duration(microseconds: packet.getInt64(kStride * offset++, _kFakeHostEndian)),
314      change: PointerChange.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)],
315      kind: PointerDeviceKind.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)],
316      signalKind: PointerSignalKind.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)],
317      device: packet.getInt64(kStride * offset++, _kFakeHostEndian),
318      physicalX: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
319      physicalY: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
320      buttons: packet.getInt64(kStride * offset++, _kFakeHostEndian),
321      obscured: packet.getInt64(kStride * offset++, _kFakeHostEndian) != 0,
322      pressure: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
323      pressureMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
324      pressureMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
325      distance: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
326      distanceMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
327      size: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
328      radiusMajor: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
329      radiusMinor: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
330      radiusMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
331      radiusMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
332      orientation: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
333      tilt: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
334      platformData: packet.getInt64(kStride * offset++, _kFakeHostEndian),
335      scrollDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
336      scrollDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian)
337    );
338    assert(offset == (i + 1) * _kPointerDataFieldCount);
339  }
340  return PointerDataPacket(data: data);
341}
342