浏览代码

future, timer, serialization, platform message, asset bundle.

/siyaoH-1.17-PlatformMessage
Kevin Gu 4 年前
当前提交
284b4aac
共有 48 个文件被更改,包括 2361 次插入359 次删除
  1. 111
      com.unity.uiwidgets/Runtime/async2/future.cs
  2. 47
      com.unity.uiwidgets/Runtime/async2/future_impl.cs
  3. 77
      com.unity.uiwidgets/Runtime/async2/schedule_microtask.cs
  4. 44
      com.unity.uiwidgets/Runtime/async2/timer.cs
  5. 16
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
  6. 9
      com.unity.uiwidgets/Runtime/foundation/binding.cs
  7. 2
      com.unity.uiwidgets/Runtime/foundation/constants.cs
  8. 48
      com.unity.uiwidgets/Runtime/painting/binding.cs
  9. 10
      com.unity.uiwidgets/Runtime/scheduler2/binding.cs
  10. 6
      com.unity.uiwidgets/Runtime/scheduler2/ticker.cs
  11. 24
      com.unity.uiwidgets/Runtime/ui2/compositing.cs
  12. 138
      com.unity.uiwidgets/Runtime/ui2/hooks.cs
  13. 59
      com.unity.uiwidgets/Runtime/ui2/isolate.cs
  14. 80
      com.unity.uiwidgets/Runtime/ui2/painting.cs
  15. 73
      com.unity.uiwidgets/Runtime/ui2/window.cs
  16. 6
      engine/Build.bee.cs
  17. 93
      engine/src/lib/ui/window/window.cc
  18. 19
      engine/src/shell/platform/unity/uiwidgets_panel.cc
  19. 2
      engine/src/shell/platform/unity/uiwidgets_panel.h
  20. 9
      engine/src/shell/platform/unity/win32_task_runner.cc
  21. 33
      com.unity.uiwidgets/Runtime/foundation/isolates.cs
  22. 3
      com.unity.uiwidgets/Runtime/foundation/isolates.cs.meta
  23. 11
      com.unity.uiwidgets/Runtime/foundation/object.cs
  24. 3
      com.unity.uiwidgets/Runtime/foundation/object.cs.meta
  25. 202
      com.unity.uiwidgets/Runtime/foundation/serialization.cs
  26. 3
      com.unity.uiwidgets/Runtime/foundation/serialization.cs.meta
  27. 53
      com.unity.uiwidgets/Runtime/foundation/synchronous_future.cs
  28. 3
      com.unity.uiwidgets/Runtime/foundation/synchronous_future.cs.meta
  29. 159
      com.unity.uiwidgets/Runtime/painting/shader_warmup.cs
  30. 3
      com.unity.uiwidgets/Runtime/painting/shader_warmup.cs.meta
  31. 3
      com.unity.uiwidgets/Runtime/services.meta
  32. 158
      com.unity.uiwidgets/Runtime/ui2/channel_buffers.cs
  33. 3
      com.unity.uiwidgets/Runtime/ui2/channel_buffers.cs.meta
  34. 50
      engine/src/lib/ui/window/platform_message_response_mono.cc
  35. 33
      engine/src/lib/ui/window/platform_message_response_mono.h
  36. 161
      com.unity.uiwidgets/Runtime/services/asset_bundle.cs
  37. 3
      com.unity.uiwidgets/Runtime/services/asset_bundle.cs.meta
  38. 15
      com.unity.uiwidgets/Runtime/services/binary_messenger.cs
  39. 3
      com.unity.uiwidgets/Runtime/services/binary_messenger.cs.meta
  40. 104
      com.unity.uiwidgets/Runtime/services/binding.cs
  41. 3
      com.unity.uiwidgets/Runtime/services/binding.cs.meta
  42. 67
      com.unity.uiwidgets/Runtime/services/message_codec.cs
  43. 3
      com.unity.uiwidgets/Runtime/services/message_codec.cs.meta
  44. 650
      com.unity.uiwidgets/Runtime/services/message_codecs.cs
  45. 3
      com.unity.uiwidgets/Runtime/services/message_codecs.cs.meta
  46. 89
      engine/src/lib/ui/window/platform_message_response_dart.cc
  47. 26
      engine/src/lib/ui/window/platform_message_response_dart.h

111
com.unity.uiwidgets/Runtime/async2/future.cs


namespace Unity.UIWidgets.async2 {
public struct FutureOr {
public object value;
public Future future;
public object v;
public Future f;
public bool isFuture => future != null;
public bool isFuture => f != null;
public static FutureOr withValue(object value) {
return new FutureOr {value = value};
public static FutureOr value(object value) {
return new FutureOr {v = value};
public static FutureOr withFuture(Future future) {
return new FutureOr {future = future};
public static FutureOr future(Future future) {
return new FutureOr {f = future};
public static readonly FutureOr nullValue = withValue(null);
public static readonly FutureOr trueValue = withValue(true);
public static readonly FutureOr nil = value(null);
public static implicit operator FutureOr(Future f) => future(f);
public static implicit operator FutureOr(bool v) => value(v);
public static implicit operator FutureOr(int v) => value(v);
public static implicit operator FutureOr(long v) => value(v);
public static implicit operator FutureOr(float v) => value(v);
public static implicit operator FutureOr(double v) => value(v);
public static implicit operator FutureOr(string v) => value(v);
public static readonly FutureOr falseValue = withValue(false);
public static implicit operator FutureOr(byte[] v) => value(v);
}
public abstract class Future {

try {
var result = computation();
if (result.isFuture) {
return result.future;
return result.f;
}
else {
return _Future.value(result);

_Future result = new _Future();
Timer.create(duration, () => {
if (computation == null) {
result._complete(FutureOr.nullValue);
result._complete();
}
else {
try {

// Ensure errors from cleanUp are uncaught.
Future.sync(() => {
cleanUp(value);
return FutureOr.nullValue;
return FutureOr.nil;
});
}
}

result._completeError(error);
}
return FutureOr.nullValue;
return FutureOr.nil;
};
try {

// Ensure errors from cleanUp are uncaught.
Future.sync(() => {
cleanUp((T) value);
return FutureOr.nullValue;
return FutureOr.nil;
});
}

}
return FutureOr.nullValue;
return FutureOr.nil;
}, onError: handleError);
// Increment the 'remaining' after the call to 'then'.
// If that call throws, we don't expect any future callback from

if (remaining == 0) {
return Future.value(FutureOr.withValue(new List<T>()));
return Future.value(FutureOr.value(new List<T>()));
}
values = new List<T>(remaining);

public static Future any(IEnumerable<Future> futures) {
var completer = Completer.sync();
Func<object, FutureOr> onValue = (object value) => {
if (!completer.isCompleted) completer.complete(FutureOr.withValue(value));
return FutureOr.nullValue;
if (!completer.isCompleted) completer.complete(FutureOr.value(value));
return FutureOr.nil;
return FutureOr.nullValue;
return FutureOr.nil;
};
foreach (var future in futures) {

public static Future forEach<T>(IEnumerable<T> elements, Func<T, FutureOr> action) {
var iterator = elements.GetEnumerator();
return doWhile(() => {
if (!iterator.MoveNext()) return FutureOr.falseValue;
if (!iterator.MoveNext()) return false;
if (result.isFuture) return FutureOr.withFuture(result.future.then(_kTrue));
return FutureOr.trueValue;
if (result.isFuture) return FutureOr.future(result.f.then(_kTrue));
return true;
static readonly Func<object, FutureOr> _kTrue = (_) => FutureOr.trueValue;
static readonly Func<object, FutureOr> _kTrue = (_) => true;
public static Future doWhile(Func<FutureOr> action) {
_Future doneSignal = new _Future();

}
if (result.isFuture) {
result.future.then((value) => {
result.f.then((value) => {
return FutureOr.nullValue;
return FutureOr.nil;
return FutureOr.nullValue;
return FutureOr.nil;
keepGoing = (bool) result.value;
keepGoing = (bool) result.v;
doneSignal._complete(FutureOr.nullValue);
doneSignal._complete();
return null;
});

public abstract Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null);
public abstract Future whenComplete(Func<object> action);
public abstract Future whenComplete(Func<FutureOr> action);
public Future<T> to<T>() {
if (this is Future<T>) {
return (Future<T>) this;
}
return new Future<T>(this);
}
public class Future<T> : Future {
readonly Future _future;
public Future(Future future) {
_future = future;
}
public override Future then(Func<object, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(onValue, onError);
}
public Future<R> then<R>(Func<T, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(obj => onValue((T) obj), onError).to<R>();
}
public override Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null) {
return _future.catchError(onError, test);
}
public override Future whenComplete(Func<FutureOr> action) {
return _future.whenComplete(action);
}
public override Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null) {
return _future.timeout(timeLimit, onTimeout);
}
}
public class TimeoutException : Exception {
public readonly TimeSpan? duration;

public static Completer sync() => new _SyncCompleter();
public abstract Future future { get; }
public abstract void complete(FutureOr value = default);
public abstract void completeError(Exception error);

47
com.unity.uiwidgets/Runtime/async2/future_impl.cs


namespace Unity.UIWidgets.async2 {
using _FutureOnValue = Func<object, FutureOr>;
using _FutureErrorTest = Func<Exception, bool>;
using _FutureAction = Func<object>;
using _FutureAction = Func<FutureOr>;
abstract class _Completer : Completer {
protected readonly _Future _future = new _Future();

return (FutureOr) _zone.runUnary(arg => errorCallback((Exception) arg), asyncError.InnerException);
}
public object handleWhenComplete() {
public FutureOr handleWhenComplete() {
return _zone.run(() => _whenCompleteAction());
return (FutureOr) _zone.run(() => _whenCompleteAction());
}
}

_zone = zone;
}
internal static _Future immediate(object result) {
internal static _Future immediate(FutureOr result) {
var future = new _Future(Zone.current);
future._asyncComplete(result);
return future;

return result;
}
public override Future whenComplete(Func<object> action) {
public override Future whenComplete(Func<FutureOr> action) {
_Future result = new _Future();
if (!ReferenceEquals(result._zone, async_._rootZone)) {
action = async_._registerHandler(action, result._zone);

}
internal void _setValue(object value) {
D.assert(!(value is Future || value is FutureOr));
D.assert(!_isComplete); // But may have a completion pending.
_state = _stateValue;
_resultOrListeners = value;

// implementation is mis-behaving,
// so use _complete instead of _completeWithValue.
target._clearPendingComplete(); // Clear this first, it's set again.
target._complete(FutureOr.withValue(value));
target._complete(FutureOr.value(value));
return new FutureOr();
},
onError: (Exception error) => {

}
}
internal void _complete(FutureOr value) {
internal void _complete(FutureOr value = default) {
if (value.future is _Future coreFuture) {
if (value.f is _Future coreFuture) {
_chainForeignFuture(value.future, this);
_chainForeignFuture(value.f, this);
_setValue(value);
_setValue(value.v);
_propagateToListeners(this, listeners);
}
}

D.assert(!(value is Future));
_FutureListener listeners = _removeListeners();
_setValue(value);

_propagateToListeners(this, listeners);
}
internal void _asyncComplete(object value) {
internal void _asyncComplete(FutureOr value) {
D.assert(!_isComplete);
// Two corner cases if the value is a future:
// 1. the future is already completed and an error.

// unhandled error, even though we know we are already going to listen to
// it.
if (value is Future future) {
_chainFuture(future);
if (value.isFuture) {
_chainFuture(value.f);
_completeWithValue(value);
_completeWithValue(value.v);
return null;
});
}

// listener.
D.assert(!listener.handlesValue);
D.assert(!listener.handlesError);
object completeResult = null;
FutureOr completeResult;
try {
completeResult = listener.handleWhenComplete();
}

return;
}
if (completeResult is Future completeResultFuture) {
if (completeResult is _Future completeResultCoreFuture &&
if (completeResult.isFuture) {
var completeResultFuture = completeResult.f;
if (completeResultFuture is _Future completeResultCoreFuture &&
completeResultCoreFuture._isComplete) {
if (completeResultCoreFuture._hasError) {
listenerValueOrError = completeResultCoreFuture._error;

// of source.
var originalSource = source;
listenerValueOrError =
completeResultFuture.then((_) => FutureOr.withFuture(originalSource));
completeResultFuture.then((_) => FutureOr.future(originalSource));
listenerHasError = false;
}
};

// If we changed zone, oldZone will not be null.
if (oldZone != null) Zone._leave(oldZone);
if (listenerValueOrError is FutureOr futureOr) {
listenerValueOrError = futureOr.isFuture ? futureOr.f : futureOr.v;
}
// If the listener's value is a future we need to chain it. Note that
// this can only happen if there is a callback.
if (listenerValueOrError is Future chainSource) {

result._completeWithValue(v);
}
return FutureOr.nullValue;
return FutureOr.nil;
}, onError: e => {
if (timer.isActive) {
timer.cancel();

return FutureOr.nullValue;
return FutureOr.nil;
});
return result;
}

77
com.unity.uiwidgets/Runtime/async2/schedule_microtask.cs


using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.ui2;
using UnityEngine;
namespace Unity.UIWidgets.async2 {
class _AsyncCallbackEntry {

}
}
public static partial class async_ {
static _AsyncCallbackEntry _nextCallback;
static _AsyncCallbackEntry _lastCallback;
static _AsyncCallbackEntry _lastPriorityCallback;
class _AsyncCallbackState {
internal _AsyncCallbackEntry _nextCallback;
internal _AsyncCallbackEntry _lastCallback;
internal _AsyncCallbackEntry _lastPriorityCallback;
internal bool _isInCallbackLoop;
}
static bool _isInCallbackLoop = false;
public static partial class async_ {
static _AsyncCallbackState _getState()
{
return Window.instance._asyncCallbackState ??
(Window.instance._asyncCallbackState = new _AsyncCallbackState());
}
while (_nextCallback != null) {
_lastPriorityCallback = null;
_AsyncCallbackEntry entry = _nextCallback;
_nextCallback = entry.next;
if (_nextCallback == null) _lastCallback = null;
var state = _getState();
while (state._nextCallback != null) {
state._lastPriorityCallback = null;
_AsyncCallbackEntry entry = state._nextCallback;
state._nextCallback = entry.next;
if (state._nextCallback == null) state._lastCallback = null;
_isInCallbackLoop = true;
var state = _getState();
state._isInCallbackLoop = true;
try {
// Moved to separate function because try-finally prevents
// good optimization.

_lastPriorityCallback = null;
_isInCallbackLoop = false;
if (_nextCallback != null) {
state._lastPriorityCallback = null;
state._isInCallbackLoop = false;
if (state._nextCallback != null) {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
}

static void _scheduleAsyncCallback(ZoneCallback callback) {
var state = _getState();
if (_nextCallback == null) {
_nextCallback = _lastCallback = newEntry;
if (!_isInCallbackLoop) {
if (state._nextCallback == null) {
state._nextCallback = state._lastCallback = newEntry;
if (!state._isInCallbackLoop) {
_lastCallback.next = newEntry;
_lastCallback = newEntry;
state._lastCallback.next = newEntry;
state._lastCallback = newEntry;
if (_nextCallback == null) {
var state = _getState();
if (state._nextCallback == null) {
_lastPriorityCallback = _lastCallback;
state._lastPriorityCallback = state._lastCallback;
if (_lastPriorityCallback == null) {
entry.next = _nextCallback;
_nextCallback = _lastPriorityCallback = entry;
if (state._lastPriorityCallback == null) {
entry.next = state._nextCallback;
state._nextCallback = state._lastPriorityCallback = entry;
entry.next = _lastPriorityCallback.next;
_lastPriorityCallback.next = entry;
_lastPriorityCallback = entry;
entry.next = state._lastPriorityCallback.next;
state._lastPriorityCallback.next = entry;
state._lastPriorityCallback = entry;
_lastCallback = entry;
state._lastCallback = entry;
}
}
}

class _AsyncRun {
internal static void _scheduleImmediate(ZoneCallback callback) {
Isolate.ensureExists();
GCHandle callabackHandle = GCHandle.Alloc(callback);
UIMonoState_scheduleMicrotask(_scheduleMicrotask, (IntPtr) callabackHandle);
}

var callback = (ZoneCallback) handle.Target;
handle.Free();
callback();
try {
callback();
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
delegate void UIMonoState_scheduleMicrotaskCallback(IntPtr callbackHandle);

44
com.unity.uiwidgets/Runtime/async2/timer.cs


using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.ui2;
using UnityEngine;
namespace Unity.UIWidgets.async2 {
public abstract class Timer : IDisposable {

}
void _enqueue() {
Isolate.ensureExists();
GCHandle callabackHandle = GCHandle.Alloc(this);
UIMonoState_postTaskForTime(_postTaskForTime, (IntPtr) callabackHandle, _wakeupTime * 1000L);
}

var timer = (_Timer) timerHandle.Target;
timerHandle.Free();
if (timer._callback != null) {
var callback = timer._callback;
if (!timer._repeating) {
timer._callback = null;
}
else if (timer._milliSeconds > 0) {
var ms = timer._milliSeconds;
int overdue = UIMonoState_timerMillisecondClock() - timer._wakeupTime;
if (overdue > ms) {
int missedTicks = overdue / ms;
timer._wakeupTime += missedTicks * ms;
timer._tick += missedTicks;
try {
if (timer._callback != null) {
var callback = timer._callback;
if (!timer._repeating) {
timer._callback = null;
}
else if (timer._milliSeconds > 0) {
var ms = timer._milliSeconds;
int overdue = UIMonoState_timerMillisecondClock() - timer._wakeupTime;
if (overdue > ms) {
int missedTicks = overdue / ms;
timer._wakeupTime += missedTicks * ms;
timer._tick += missedTicks;
}
}
timer._tick += 1;
timer._tick += 1;
callback(timer);
callback(timer);
if (timer._repeating && (timer._callback != null)) {
timer._advanceWakeupTime();
timer._enqueue();
if (timer._repeating && (timer._callback != null)) {
timer._advanceWakeupTime();
timer._enqueue();
}
}
catch (Exception ex) {
Debug.LogException(ex);
}
}

16
com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs


namespace Unity.UIWidgets.engine2 {
public class UIWidgetsPanel : RawImage {
public IntPtr isolate { get; private set; }
public static UIWidgetsPanel current {
get { return Window.instance._panel; }
}
public Isolate isolate { get; private set; }
IntPtr _ptr;
GCHandle _handle;

_ptr = UIWidgetsPanel_constructor((IntPtr) _handle, UIWidgetsPanel_entrypoint);
UIWidgetsPanel_onEnable(_ptr, _renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio);
_width, _height, _devicePixelRatio, Application.streamingAssetsPath);
Debug.Log(Debug.isDebugBuild);
Window.instance._panel = this;
main();
}
catch (Exception ex) {

_handle.Free();
_handle = default;
if (isolate != null)
Isolate.remove(isolate);
base.OnDisable();
}

[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onEnable(IntPtr ptr,
IntPtr nativeTexturePtr, int width, int height, float dpi);
IntPtr nativeTexturePtr, int width, int height, float dpi, string streamingAssetsPath);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onDisable(IntPtr ptr);

9
com.unity.uiwidgets/Runtime/foundation/binding.cs


namespace Unity.UIWidgets.foundation {
public abstract class BindingBase {
protected BindingBase() {
D.assert(!_debugInitialized);
D.assert(_debugInitialized);
}
static bool _debugInitialized = false;

protected virtual void initInstances() {
D.assert(!_debugInitialized);
D.assert(() => {
_debugInitialized = true;
return true;
});
}
protected bool locked => _lockCount > 0;

unlocked();
}
return null;
return FutureOr.nil;
});
return future;
}

2
com.unity.uiwidgets/Runtime/foundation/constants.cs


using UnityEngine;
namespace Unity.UIWidgets.foundation {
public static class foundation_ {
public static partial class foundation_ {
public static readonly bool kReleaseMode = !Debug.isDebugBuild;
#if UIWidgets_PROFILE

48
com.unity.uiwidgets/Runtime/painting/binding.cs


using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.scheduler2;
using Unity.UIWidgets.ui;
using Window = Unity.UIWidgets.ui2.Window;
// protected override void initInstances() {
// base.initInstances();
// instance = this;
// _imageCache = createImageCache();
//
// if (shaderWarmUp != null) {
// shaderWarmUp.execute();
// }
// }
public PaintingBinding() {
}
public static ShaderWarmUp shaderWarmUp = new DefaultShaderWarmUp();
public ImageCache imageCache => _imageCache;
public ImageCache imageCache {
get {
if (this._imageCache == null) {
this._imageCache = this.createImageCache();
}
return this._imageCache;
}
}
//
// public Future<Codec> instantiateImageCodec(byte[] bytes,
// int? cacheWidth = null,
// int? cacheHeight = null) {
// D.assert(cacheWidth == null || cacheWidth > 0);
// D.assert(cacheHeight == null || cacheHeight > 0);
//
// Future<object> f = instantiateImageCodec(null).then<object>(c => {
// return FutureOr.null_;
// }).to<Codec>().asOf<object>();
// return ui.instantiateImageCodec(
// bytes,
// targetWidth: cacheWidth,
// targetHeight: cacheHeight
// );
// }
}
public static partial class painting_ {
public static ImageCache imageCache => PaintingBinding.instance.imageCache;
}
}

10
com.unity.uiwidgets/Runtime/scheduler2/binding.cs


public void run() {
if (!foundation_.kReleaseMode) {
completer.complete(FutureOr.withValue(task()));
completer.complete(FutureOr.value(task()));
completer.complete(FutureOr.withValue(task()));
completer.complete(FutureOr.value(task()));
}
}

public static SchedulerBinding instance {
get { return (SchedulerBinding) Window.instance._binding; }
set { Window.instance._binding = value; }
private set { Window.instance._binding = value; }
}
public AppLifecycleState? lifecycleState => _lifecycleState;

if (schedulerPhase == SchedulerPhase.idle)
scheduleFrame();
_nextFrameCompleter = Completer.create();
addPostFrameCallback((TimeSpan timeStamp) => {
addPostFrameCallback((timeStamp) => {
_nextFrameCompleter.complete();
_nextFrameCompleter = null;
});

// scheduled frame has finished.
lockEvents(() => endOfFrame.then(v => {
Timeline.finishSync();
return FutureOr.nullValue;
return FutureOr.nil;
}));
}

6
com.unity.uiwidgets/Runtime/scheduler2/ticker.cs


public void whenCompleteOrCancel(VoidCallback callback) {
orCancel.then((value) => {
callback();
return FutureOr.nullValue;
return FutureOr.nil;
return FutureOr.nullValue;
return FutureOr.nil;
});
}

return _primaryCompleter.future.timeout(timeLimit, onTimeout: onTimeout);
}
public override Future whenComplete(Func<object> action) {
public override Future whenComplete(Func<FutureOr> action) {
return _primaryCompleter.future.whenComplete(action);
}

24
com.unity.uiwidgets/Runtime/ui2/compositing.cs


using RSG;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;
namespace Unity.UIWidgets.ui2 {
public class Scene : NativeWrapperDisposable {

var completer = (Promise<Image>) completerHandle.Target;
completerHandle.Free();
if (result == IntPtr.Zero) {
completer.Reject(new Exception("operation failed"));
try {
if (result == IntPtr.Zero) {
completer.Reject(new Exception("operation failed"));
}
else {
var image = new Image(result);
completer.Resolve(image);
}
else {
var image = new Image(result);
completer.Resolve(image);
catch (Exception ex) {
Debug.LogException(ex);
}
}

public Scene build() {
return new Scene(SceneBuilder_build(_ptr));
}
public void addRetained(EngineLayer retainedLayer) {
D.assert(retainedLayer is _EngineLayerWrapper);
D.assert(() => {

_EngineLayerWrapper wrapper = retainedLayer as _EngineLayerWrapper;
SceneBuilder_addRetained(_ptr, wrapper._ptr);
}
Picture picture,
Picture picture,
bool isComplexHint = false,
bool willChangeHint = false
) {

[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_build(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_addPicture(IntPtr ptr, float dx, float dy, IntPtr picture, int hints);

138
com.unity.uiwidgets/Runtime/ui2/hooks.cs


using System;
using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;

#else
[RuntimeInitializeOnLoadMethod]
#endif
static void hook() {
static unsafe void hook() {
Mono_hook(
Mono_throwException);

Window_updateWindowMetrics,
Window_beginFrame,
Window_drawFrame);
Window_drawFrame,
ui_._dispatchPlatformMessage);
}
delegate void Mono_ThrowExceptionCallback(IntPtr exception);

float systemGestureInsetBottom,
float systemGestureInsetLeft
) {
var window = Window.instance;
try {
var window = Window.instance;
window.devicePixelRatio = devicePixelRatio;
window.devicePixelRatio = devicePixelRatio;
window.physicalSize = new Size(width, height);
window.physicalDepth = depth;
window.physicalSize = new Size(width, height);
window.physicalDepth = depth;
window.viewPadding = new WindowPadding(
top: viewPaddingTop,
right: viewPaddingRight,
bottom: viewPaddingBottom,
left: viewPaddingLeft);
window.viewPadding = new WindowPadding(
top: viewPaddingTop,
right: viewPaddingRight,
bottom: viewPaddingBottom,
left: viewPaddingLeft);
window.viewInsets = new WindowPadding(
top: viewInsetTop,
right: viewInsetRight,
bottom: viewInsetBottom,
left: viewInsetLeft);
window.viewInsets = new WindowPadding(
top: viewInsetTop,
right: viewInsetRight,
bottom: viewInsetBottom,
left: viewInsetLeft);
window.padding = new WindowPadding(
top: Mathf.Max(0.0f, viewPaddingTop - viewInsetTop),
right: Mathf.Max(0.0f, viewPaddingRight - viewInsetRight),
bottom: Mathf.Max(0.0f, viewPaddingBottom - viewInsetBottom),
left: Mathf.Max(0.0f, viewPaddingLeft - viewInsetLeft));
window.padding = new WindowPadding(
top: Mathf.Max(0.0f, viewPaddingTop - viewInsetTop),
right: Mathf.Max(0.0f, viewPaddingRight - viewInsetRight),
bottom: Mathf.Max(0.0f, viewPaddingBottom - viewInsetBottom),
left: Mathf.Max(0.0f, viewPaddingLeft - viewInsetLeft));
window.systemGestureInsets = new WindowPadding(
top: Mathf.Max(0.0f, systemGestureInsetTop),
right: Mathf.Max(0.0f, systemGestureInsetRight),
bottom: Mathf.Max(0.0f, systemGestureInsetBottom),
left: Mathf.Max(0.0f, systemGestureInsetLeft));
window.systemGestureInsets = new WindowPadding(
top: Mathf.Max(0.0f, systemGestureInsetTop),
right: Mathf.Max(0.0f, systemGestureInsetRight),
bottom: Mathf.Max(0.0f, systemGestureInsetBottom),
left: Mathf.Max(0.0f, systemGestureInsetLeft));
window.onMetricsChanged?.Invoke();
window.onMetricsChanged?.Invoke();
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
delegate void Window_beginFrameCallback(long microseconds);

Window.instance.onBeginFrame?.Invoke(TimeSpan.FromMilliseconds(microseconds / 1000.0));
try {
Window.instance.onBeginFrame?.Invoke(TimeSpan.FromMilliseconds(microseconds / 1000.0));
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
delegate void Window_drawFrameCallback();

Window.instance.onDrawFrame?.Invoke();
try {
Window.instance.onDrawFrame?.Invoke();
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
[DllImport(NativeBindings.dllName)]

Window_updateWindowMetricsCallback Window_updateWindowMetrics,
Window_beginFrameCallback Window_beginFrame,
Window_drawFrameCallback Window_drawFrame);
Window_drawFrameCallback Window_drawFrame,
ui_.Window_dispatchPlatformMessageCallback Window_dispatchPlatformMessage);
}
public static partial class ui_ {
internal unsafe delegate void Window_dispatchPlatformMessageCallback(string name, byte* dataRaw, int dataLength,
int responseId);
[MonoPInvokeCallback(typeof(Window_dispatchPlatformMessageCallback))]
internal static unsafe void _dispatchPlatformMessage(
string name, byte* dataRaw, int dataLength, int responseId) {
try {
var data = new byte[dataLength];
Marshal.Copy((IntPtr) dataRaw, data, 0, dataLength);
if (name == ChannelBuffers.kControlChannelName) {
try {
channelBuffers.handleMessage(data);
}
catch (Exception ex) {
Debug.LogError($"Message to \"{name}\" caused exception {ex}");
}
finally {
Window.instance._respondToPlatformMessage(responseId, null);
}
}
else if (Window.instance.onPlatformMessage != null) {
_invoke3<string, byte[], PlatformMessageResponseCallback>(
(name1, data1, callback1) => Window.instance.onPlatformMessage(name1, data1, callback1),
Window.instance._onPlatformMessageZone,
name, data, responseData =>
Window.instance._respondToPlatformMessage(responseId, responseData)
);
}
else {
channelBuffers.push(name, data, responseData
=> Window.instance._respondToPlatformMessage(responseId, responseData));
}
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
internal static void _invoke3<A1, A2, A3>(Action<A1, A2, A3> callback, Zone zone, A1 arg1, A2 arg2, A3 arg3) {
if (callback == null)
return;
D.assert(zone != null);
if (ReferenceEquals(zone, Zone.current)) {
callback(arg1, arg2, arg3);
}
else {
zone.runGuarded(() => {
callback(arg1, arg2, arg3);
return null;
});
}
}
}
}

59
com.unity.uiwidgets/Runtime/ui2/isolate.cs


using System;
using System.Collections.Generic;
public static class Isolate {
public static IntPtr current {
get => Isolate_current();
public class Isolate {
static Dictionary<IntPtr, Isolate> _isolates = new Dictionary<IntPtr, Isolate>();
Isolate(IntPtr ptr) {
_ptr = ptr;
}
IntPtr _ptr;
public bool isValid => _ptr != IntPtr.Zero;
public static Isolate current {
get {
IntPtr ptr = ensureExists();
if (_isolates.TryGetValue(ptr, out Isolate value)) {
D.assert(value.isValid);
return value;
}
var isolate = new Isolate(ptr);
_isolates.Add(ptr, isolate);
return isolate;
}
}
public static IntPtr ensureExists() {
IntPtr ptr = Isolate_current();
if (ptr == IntPtr.Zero) {
throw new Exception("Isolate.current is null. " +
"This usually happens when there is a callback from outside of UIWidgets. " +
"Try to use \"using (Isolate.getScope(...)) { ... }\" to wrap your code.");
}
return ptr;
public static IDisposable getScope(IntPtr isolate) {
return new _IsolateDisposable(isolate);
internal static void remove(Isolate isolate) {
D.assert(isolate != null && isolate.isValid);
_isolates.Remove(isolate._ptr);
isolate._ptr = IntPtr.Zero;
}
public static IDisposable getScope(Isolate isolate) {
D.assert(isolate != null && isolate.isValid);
return new _IsolateDisposable(isolate._ptr);
}
class _IsolateDisposable : IDisposable {

}
}
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr Isolate_current();

[DllImport(NativeBindings.dllName)]
static extern void Isolate_exit();
}
}

80
com.unity.uiwidgets/Runtime/ui2/painting.cs


using System.Text;
using AOT;
using RSG;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using UnityEngine;
using Unity.UIWidgets.ui;

}
}
float strokeWidth {
public float strokeWidth {
get { return _data.getFloat32(_kStrokeWidthOffset); }
set {
float encoded = value;

var completer = (Promise<byte[]>) completerHandle.Target;
completerHandle.Free();
if (data == IntPtr.Zero || length == 0) {
completer.Resolve(new byte[0]);
try {
if (data == IntPtr.Zero || length == 0) {
completer.Resolve(new byte[0]);
}
else {
var bytes = new byte[length];
Marshal.Copy(data, bytes, 0, length);
completer.Resolve(bytes);
}
else {
var bytes = new byte[length];
Marshal.Copy(data, bytes, 0, length);
completer.Resolve(bytes);
catch (Exception ex) {
Debug.LogException(ex);
}
}

Picture_dispose(ptr);
}
public Promise<Image> toImage(int width, int height) {
public Future toImage(int width, int height) {
var completer = new Promise<Image>(true);
GCHandle completerHandle = GCHandle.Alloc(completer);
return ui_._futurize(
(_Callback<Image> callback) => {
GCHandle callbackHandle = GCHandle.Alloc(callback);
IntPtr error =
Picture_toImage(_ptr, width, height, _toImageCallback,
(IntPtr) callbackHandle);
IntPtr error =
Picture_toImage(_ptr, width, height, _toImageCallback,
(IntPtr) completerHandle);
if (error != null) {
completerHandle.Free();
throw new Exception(Marshal.PtrToStringAnsi(error));
}
if (error != IntPtr.Zero) {
callbackHandle.Free();
return Marshal.PtrToStringAnsi(error);
}
return completer;
return null;
});
GCHandle completerHandle = (GCHandle) callbackHandle;
var completer = (Promise<Image>) completerHandle.Target;
completerHandle.Free();
GCHandle handle = (GCHandle) callbackHandle;
var callback = (_Callback<Image>) handle.Target;
handle.Free();
if (result == IntPtr.Zero) {
completer.Reject(new Exception("operation failed"));
try {
callback(result == IntPtr.Zero ? null : new Image(result));
else {
var image = new Image(result);
completer.Resolve(image);
catch (Exception ex) {
Debug.LogException(ex);
}
}

// TODO: for text.
public class Shadow {
}
delegate void _Callback<T>(T result);
delegate string _Callbacker<T>(_Callback<T> callback);
public static partial class ui_ {
internal static Future _futurize<T>(_Callbacker<T> callbacker) {
Completer completer = Completer.sync();
string error = callbacker(t => {
if (t == null) {
completer.completeError(new Exception("operation failed"));
}
else {
completer.complete(FutureOr.value(t));
}
});
if (error != null)
throw new Exception(error);
return completer.future;
}
}
}

73
com.unity.uiwidgets/Runtime/ui2/window.cs


using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.engine2;
using UnityEngine;
namespace Unity.UIWidgets.ui2 {
public delegate void VoidCallback();

public delegate void PointerDataPacketCallback(PointerDataPacket packet);
public unsafe delegate void PlatformMessageResponseCallback(byte* data, int dataLength);
public delegate void PlatformMessageResponseCallback(byte[] data);
public unsafe delegate void PlatformMessageCallback(
[MarshalAs(UnmanagedType.LPStr)] string name, byte* data, int dataLength,
PlatformMessageResponseCallback callback);
public delegate Future PlatformMessageCallback(
string name, byte[] data, PlatformMessageResponseCallback callback);
delegate void _SetNeedsReportTimingsFunc(IntPtr ptr, bool value);

public class Window {
internal IntPtr _ptr;
internal object _binding;
internal UIWidgetsPanel _panel;
internal _AsyncCallbackState _asyncCallbackState;
internal Window() {
_setNeedsReportTimings = Window_setNeedsReportTimings;

public VoidCallback onAccessibilityFeaturesChanged { get; set; }
public unsafe void sendPlatformMessage(string name,
byte* data, int dataLength,
PlatformMessageResponseCallback callback) {
IntPtr errorPtr =
Window_sendPlatformMessage(_ptr, name, callback, data, dataLength);
if (errorPtr != IntPtr.Zero)
throw new Exception(Marshal.PtrToStringAnsi(errorPtr));
byte[] data, PlatformMessageResponseCallback callback) {
fixed (byte* bytes = data) {
var callbackHandle = GCHandle.Alloc(callback);
IntPtr errorPtr = Window_sendPlatformMessage(name, _sendPlatformMessageCallback,
(IntPtr) callbackHandle, bytes, data?.Length ?? 0);
if (errorPtr != IntPtr.Zero) {
callbackHandle.Free();
throw new Exception(Marshal.PtrToStringAnsi(errorPtr));
}
}
}
public PlatformMessageCallback onPlatformMessage {
get { return _onPlatformMessage; }
set {
_onPlatformMessage = value;
_onPlatformMessageZone = Zone.current;
}
public PlatformMessageCallback onPlatformMessage { get; set; }
PlatformMessageCallback _onPlatformMessage;
internal Zone _onPlatformMessageZone;
unsafe void _respondToPlatformMessage(int responseId, byte* data, int dataLength) {
Window_respondToPlatformMessage(_ptr, responseId, data, dataLength);
internal unsafe void _respondToPlatformMessage(int responseId, byte[] data) {
fixed (byte* bytes = data) {
Window_respondToPlatformMessage(_ptr, responseId, bytes, data?.Length ?? 0);
}
}
[DllImport(NativeBindings.dllName)]

[DllImport(NativeBindings.dllName)]
static extern void Window_render(IntPtr ptr, IntPtr scene);
[MonoPInvokeCallback(typeof(Window_sendPlatformMessageCallback))]
static unsafe void _sendPlatformMessageCallback(IntPtr callbackHandle, byte* data, int dataLength) {
GCHandle handle = (GCHandle) callbackHandle;
var callback = (PlatformMessageResponseCallback) handle.Target;
handle.Free();
byte[] bytes = null;
if (data != null && dataLength != 0) {
bytes = new byte[dataLength];
Marshal.Copy((IntPtr) data, bytes, 0, dataLength);
}
try {
callback(bytes);
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
unsafe delegate void Window_sendPlatformMessageCallback(IntPtr callbackHandle, byte* data, int dataLength);
static extern unsafe IntPtr Window_sendPlatformMessage(IntPtr ptr, string name,
PlatformMessageResponseCallback callback,
static extern unsafe IntPtr Window_sendPlatformMessage(string name,
Window_sendPlatformMessageCallback callback, IntPtr callbackHandle,
byte* data, int dataLength);
[DllImport(NativeBindings.dllName)]

6
engine/Build.bee.cs


"src/lib/ui/painting/vertices.cc",
"src/lib/ui/painting/vertices.h",
"src/lib/ui/window/platform_message.cc",
"src/lib/ui/window/platform_message.h",
"src/lib/ui/window/platform_message_response_mono.cc",
"src/lib/ui/window/platform_message_response_mono.h",
"src/lib/ui/window/platform_message.cc",
"src/lib/ui/window/platform_message.h",
"src/lib/ui/window/pointer_data.cc",
"src/lib/ui/window/pointer_data.h",
"src/lib/ui/window/pointer_data_packet.cc",

93
engine/src/lib/ui/window/window.cc


#include "lib/ui/compositing/scene.h"
#include "lib/ui/ui_mono_state.h"
#include "platform_message_response_mono.h"
namespace uiwidgets {
namespace {

typedef void (*Window_drawFrameCallback)();
Window_drawFrameCallback Window_drawFrame_;
typedef void (*Window_dispatchPlatformMessageCallback)(const char* name,
const uint8_t* data,
int data_length,
int response_id);
Window_dispatchPlatformMessageCallback Window_dispatchPlatformMessage_;
Window_hook(Window_constructorCallback Window_constructor,
Window_disposeCallback Window_dispose,
Window_updateWindowMetricsCallback Window_updateWindowMetrics,
Window_beginFrameCallback Window_beginFrame,
Window_drawFrameCallback Window_drawFrame) {
Window_hook(
Window_constructorCallback Window_constructor,
Window_disposeCallback Window_dispose,
Window_updateWindowMetricsCallback Window_updateWindowMetrics,
Window_beginFrameCallback Window_beginFrame,
Window_drawFrameCallback Window_drawFrame,
Window_dispatchPlatformMessageCallback Window_dispatchPlatformMessage) {
Window_dispatchPlatformMessage_ = Window_dispatchPlatformMessage;
}
UIWIDGETS_API(Mono_Handle) Window_instance() {

ptr->client()->ScheduleFrame();
}
typedef void (*Window_sendPlatformMessageCallback)(Mono_Handle callback_handle,
const uint8_t* data,
int data_length);
UIWIDGETS_API(const char*)
Window_sendPlatformMessage(char* name,
Window_sendPlatformMessageCallback callback,
Mono_Handle callback_handle, const uint8_t* data,
int data_length) {
UIMonoState* dart_state = UIMonoState::Current();
if (!dart_state->window()) {
return "Platform messages can only be sent from the main isolate";
}
fml::RefPtr<PlatformMessageResponse> response;
if (callback != nullptr) {
response = fml::MakeRefCounted<PlatformMessageResponseMono>(
dart_state->GetWeakPtr(), callback, callback_handle,
dart_state->GetTaskRunners().GetUITaskRunner());
}
if (data == nullptr) {
dart_state->window()->client()->HandlePlatformMessage(
fml::MakeRefCounted<PlatformMessage>(name, response));
} else {
dart_state->window()->client()->HandlePlatformMessage(
fml::MakeRefCounted<PlatformMessage>(
name, std::vector<uint8_t>(data, data + data_length), response));
}
return nullptr;
}
UIWIDGETS_API(void)
Window_respondToPlatformMessage(Window* ptr, int response_id,
const uint8_t* data, int data_length) {
if (data == nullptr || data_length == 0) {
ptr->CompletePlatformMessageEmptyResponse(response_id);
} else {
ptr->CompletePlatformMessageResponse(
response_id, std::vector<uint8_t>(data, data + data_length));
}
}
UIWIDGETS_API(void) Window_render(Window* ptr, Scene* scene) {
ptr->client()->Render(scene);
}

void Window::UpdateAccessibilityFeatures(int32_t values) {}
void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {}
void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
std::shared_ptr<MonoState> mono_state = mono_state_.lock();
if (!mono_state) {
FML_DLOG(WARNING)
<< "Dropping platform message for lack of MonoState on channel: "
<< message->channel();
return;
}
MonoState::Scope scope(mono_state);
int response_id = 0;
if (auto response = message->response()) {
response_id = next_response_id_++;
pending_responses_[response_id] = response;
}
const uint8_t* data = nullptr;
int data_length = 0;
if (message->hasData()) {
data = message->data().data();
data_length = static_cast<int>(message->data().size());
}
Window_dispatchPlatformMessage_(message->channel().c_str(), data, data_length,
response_id);
}
void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) {}

19
engine/src/shell/platform/unity/uiwidgets_panel.cc


UIWidgetsPanel::~UIWidgetsPanel() = default;
void UIWidgetsPanel::OnEnable(void* native_texture_ptr, size_t width,
size_t height, float device_pixel_ratio) {
size_t height, float device_pixel_ratio,
const char* streaming_assets_path) {
surface_manager_ = std::make_unique<UnitySurfaceManager>(
UIWidgetsSystem::GetInstancePtr()->GetUnityInterfaces());

UIWidgetsProjectArgs args = {};
args.struct_size = sizeof(UIWidgetsProjectArgs);
args.assets_path = "";
args.assets_path = streaming_assets_path;
args.icu_data_path = "";
args.command_line_argc = 0;

void UIWidgetsPanel::MonoEntrypoint() { entrypoint_callback_(handle_); }
void UIWidgetsPanel::OnDisable() {
// drain pending messages
// drain pending messages
// drain pending vsync batons
// drain pending vsync batons
ProcessVSync();
UIWidgetsSystem::GetInstancePtr()->UnregisterPanel(this);

});
ViewportMetrics metrics;
metrics.physical_width = width;
metrics.physical_height = height;
metrics.physical_width = static_cast<float>(width);
metrics.physical_height = static_cast<float>(height);
metrics.device_pixel_ratio = device_pixel_ratio;
reinterpret_cast<EmbedderEngine*>(engine_)->SetViewportMetrics(metrics);
}

UIWIDGETS_API(void)
UIWidgetsPanel_onEnable(UIWidgetsPanel* panel, void* native_texture_ptr,
size_t width, size_t height, float device_pixel_ratio) {
panel->OnEnable(native_texture_ptr, width, height, device_pixel_ratio);
size_t width, size_t height, float device_pixel_ratio,
const char* streaming_assets_path) {
panel->OnEnable(native_texture_ptr, width, height, device_pixel_ratio,
streaming_assets_path);
}
UIWIDGETS_API(void) UIWidgetsPanel_onDisable(UIWidgetsPanel* panel) {

2
engine/src/shell/platform/unity/uiwidgets_panel.h


~UIWidgetsPanel();
void OnEnable(void* native_texture_ptr, size_t width, size_t height,
float device_pixel_ratio);
float device_pixel_ratio, const char* streaming_assets_path);
void MonoEntrypoint();

9
engine/src/shell/platform/unity/win32_task_runner.cc


}
}
for (const auto& observer : task_observers_) {
observer.second();
}
// Fire expired tasks.
{
// Flushing tasks here without holing onto the task queue mutex.

}
}
if (!expired_tasks.empty())
{
if (!expired_tasks.empty()) {
}
}
// Calculate duration to sleep for on next iteration.
{

33
com.unity.uiwidgets/Runtime/foundation/isolates.cs


using System.ComponentModel;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.ui2;
namespace Unity.UIWidgets.foundation {
public delegate R ComputeCallback<Q, R>(Q message);
public static partial class foundation_ {
public static Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message, string debugLabel = null) {
var completer = Completer.create();
var isolate = Isolate.current;
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (sender, args) => { args.Result = callback((Q) args.Argument); };
backgroundWorker.RunWorkerCompleted += (o, a) => {
if (!isolate.isValid) {
return;
}
using (Isolate.getScope(isolate)) {
if (a.Error != null) {
completer.completeError(a.Error);
}
else {
completer.complete(FutureOr.value((R) a.Result));
}
}
};
backgroundWorker.RunWorkerAsync(message);
return completer.future.to<R>();
}
}
}

3
com.unity.uiwidgets/Runtime/foundation/isolates.cs.meta


fileFormatVersion: 2
guid: 49ca84be53324d319a12e00ce498586d
timeCreated: 1600226656

11
com.unity.uiwidgets/Runtime/foundation/object.cs


namespace Unity.UIWidgets.foundation {
public static partial class foundation_ {
public static string objectRuntimeType(object @object, string optimizedValue) {
D.assert(() => {
optimizedValue = @object.GetType().ToString();
return true;
});
return optimizedValue;
}
}
}

3
com.unity.uiwidgets/Runtime/foundation/object.cs.meta


fileFormatVersion: 2
guid: 22e45882692145ac80b92b36da3a9a95
timeCreated: 1600152523

202
com.unity.uiwidgets/Runtime/foundation/serialization.cs


using System;
namespace Unity.UIWidgets.foundation {
public class WriteBuffer {
public WriteBuffer() {
_buffer = new byte[0];
_position = 0;
}
byte[] _buffer;
int _position;
void _ensureCapacity(int value) {
if (value <= _buffer.Length)
return;
int capacity = value;
if (capacity < 256)
capacity = 256;
if (capacity < _buffer.Length * 2)
capacity = _buffer.Length * 2;
if ((uint) (_buffer.Length * 2) > 2147483591U)
capacity = value > 2147483591 ? value : 2147483591;
byte[] buffer = new byte[capacity];
if (_buffer.Length > 0)
Buffer.BlockCopy(_buffer, 0, buffer, 0, _buffer.Length);
_buffer = buffer;
}
public void putUint8(byte value) {
_ensureCapacity(_position + 1);
_buffer[_position] = value;
_position++;
}
public unsafe void putUint16(ushort value) {
_ensureCapacity(_position + 2);
fixed (byte* ptr = &_buffer[_position])
*(ushort*) ptr = value;
_position += 2;
}
public unsafe void putUint32(uint value) {
_ensureCapacity(_position + 4);
fixed (byte* ptr = &_buffer[_position])
*(uint*) ptr = value;
_position += 4;
}
public unsafe void putInt32(int value) {
_ensureCapacity(_position + 4);
fixed (byte* ptr = &_buffer[_position])
*(int*) ptr = value;
_position += 4;
}
public unsafe void putInt64(long value) {
_ensureCapacity(_position + 8);
fixed (byte* ptr = &_buffer[_position])
*(long*) ptr = value;
_position += 8;
}
public unsafe void putFloat32(float value) {
_alignTo(4);
_ensureCapacity(_position + 4);
fixed (byte* ptr = &_buffer[_position])
*(float*) ptr = value;
_position += 4;
}
public void putUint8List(byte[] list) {
int lengthInBytes = list.Length;
_ensureCapacity(_position + lengthInBytes);
Buffer.BlockCopy(list, 0, _buffer, _position, lengthInBytes);
_position += lengthInBytes;
}
public void putInt32List(int[] list) {
_alignTo(4);
int lengthInBytes = list.Length * 4;
_ensureCapacity(_position + lengthInBytes);
Buffer.BlockCopy(list, 0, _buffer, _position, lengthInBytes);
_position += lengthInBytes;
}
public void putInt64List(long[] list) {
_alignTo(8);
int lengthInBytes = list.Length * 8;
_ensureCapacity(_position + lengthInBytes);
Buffer.BlockCopy(list, 0, _buffer, _position, lengthInBytes);
_position += lengthInBytes;
}
public void putFloat32List(float[] list) {
_alignTo(4);
int lengthInBytes = list.Length * 4;
_ensureCapacity(_position + lengthInBytes);
Buffer.BlockCopy(list, 0, _buffer, _position, lengthInBytes);
_position += lengthInBytes;
}
void _alignTo(int alignment) {
var mod = _position % alignment;
if (mod != 0) {
for (int i = 0; i < alignment - mod; i++)
putUint8(0);
}
}
public byte[] done() {
var bytes = new byte[_position];
Buffer.BlockCopy(_buffer, 0, bytes, 0, _position);
_buffer = null;
return bytes;
}
}
public class ReadBuffer {
public ReadBuffer(byte[] data) {
D.assert(data != null);
this.data = data;
}
public readonly byte[] data;
int _position = 0;
public bool hasRemaining => _position < data.Length;
public byte getUint8() {
return data[_position++];
}
public unsafe ushort getUint16() {
fixed (byte* ptr = &data[_position += 2])
return *(ushort*) ptr;
}
public unsafe uint getUint32() {
fixed (byte* ptr = &data[_position += 4])
return *(uint*) ptr;
}
public unsafe int getInt32() {
fixed (byte* ptr = &data[_position += 4])
return *(int*) ptr;
}
public unsafe long getInt64() {
fixed (byte* ptr = &data[_position += 8])
return *(long*) ptr;
}
public unsafe float getFloat32() {
_alignTo(4);
fixed (byte* ptr = &data[_position += 4])
return *(float*) ptr;
}
public byte[] getUint8List(int length) {
byte[] list = new byte[length];
int lengthInBytes = length;
Buffer.BlockCopy(data, _position, list, 0, lengthInBytes);
_position += lengthInBytes;
return list;
}
public int[] getInt32List(int length) {
_alignTo(4);
int[] list = new int[length];
int lengthInBytes = length * 4;
Buffer.BlockCopy(data, _position, list, 0, lengthInBytes);
_position += lengthInBytes;
return list;
}
public long[] getInt64List(int length) {
_alignTo(8);
long[] list = new long[length];
int lengthInBytes = length * 8;
Buffer.BlockCopy(data, _position, list, 0, lengthInBytes);
_position += lengthInBytes;
return list;
}
public float[] getFloat32List(int length) {
_alignTo(4);
float[] list = new float[length];
int lengthInBytes = length * 4;
Buffer.BlockCopy(data, _position, list, 0, lengthInBytes);
_position += lengthInBytes;
return list;
}
void _alignTo(int alignment) {
int mod = _position % alignment;
if (mod != 0)
_position += alignment - mod;
}
}
}

3
com.unity.uiwidgets/Runtime/foundation/serialization.cs.meta


fileFormatVersion: 2
guid: 400db01fc64b47479eae0c633ef6b721
timeCreated: 1599625046

53
com.unity.uiwidgets/Runtime/foundation/synchronous_future.cs


using System;
using Unity.UIWidgets.async2;
namespace Unity.UIWidgets.foundation {
public class SynchronousFuture : Future {
public SynchronousFuture(object value) {
_value = value;
}
readonly object _value;
// @override
// Stream<T> asStream() {
// final StreamController<T> controller = StreamController<T>();
// controller.add(_value);
// controller.close();
// return controller.stream;
// }
public override Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null) {
return Completer.create().future;
}
public override Future then(Func<object, FutureOr> f, Func<Exception, FutureOr> onError = null) {
FutureOr result = f(_value);
if (result.isFuture)
return result.f;
return new SynchronousFuture(result.v);
}
public override Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null) {
return Future.value(FutureOr.value(_value)).timeout(timeLimit, onTimeout: onTimeout);
}
public override Future whenComplete(Func<FutureOr> action) {
try {
FutureOr result = action();
if (result.isFuture)
return result.f.then((value) => FutureOr.value(_value));
return this;
}
catch (Exception e) {
return Future.error(e);
}
}
}
public class SynchronousFuture<T> : Future<T> {
public SynchronousFuture(T value) : base(new SynchronousFuture(value)) {
}
}
}

3
com.unity.uiwidgets/Runtime/foundation/synchronous_future.cs.meta


fileFormatVersion: 2
guid: 00836efc8fdd45bf800d682996a7952a
timeCreated: 1600228109

159
com.unity.uiwidgets/Runtime/painting/shader_warmup.cs


using System.Collections.Generic;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.ui;
using Canvas = Unity.UIWidgets.ui2.Canvas;
using Paint = Unity.UIWidgets.ui2.Paint;
using PaintingStyle = Unity.UIWidgets.ui2.PaintingStyle;
using Path = Unity.UIWidgets.ui2.Path;
using Picture = Unity.UIWidgets.ui2.Picture;
using PictureRecorder = Unity.UIWidgets.ui2.PictureRecorder;
using Color = Unity.UIWidgets.ui2.Color;
namespace Unity.UIWidgets.painting {
public abstract class ShaderWarmUp {
protected ShaderWarmUp() {
}
public virtual Size size => new Size(100.0f, 100.0f);
protected abstract Future warmUpOnCanvas(Canvas canvas);
public Future execute() {
PictureRecorder recorder = new PictureRecorder();
Canvas canvas = new Canvas(recorder);
return warmUpOnCanvas(canvas).then(_ => {
Picture picture = recorder.endRecording();
//TimelineTask shaderWarmUpTask = TimelineTask();
//shaderWarmUpTask.start('Warm-up shader');
picture.toImage(size.width.ceil(), size.height.ceil()).then(__ => {
//shaderWarmUpTask.finish();
return FutureOr.nil;
});
return FutureOr.nil;
});
}
}
public class DefaultShaderWarmUp : ShaderWarmUp {
public DefaultShaderWarmUp(
float drawCallSpacing = 0.0f,
Size canvasSize = null
) {
canvasSize = canvasSize ?? new Size(100.0f, 100.0f);
this.drawCallSpacing = drawCallSpacing;
this.canvasSize = canvasSize;
}
public readonly float drawCallSpacing;
public readonly Size canvasSize;
public override Size size => canvasSize;
/// Trigger common draw operations on a canvas to warm up GPU shader
/// compilation cache.
protected override Future warmUpOnCanvas(Canvas canvas) {
RRect rrect = RRect.fromLTRBXY(20.0f, 20.0f, 60.0f, 60.0f, 10.0f, 10.0f);
Path rrectPath = new Path();
rrectPath.addRRect(rrect);
Path circlePath = new Path();
circlePath.addOval(
Rect.fromCircle(center: new Offset(40.0f, 40.0f), radius: 20.0f)
);
// The following path is based on
// https://skia.org/user/api/SkCanvas_Reference#SkCanvas_drawPath
Path path = new Path();
path.moveTo(20.0f, 60.0f);
path.quadraticBezierTo(60.0f, 20.0f, 60.0f, 60.0f);
path.close();
path.moveTo(60.0f, 20.0f);
path.quadraticBezierTo(60.0f, 60.0f, 20.0f, 60.0f);
Path convexPath = new Path();
convexPath.moveTo(20.0f, 30.0f);
convexPath.lineTo(40.0f, 20.0f);
convexPath.lineTo(60.0f, 30.0f);
convexPath.lineTo(60.0f, 60.0f);
convexPath.lineTo(20.0f, 60.0f);
convexPath.close();
// Skia uses different shaders based on the kinds of paths being drawn and
// the associated paint configurations. According to our experience and
// tracing, drawing the following paths/paints generates various of
// shaders that are commonly used.
List<Path> paths = new List<Path> {rrectPath, circlePath, path, convexPath};
List<Paint> paints = new List<Paint> {
new Paint {
isAntiAlias = true,
style = PaintingStyle.fill
},
new Paint {
isAntiAlias = false,
style = PaintingStyle.fill
},
new Paint {
isAntiAlias = true,
style = PaintingStyle.stroke,
strokeWidth = 10
},
new Paint {
isAntiAlias = true,
style = PaintingStyle.stroke,
strokeWidth = 0.1f, // hairline
}
};
// Warm up path stroke and fill shaders.
for (int i = 0; i < paths.Count; i += 1) {
canvas.save();
foreach (var paint in paints) {
canvas.drawPath(paths[i], paint);
canvas.translate(drawCallSpacing, 0.0f);
}
canvas.restore();
canvas.translate(0.0f, drawCallSpacing);
}
// Warm up shadow shaders.
Color black = new Color(0xFF000000);
canvas.save();
canvas.drawShadow(rrectPath, black, 10.0f, true);
canvas.translate(drawCallSpacing, 0.0f);
canvas.drawShadow(rrectPath, black, 10.0f, false);
canvas.restore();
// Warm up text shaders.
canvas.translate(0.0f, drawCallSpacing);
// final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(
// ui.ParagraphStyle(textDirection: ui.TextDirection.ltr),
// )..pushStyle(ui.TextStyle(color: black))..addText('_');
// final ui.Paragraph paragraph = paragraphBuilder.build()
// ..layout(const ui.ParagraphConstraints (width: 60.0));
// canvas.drawParagraph(paragraph, const ui.Offset (20.0, 20.0));
// Draw a rect inside a rrect with a non-trivial intersection. If the
// intersection is trivial (e.g., equals the rrect clip), Skia will optimize
// the clip out.
//
// Add an integral or fractional translation to trigger Skia's non-AA or AA
// optimizations (as did before in normal FillRectOp in rrect clip cases).
foreach (var fraction in new[] {0.0f, 0.5f}) {
canvas.save();
canvas.translate(fraction, fraction);
canvas.clipRRect(RRect.fromLTRBR(8, 8, 328, 248, Radius.circular(16)));
canvas.drawRect(Rect.fromLTRB(10, 10, 320, 240), new Paint());
canvas.restore();
canvas.translate(drawCallSpacing, 0.0f);
}
canvas.translate(0.0f, drawCallSpacing);
return Future.value();
}
}
}

3
com.unity.uiwidgets/Runtime/painting/shader_warmup.cs.meta


fileFormatVersion: 2
guid: 267de2236edc47de871b74a567a94a68
timeCreated: 1599468005

3
com.unity.uiwidgets/Runtime/services.meta


fileFormatVersion: 2
guid: 6c09aa2afc094af0b1e04e39c0aa59a6
timeCreated: 1599611392

158
com.unity.uiwidgets/Runtime/ui2/channel_buffers.cs


using System;
using System.Collections.Generic;
using System.Text;
using Unity.UIWidgets.async2;
using UnityEngine;
namespace Unity.UIWidgets.ui2 {
readonly struct _StoredMessage {
internal _StoredMessage(byte[] data, PlatformMessageResponseCallback callback) {
_data = data;
_callback = callback;
}
readonly byte[] _data;
public byte[] data => _data;
readonly PlatformMessageResponseCallback _callback;
public PlatformMessageResponseCallback callback => _callback;
}
class _RingBuffer<T> where T : struct {
readonly Queue<T> _queue;
internal _RingBuffer(int capacity) {
_capacity = capacity;
_queue = new Queue<T>(_capacity);
}
public int length => _queue.Count;
int _capacity;
public int capacity => _capacity;
public bool isEmpty => _queue.Count == 0;
Action<T> _dropItemCallback;
public Action<T> dropItemCallback {
set { _dropItemCallback = value; }
}
public bool push(in T val) {
if (_capacity <= 0)
return true;
int overflowCount = _dropOverflowItems(_capacity - 1);
_queue.Enqueue(val);
return overflowCount > 0;
}
public T? pop() {
return _queue.Count == 0 ? (T?) null : _queue.Dequeue();
}
int _dropOverflowItems(int lengthLimit) {
int result = 0;
while (_queue.Count > lengthLimit) {
T item = _queue.Dequeue();
_dropItemCallback?.Invoke(item);
result += 1;
}
return result;
}
public int resize(int newSize) {
_capacity = newSize;
return _dropOverflowItems(newSize);
}
}
public delegate Future DrainChannelCallback(byte[] data, PlatformMessageResponseCallback callback);
public class ChannelBuffers {
public const int kDefaultBufferSize = 1;
public const string kControlChannelName = "dev.uiwidgets/channel-buffers";
readonly Dictionary<string, _RingBuffer<_StoredMessage>> _messages =
new Dictionary<string, _RingBuffer<_StoredMessage>>();
_RingBuffer<_StoredMessage> _makeRingBuffer(int size) =>
new _RingBuffer<_StoredMessage>(size) {dropItemCallback = _onDropItem};
void _onDropItem(_StoredMessage message) {
message.callback(null);
}
public bool push(string channel, byte[] data, PlatformMessageResponseCallback callback) {
_RingBuffer<_StoredMessage> queue = _messages[channel];
if (queue == null) {
queue = _makeRingBuffer(kDefaultBufferSize);
_messages[channel] = queue;
}
bool didOverflow = queue.push(new _StoredMessage(data, callback));
if (didOverflow) {
Debug.LogWarning($"Overflow on channel: {channel}. " +
"Messages on this channel are being discarded in FIFO fashion. " +
"The engine may not be running or you need to adjust " +
"the buffer size of the channel.");
}
return didOverflow;
}
_StoredMessage? _pop(string channel) {
_RingBuffer<_StoredMessage> queue = _messages[channel];
_StoredMessage? result = queue?.pop();
return result;
}
void _resize(string channel, int newSize) {
_RingBuffer<_StoredMessage> queue = _messages[channel];
if (queue == null) {
queue = _makeRingBuffer(newSize);
_messages[channel] = queue;
}
else {
int numberOfDroppedMessages = queue.resize(newSize);
if (numberOfDroppedMessages > 0) {
Debug.LogWarning(
$"Dropping messages on channel \"{channel}\" as a result of shrinking the buffer size.");
}
}
}
public Future drain(string channel, DrainChannelCallback callback) {
return Future.doWhile(() => {
_StoredMessage? message = _pop(channel);
if (!message.HasValue) {
return false;
}
return callback(message.Value.data, message.Value.callback);
});
}
string _getString(byte[] data) {
return Encoding.UTF8.GetString(data);
}
public void handleMessage(byte[] data) {
var command = _getString(data).Split('\r');
if (command.Length == /*arity=*/2 + 1 && command[0] == "resize") {
_resize(command[1], int.Parse(command[2]));
}
else {
throw new Exception($"Unrecognized command {command} sent to {kControlChannelName}.");
}
}
}
public static partial class ui_ {
public static readonly ChannelBuffers channelBuffers = new ChannelBuffers();
}
}

3
com.unity.uiwidgets/Runtime/ui2/channel_buffers.cs.meta


fileFormatVersion: 2
guid: 8b23ea154160494fba86a467f9c29489
timeCreated: 1599613180

50
engine/src/lib/ui/window/platform_message_response_mono.cc


#include "platform_message_response_mono.h"
#include <utility>
#include "common/task_runners.h"
#include "flutter/fml/make_copyable.h"
#include "lib/ui/window/window.h"
namespace uiwidgets {
PlatformMessageResponseMono::PlatformMessageResponseMono(
std::weak_ptr<MonoState> mono_state_weak, PlatformMessageCallback callback,
Mono_Handle handle, fml::RefPtr<fml::TaskRunner> ui_task_runner)
: mono_state_weak_(mono_state_weak),
callback_(std::move(callback)),
handle_(handle),
ui_task_runner_(std::move(ui_task_runner)) {}
PlatformMessageResponseMono::~PlatformMessageResponseMono() {}
void PlatformMessageResponseMono::Complete(std::unique_ptr<fml::Mapping> data) {
if (callback_ == nullptr) return;
FML_DCHECK(!is_complete_);
is_complete_ = true;
ui_task_runner_->PostTask(fml::MakeCopyable(
[mono_state_weak = mono_state_weak_, callback = callback_,
handle = handle_, data = std::move(data)]() {
const std::shared_ptr<MonoState> mono_state = mono_state_weak.lock();
if (!mono_state) return;
MonoState::Scope scope(mono_state);
callback(handle, data->GetMapping(), static_cast<int>(data->GetSize()));
}));
}
void PlatformMessageResponseMono::CompleteEmpty() {
if (callback_ == nullptr) return;
FML_DCHECK(!is_complete_);
is_complete_ = true;
ui_task_runner_->PostTask([mono_state_weak = mono_state_weak_,
callback = callback_, handle = handle_]() {
const std::shared_ptr<MonoState> mono_state = mono_state_weak.lock();
if (!mono_state) return;
MonoState::Scope scope(mono_state);
callback(handle, nullptr, 0);
});
}
} // namespace uiwidgets

33
engine/src/lib/ui/window/platform_message_response_mono.h


#pragma once
#include "flutter/fml/message_loop.h"
#include "platform_message_response.h"
#include "runtime/mono_state.h"
namespace uiwidgets {
class PlatformMessageResponseMono : public PlatformMessageResponse {
FML_FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseMono);
public:
void Complete(std::unique_ptr<fml::Mapping> data) override;
void CompleteEmpty() override;
typedef void (*PlatformMessageCallback)(Mono_Handle callback_handle,
const uint8_t* data, int data_length);
protected:
explicit PlatformMessageResponseMono(
std::weak_ptr<MonoState> mono_state_weak,
PlatformMessageCallback callback, Mono_Handle handle,
fml::RefPtr<fml::TaskRunner> ui_task_runner);
~PlatformMessageResponseMono() override;
std::weak_ptr<MonoState> mono_state_weak_;
PlatformMessageCallback callback_;
Mono_Handle handle_;
fml::RefPtr<fml::TaskRunner> ui_task_runner_;
};
} // namespace uiwidgets

161
com.unity.uiwidgets/Runtime/services/asset_bundle.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.engine2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui2;
using UnityEngine.Networking;
namespace Unity.UIWidgets.services {
public abstract class AssetBundle {
public abstract Future<byte[]> load(string key);
public virtual Future<string> loadString(string key, bool cache = true) {
return load(key).then<string>(data => {
if (data == null)
throw new UIWidgetsError($"Unable to load asset: {key}");
if (data.Length < 10 * 1024) {
// 10KB takes about 3ms to parse on a Pixel 2 XL.
// See: https://github.com/dart-lang/sdk/issues/31954
return Encoding.UTF8.GetString(data);
}
return foundation_.compute(Encoding.UTF8.GetString, data, debugLabel: $"UTF8 decode for \"{key}\"");
});
}
public abstract Future<T> loadStructuredData<T>(String key, Func<string, Future<T>> parser);
public virtual void evict(String key) {
}
public override string ToString() => $"{Diagnostics.describeIdentity(this)}()";
}
public class NetworkAssetBundle : AssetBundle {
public NetworkAssetBundle(Uri baseUrl, IDictionary<string, string> headers = null) {
_baseUrl = baseUrl;
this.headers = headers;
}
public readonly IDictionary<string, string> headers;
readonly Uri _baseUrl;
Uri _urlFromKey(string key) => new Uri(_baseUrl, key);
IEnumerator _loadCoroutine(string key, Completer completer, Isolate isolate) {
var url = _urlFromKey(key);
using (var www = UnityWebRequest.Get(url)) {
if (headers != null) {
foreach (var header in headers) {
www.SetRequestHeader(header.Key, header.Value);
}
}
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError) {
completer.completeError(new Exception($"Failed to load from url \"{url}\": {www.error}"));
yield break;
}
var data = www.downloadHandler.data;
using (Isolate.getScope(isolate)) {
completer.complete(data);
}
}
}
public override Future<byte[]> load(string key) {
var completer = Completer.create();
var isolate = Isolate.current;
var panel = UIWidgetsPanel.current;
panel.StartCoroutine(_loadCoroutine(key, completer, isolate));
return completer.future.to<byte[]>();
}
public override Future<T> loadStructuredData<T>(string key, Func<string, Future<T>> parser) {
D.assert(key != null);
D.assert(parser != null);
return loadString(key).then<T>(value => parser(value));
}
public override string ToString() => $"{Diagnostics.describeIdentity(this)}({_baseUrl})";
}
public abstract class CachingAssetBundle : AssetBundle {
readonly Dictionary<string, Future<string>> _stringCache = new Dictionary<string, Future<string>>();
readonly Dictionary<string, Future> _structuredDataCache = new Dictionary<string, Future>();
public override Future<string> loadString(string key, bool cache = true) {
if (cache)
return _stringCache.putIfAbsent(key, () => base.loadString(key));
return base.loadString(key);
}
public override Future<T> loadStructuredData<T>(String key, Func<string, Future<T>> parser) {
D.assert(key != null);
D.assert(parser != null);
if (_structuredDataCache.ContainsKey(key))
return _structuredDataCache[key].to<T>();
Completer completer = null;
Future<T> result = null;
loadString(key, cache: false).then<T>(value => parser(value)).then<object>((T value) => {
result = new SynchronousFuture<T>(value);
_structuredDataCache[key] = result;
if (completer != null) {
// We already returned from the loadStructuredData function, which means
// we are in the asynchronous mode. Pass the value to the completer. The
// completer's future is what we returned.
completer.complete(FutureOr.value(value));
}
return FutureOr.nil;
});
if (result != null) {
// The code above ran synchronously, and came up with an answer.
// Return the SynchronousFuture that we created above.
return result;
}
// The code above hasn't yet run its "then" handler yet. Let's prepare a
// completer for it to use when it does run.
completer = Completer.create();
_structuredDataCache[key] = result = completer.future.to<T>();
return result;
}
public override void evict(string key) {
_stringCache.Remove(key);
_structuredDataCache.Remove(key);
}
}
public class PlatformAssetBundle : CachingAssetBundle {
public override Future<byte[]> load(string key) {
byte[] encoded = Encoding.UTF8.GetBytes(key);
return ServicesBinding.instance.defaultBinaryMessenger.send(
"uiwidgets/assets", encoded).then<byte[]>(asset => {
if (asset == null)
throw new UIWidgetsError($"Unable to load asset: {key}");
return asset;
});
}
}
public static partial class services_ {
static AssetBundle _initRootBundle() {
return new PlatformAssetBundle();
}
public static readonly AssetBundle rootBundle = _initRootBundle();
}
}

3
com.unity.uiwidgets/Runtime/services/asset_bundle.cs.meta


fileFormatVersion: 2
guid: 140612c411134f2791d26fb58b86fc25
timeCreated: 1600225242

15
com.unity.uiwidgets/Runtime/services/binary_messenger.cs


using System;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.ui2;
namespace Unity.UIWidgets.services {
public delegate Future<byte[]> MessageHandler(byte[] message);
public interface BinaryMessenger {
Future handlePlatformMessage(string channel, byte[] data, PlatformMessageResponseCallback callback);
Future<byte[]> send(string channel, byte[] message);
void setMessageHandler(string channel, MessageHandler handler);
}
}

3
com.unity.uiwidgets/Runtime/services/binary_messenger.cs.meta


fileFormatVersion: 2
guid: 541c41d108bd4f699a27646da8b52a38
timeCreated: 1599611703

104
com.unity.uiwidgets/Runtime/services/binding.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui2;
namespace Unity.UIWidgets.services {
public class ServicesBinding : BindingBase {
protected override void initInstances() {
base.initInstances();
instance = this;
_defaultBinaryMessenger = createBinaryMessenger();
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
//initLicenses();
//SystemChannels.system.setMessageHandler(handleSystemMessage);
}
public static ServicesBinding instance {
get { return (ServicesBinding) Window.instance._binding; }
private set { Window.instance._binding = value; }
}
public BinaryMessenger defaultBinaryMessenger => _defaultBinaryMessenger;
BinaryMessenger _defaultBinaryMessenger;
protected BinaryMessenger createBinaryMessenger() {
return new _DefaultBinaryMessenger();
}
protected virtual Future handleSystemMessage(Object systemMessage) {
return Future.value();
}
protected virtual void evict(string asset) {
services_.rootBundle.evict(asset);
}
}
class _DefaultBinaryMessenger : BinaryMessenger {
internal _DefaultBinaryMessenger() {
}
readonly Dictionary<string, MessageHandler> _handlers = new Dictionary<string, MessageHandler>();
Future<byte[]> _sendPlatformMessage(string channel, byte[] message) {
Completer completer = Completer.create();
Window.instance.sendPlatformMessage(channel, message, (reply) => {
try {
completer.complete(FutureOr.value(reply));
}
catch (Exception exception) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "services library",
context: "during a platform message response callback"
));
}
});
return completer.future.to<byte[]>();
}
public Future handlePlatformMessage(
string channel, byte[] data,
PlatformMessageResponseCallback callback) {
MessageHandler handler = _handlers[channel];
if (handler == null) {
ui_.channelBuffers.push(channel, data, callback);
return Future.value();
}
return handler(data).then(bytes => {
var response = (byte[]) bytes;
callback(response);
return FutureOr.nil;
}, onError: exception => {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "services library",
context: "during a platform message callback")
);
callback(null);
return FutureOr.nil;
});
}
public Future<byte[]> send(string channel, byte[] message) {
return _sendPlatformMessage(channel, message);
}
public void setMessageHandler(string channel, MessageHandler handler) {
if (handler == null)
_handlers.Remove(channel);
else
_handlers[channel] = handler;
ui_.channelBuffers.drain(channel,
(byte[] data, PlatformMessageResponseCallback callback) =>
handlePlatformMessage(channel, data, callback));
}
}
}

3
com.unity.uiwidgets/Runtime/services/binding.cs.meta


fileFormatVersion: 2
guid: e11e2e204ab94b0790425f27f98c8b73
timeCreated: 1599611404

67
com.unity.uiwidgets/Runtime/services/message_codec.cs


using System;
using Unity.UIWidgets.external.simplejson;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.services {
public interface MessageCodec<T> {
byte[] encodeMessage(T message);
T decodeMessage(byte[] message);
}
public readonly struct MethodCall {
public MethodCall(string method, object arguments) {
D.assert(method != null);
this.method = method;
this.arguments = arguments;
}
public readonly string method;
public readonly object arguments;
public override string ToString() =>
$"{foundation_.objectRuntimeType(this, "MethodCall")}({method}, {arguments})";
}
public interface MethodCodec {
byte[] encodeMethodCall(MethodCall methodCall);
MethodCall decodeMethodCall(byte[] methodCall);
object decodeEnvelope(byte[] envelope);
byte[] encodeSuccessEnvelope(object result);
byte[] encodeErrorEnvelope(string code, string message = null, object details = null);
}
public class PlatformException : Exception {
public PlatformException(string code,
string message = null,
object details = null) {
D.assert(code != null);
this.code = code;
this.message = message;
this.details = details;
}
public readonly string code;
public readonly string message;
public readonly object details;
public override string ToString() => $"PlatformException({code}, {message}, {details})";
}
public class MissingPluginException : Exception {
public MissingPluginException(string message = null) {
this.message = message;
}
public readonly string message;
public override string ToString() => $"MissingPluginException({message})";
}
}

3
com.unity.uiwidgets/Runtime/services/message_codec.cs.meta


fileFormatVersion: 2
guid: ca3fe165f7b04b94813a0b9c115d08c2
timeCreated: 1599790199

650
com.unity.uiwidgets/Runtime/services/message_codecs.cs


using System;
using System.Collections;
using System.Globalization;
using System.Text;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.services;
namespace Unity.UIWidgets.services {
public class BinaryCodec : MessageCodec<byte[]> {
public BinaryCodec() {
}
public static readonly BinaryCodec instance = new BinaryCodec();
public byte[] decodeMessage(byte[] message) => message;
public byte[] encodeMessage(byte[] message) => message;
}
public class StringCodec : MessageCodec<string> {
public StringCodec() {
}
public static readonly StringCodec instance = new StringCodec();
public string decodeMessage(byte[] message) {
if (message == null)
return null;
return Encoding.UTF8.GetString(message);
}
public byte[] encodeMessage(string message) {
if (message == null)
return null;
return Encoding.UTF8.GetBytes(message);
}
}
public class JSONMessageCodec : MessageCodec<object> {
public JSONMessageCodec() {
}
public static readonly JSONMessageCodec instance = new JSONMessageCodec();
public byte[] encodeMessage(object message) {
if (message == null)
return null;
var sb = new StringBuilder();
_writeToStringBuilder(message, sb);
return StringCodec.instance.encodeMessage(sb.ToString());
}
public object decodeMessage(byte[] message) {
if (message == null)
return null;
return _parseJson(StringCodec.instance.decodeMessage(message));
}
[ThreadStatic] static StringBuilder _escapeBuilder;
static StringBuilder _getEscapeBuilder() {
return _escapeBuilder ?? (_escapeBuilder = new StringBuilder());
}
static string _escape(string aText) {
var sb = _getEscapeBuilder();
sb.Length = 0;
if (sb.Capacity < aText.Length + aText.Length / 10)
sb.Capacity = aText.Length + aText.Length / 10;
foreach (char c in aText) {
switch (c) {
case '\\':
sb.Append("\\\\");
break;
case '\"':
sb.Append("\\\"");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
default:
if (c < ' ') {
ushort val = c;
sb.Append("\\u").Append(val.ToString("X4"));
}
else
sb.Append(c);
break;
}
}
string result = sb.ToString();
sb.Length = 0;
return result;
}
static void _writeToStringBuilder(object obj, StringBuilder sb) {
if (obj is IDictionary dict) {
sb.Append('{');
bool first = true;
foreach (DictionaryEntry k in dict) {
if (!first)
sb.Append(',');
first = false;
sb.Append('\"').Append(_escape(k.Key.ToString())).Append('\"');
sb.Append(':');
_writeToStringBuilder(k.Value, sb);
}
sb.Append('}');
}
else if (obj is IList list) {
sb.Append('[');
int count = list.Count;
for (int i = 0; i < count; i++) {
if (i > 0)
sb.Append(',');
_writeToStringBuilder(list[i], sb);
}
sb.Append(']');
}
else if (obj is string str) {
sb.Append('\"').Append(_escape(str)).Append('\"');
}
else if (obj is double d) {
sb.Append(d.ToString(CultureInfo.InvariantCulture));
}
else if (obj is float f) {
sb.Append(f.ToString(CultureInfo.InvariantCulture));
}
else if (obj is int i) {
sb.Append(i.ToString(CultureInfo.InvariantCulture));
}
else if (obj is long l) {
sb.Append(l.ToString(CultureInfo.InvariantCulture));
}
else if (obj is bool b) {
sb.Append(b ? "true" : "false");
}
else if (obj == null) {
sb.Append("null");
}
else {
throw new Exception("Unsupported object: " + obj);
}
}
static object _parseElement(string token, bool quoted) {
if (quoted)
return token;
string tmp = token.ToLower();
if (tmp == "false" || tmp == "true")
return tmp == "true";
if (tmp == "null")
return null;
if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out var val))
return val;
else
return token;
}
static void _addElement(object ctx, string tokenName, object element) {
if (ctx is IDictionary dict) {
dict.Add(tokenName, element);
}
else if (ctx is IList list) {
D.assert(tokenName.isEmpty);
list.Add(element);
}
else {
D.assert(ctx == null);
}
}
static object _parseJson(string jsonStr) {
Stack stack = new Stack();
object ctx = null;
int i = 0;
StringBuilder token = new StringBuilder();
string tokenName = "";
bool quoteMode = false;
bool tokenIsQuoted = false;
while (i < jsonStr.Length) {
switch (jsonStr[i]) {
case '{':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
stack.Push(new Hashtable());
_addElement(ctx, tokenName, stack.Peek());
tokenName = "";
token.Length = 0;
ctx = stack.Peek();
break;
case '[':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
stack.Push(new ArrayList());
_addElement(ctx, tokenName, stack.Peek());
tokenName = "";
token.Length = 0;
ctx = stack.Peek();
break;
case '}':
case ']':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
if (stack.Count == 0)
throw new Exception("JSON Parse: Too many closing brackets");
stack.Pop();
if (token.Length > 0 || tokenIsQuoted)
_addElement(ctx, tokenName, _parseElement(token.ToString(), tokenIsQuoted));
tokenIsQuoted = false;
tokenName = "";
token.Length = 0;
if (stack.Count > 0)
ctx = stack.Peek();
break;
case ':':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
tokenIsQuoted = false;
tokenName = token.ToString();
token.Length = 0;
break;
case '"':
quoteMode ^= true;
tokenIsQuoted |= quoteMode;
break;
case ',':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
if (token.Length > 0 || tokenIsQuoted)
_addElement(ctx, tokenName, _parseElement(token.ToString(), tokenIsQuoted));
tokenIsQuoted = false;
tokenName = "";
token.Length = 0;
break;
case '\r':
case '\n':
break;
case ' ':
case '\t':
if (quoteMode)
token.Append(jsonStr[i]);
break;
case '\\':
++i;
if (quoteMode) {
char c = jsonStr[i];
switch (c) {
case 't':
token.Append('\t');
break;
case 'r':
token.Append('\r');
break;
case 'n':
token.Append('\n');
break;
case 'b':
token.Append('\b');
break;
case 'f':
token.Append('\f');
break;
case 'u': {
string s = jsonStr.Substring(i + 1, 4);
token.Append((char) int.Parse(
s,
System.Globalization.NumberStyles.AllowHexSpecifier));
i += 4;
break;
}
default:
token.Append(c);
break;
}
}
break;
default:
token.Append(jsonStr[i]);
break;
}
++i;
}
if (quoteMode) {
throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
}
if (ctx == null)
return _parseElement(token.ToString(), tokenIsQuoted);
return ctx;
}
}
}
public class JSONMethodCodec : MethodCodec {
public JSONMethodCodec() {
}
public static readonly JSONMethodCodec instance = new JSONMethodCodec();
public byte[] encodeMethodCall(MethodCall call) {
var obj = new Hashtable {{"method", call.method}, {"args", call.arguments}};
return JSONMessageCodec.instance.encodeMessage(obj);
}
public MethodCall decodeMethodCall(byte[] methodCall) {
object decoded = JSONMessageCodec.instance.decodeMessage(methodCall);
if (!(decoded is IDictionary dict))
throw new Exception($"Expected method call JSONObject, got {decoded}");
object methodRaw = dict["method"];
object arguments = dict["args"];
if (methodRaw is string method)
return new MethodCall(method, arguments);
throw new Exception($"Invalid method call: {decoded}");
}
public object decodeEnvelope(byte[] envelope) {
object decoded = JSONMessageCodec.instance.decodeMessage(envelope);
if (!(decoded is IList list))
throw new Exception($"Expected envelope JSONArray, got {decoded}");
if (list.Count == 1)
return list[0];
if (list.Count == 3
&& list[0] is string code
&& (list[1] == null || list[1] is string))
throw new PlatformException(
code: code,
message: list[1] as string,
details: list[2]
);
throw new Exception($"Invalid envelope: {decoded}");
}
public byte[] encodeSuccessEnvelope(object result) {
var array = new ArrayList {result};
return JSONMessageCodec.instance.encodeMessage(array);
}
public byte[] encodeErrorEnvelope(string code, string message = null, object details = null) {
D.assert(code != null);
var array = new ArrayList {code, message, details};
return JSONMessageCodec.instance.encodeMessage(array);
}
}
public class StandardMessageCodec : MessageCodec<object> {
public StandardMessageCodec() {
}
public static readonly StandardMessageCodec instance = new StandardMessageCodec();
const byte _valueNull = 0;
const byte _valueTrue = 1;
const byte _valueFalse = 2;
const byte _valueInt32 = 3;
const byte _valueInt64 = 4;
const byte _valueFloat32 = 6;
const byte _valueString = 7;
const byte _valueUint8List = 8;
const byte _valueInt32List = 9;
const byte _valueInt64List = 10;
const byte _valueFloat32List = 11;
const byte _valueList = 12;
const byte _valueMap = 13;
public byte[] encodeMessage(object message) {
if (message == null)
return null;
WriteBuffer buffer = new WriteBuffer();
writeValue(buffer, message);
return buffer.done();
}
public object decodeMessage(byte[] message) {
if (message == null)
return null;
ReadBuffer buffer = new ReadBuffer(message);
object result = readValue(buffer);
if (buffer.hasRemaining)
throw new Exception("Message corrupted");
return result;
}
public void writeValue(WriteBuffer buffer, object value) {
if (value == null) {
buffer.putUint8(_valueNull);
}
else if (value is bool b) {
buffer.putUint8(b ? _valueTrue : _valueFalse);
}
else if (value is float f) {
buffer.putUint8(_valueFloat32);
buffer.putFloat32(f);
}
else if (value is int i) {
buffer.putUint8(_valueInt32);
buffer.putInt32(i);
}
else if (value is long l) {
buffer.putUint8(_valueInt64);
buffer.putInt64(l);
}
else if (value is string s) {
buffer.putUint8(_valueString);
byte[] bytes = Encoding.UTF8.GetBytes(s);
writeSize(buffer, bytes.Length);
buffer.putUint8List(bytes);
}
else if (value is byte[] bytes) {
buffer.putUint8(_valueUint8List);
writeSize(buffer, bytes.Length);
buffer.putUint8List(bytes);
}
else if (value is int[] ints) {
buffer.putUint8(_valueInt32List);
writeSize(buffer, ints.Length);
buffer.putInt32List(ints);
}
else if (value is long[] longs) {
buffer.putUint8(_valueInt64List);
writeSize(buffer, longs.Length);
buffer.putInt64List(longs);
}
else if (value is float[] floats) {
buffer.putUint8(_valueFloat32List);
writeSize(buffer, floats.Length);
buffer.putFloat32List(floats);
}
else if (value is IList list) {
buffer.putUint8(_valueList);
writeSize(buffer, list.Count);
foreach (object item in list) {
writeValue(buffer, item);
}
}
else if (value is IDictionary dict) {
buffer.putUint8(_valueMap);
writeSize(buffer, dict.Count);
foreach (DictionaryEntry entry in dict) {
writeValue(buffer, entry.Key);
writeValue(buffer, entry.Value);
}
}
else {
throw new ArgumentException(value.ToString());
}
}
public object readValue(ReadBuffer buffer) {
if (!buffer.hasRemaining)
throw new Exception("Message corrupted");
int type = buffer.getUint8();
return readValueOfType(type, buffer);
}
object readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case _valueNull:
return null;
case _valueTrue:
return true;
case _valueFalse:
return false;
case _valueInt32:
return buffer.getInt32();
case _valueInt64:
return buffer.getInt64();
case _valueFloat32:
return buffer.getFloat32();
case _valueString: {
int length = (int) readSize(buffer);
return Encoding.UTF8.GetString(buffer.getUint8List(length));
}
case _valueUint8List: {
int length = (int) readSize(buffer);
return buffer.getUint8List(length);
}
case _valueInt32List: {
int length = (int) readSize(buffer);
return buffer.getInt32List(length);
}
case _valueInt64List: {
int length = (int) readSize(buffer);
return buffer.getInt64List(length);
}
case _valueFloat32List: {
int length = (int) readSize(buffer);
return buffer.getFloat32List(length);
}
case _valueList: {
int length = (int) readSize(buffer);
var result = new ArrayList(length);
for (int i = 0; i < length; i++)
result.Add(readValue(buffer));
return result;
}
case _valueMap: {
int length = (int) readSize(buffer);
Hashtable result = new Hashtable();
for (int i = 0; i < length; i++)
result[readValue(buffer)] = readValue(buffer);
return result;
}
default:
throw new Exception("Message corrupted");
}
}
void writeSize(WriteBuffer buffer, long value) {
D.assert(0 <= value && value <= 0x7fffffff);
if (value < 254) {
buffer.putUint8((byte) value);
}
else if (value <= 0xffff) {
buffer.putUint8(254);
buffer.putUint16((ushort) value);
}
else {
buffer.putUint8(255);
buffer.putUint32((uint) value);
}
}
long readSize(ReadBuffer buffer) {
int value = buffer.getUint8();
switch (value) {
case 254:
return buffer.getUint16();
case 255:
return buffer.getUint32();
default:
return value;
}
}
}
public class StandardMethodCodec : MethodCodec {
public StandardMethodCodec(StandardMessageCodec messageCodec = null) {
this.messageCodec = messageCodec ?? StandardMessageCodec.instance;
}
readonly StandardMessageCodec messageCodec;
public byte[] encodeMethodCall(MethodCall call) {
WriteBuffer buffer = new WriteBuffer();
messageCodec.writeValue(buffer, call.method);
messageCodec.writeValue(buffer, call.arguments);
return buffer.done();
}
public MethodCall decodeMethodCall(byte[] methodCall) {
ReadBuffer buffer = new ReadBuffer(methodCall);
object methodRaw = messageCodec.readValue(buffer);
object arguments = messageCodec.readValue(buffer);
if (methodRaw is string method && !buffer.hasRemaining)
return new MethodCall(method, arguments);
else
throw new Exception("Invalid method call");
}
public byte[] encodeSuccessEnvelope(object result) {
WriteBuffer buffer = new WriteBuffer();
buffer.putUint8(0);
messageCodec.writeValue(buffer, result);
return buffer.done();
}
public byte[] encodeErrorEnvelope(string code, string message = null, object details = null) {
WriteBuffer buffer = new WriteBuffer();
buffer.putUint8(1);
messageCodec.writeValue(buffer, code);
messageCodec.writeValue(buffer, message);
messageCodec.writeValue(buffer, details);
return buffer.done();
}
public object decodeEnvelope(byte[] envelope) {
if (envelope.Length == 0)
throw new Exception("Expected envelope, got nothing");
ReadBuffer buffer = new ReadBuffer(envelope);
if (buffer.getUint8() == 0)
return messageCodec.readValue(buffer);
object errorCodeRaw = messageCodec.readValue(buffer);
object errorMessage = messageCodec.readValue(buffer);
object errorDetails = messageCodec.readValue(buffer);
if (errorCodeRaw is string errorCode && (errorMessage == null || errorMessage is string) &&
!buffer.hasRemaining)
throw new PlatformException(code: errorCode, message: errorMessage as string, details: errorDetails);
else
throw new Exception("Invalid envelope");
}
}

3
com.unity.uiwidgets/Runtime/services/message_codecs.cs.meta


fileFormatVersion: 2
guid: eda58f2816f44397ac01597513782e10
timeCreated: 1600152975

89
engine/src/lib/ui/window/platform_message_response_dart.cc


#include "platform_message_response_dart.h"
#include <utility>
#include "common/task_runners.h"
#include "flutter/fml/make_copyable.h"
#include "lib/ui/window/window.h"
namespace uiwidgets {
namespace {
// Avoid copying the contents of messages beyond a certain size.
const int kMessageCopyThreshold = 1000;
void MessageDataFinalizer(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* peer) {
std::vector<uint8_t>* data = reinterpret_cast<std::vector<uint8_t>*>(peer);
delete data;
}
Dart_Handle WrapByteData(std::vector<uint8_t> data) {
if (data.size() < kMessageCopyThreshold) {
return ToByteData(data);
} else {
std::vector<uint8_t>* heap_data = new std::vector<uint8_t>(std::move(data));
return Dart_NewExternalTypedDataWithFinalizer(
Dart_TypedData_kByteData, heap_data->data(), heap_data->size(),
heap_data, heap_data->size(), MessageDataFinalizer);
}
}
Dart_Handle WrapByteData(std::unique_ptr<fml::Mapping> mapping) {
std::vector<uint8_t> data(mapping->GetSize());
memcpy(data.data(), mapping->GetMapping(), mapping->GetSize());
return WrapByteData(std::move(data));
}
} // anonymous namespace
PlatformMessageResponseDart::PlatformMessageResponseDart(
tonic::DartPersistentValue callback,
fml::RefPtr<fml::TaskRunner> ui_task_runner)
: callback_(std::move(callback)),
ui_task_runner_(std::move(ui_task_runner)) {}
PlatformMessageResponseDart::~PlatformMessageResponseDart() {
if (!callback_.is_empty()) {
ui_task_runner_->PostTask(fml::MakeCopyable(
[callback = std::move(callback_)]() mutable { callback.Clear(); }));
}
}
void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
if (callback_.is_empty())
return;
FML_DCHECK(!is_complete_);
is_complete_ = true;
ui_task_runner_->PostTask(fml::MakeCopyable(
[callback = std::move(callback_), data = std::move(data)]() mutable {
std::shared_ptr<tonic::DartState> dart_state =
callback.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
Dart_Handle byte_buffer = WrapByteData(std::move(data));
tonic::DartInvoke(callback.Release(), {byte_buffer});
}));
}
void PlatformMessageResponseDart::CompleteEmpty() {
if (callback_.is_empty())
return;
FML_DCHECK(!is_complete_);
is_complete_ = true;
ui_task_runner_->PostTask(
fml::MakeCopyable([callback = std::move(callback_)]() mutable {
std::shared_ptr<tonic::DartState> dart_state =
callback.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
tonic::DartInvoke(callback.Release(), {Dart_Null()});
}));
}
} // namespace flutter

26
engine/src/lib/ui/window/platform_message_response_dart.h


#pragma once
#include "flutter/fml/message_loop.h"
#include "platform_message_response.h"
namespace uiwidgets {
class PlatformMessageResponseDart : public PlatformMessageResponse {
FML_FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDart);
public:
// Callable on any thread.
void Complete(std::unique_ptr<fml::Mapping> data) override;
void CompleteEmpty() override;
protected:
explicit PlatformMessageResponseDart(
tonic::DartPersistentValue callback,
fml::RefPtr<fml::TaskRunner> ui_task_runner);
~PlatformMessageResponseDart() override;
tonic::DartPersistentValue callback_;
fml::RefPtr<fml::TaskRunner> ui_task_runner_;
};
} // namespace uiwidgets
正在加载...
取消
保存