浏览代码

Merge branch 'skia' into siyao_skia

/siyaoH-1.17-PlatformMessage
siyao 4 年前
当前提交
6715fa3d
共有 139 个文件被更改,包括 7574 次插入1243 次删除
  1. 7
      Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/app.cs
  2. 18
      com.unity.uiwidgets/Runtime/async/priority_queue.cs
  3. 2
      com.unity.uiwidgets/Runtime/debugger/inspector_service.cs
  4. 55
      com.unity.uiwidgets/Runtime/foundation/binding.cs
  5. 20
      com.unity.uiwidgets/Runtime/foundation/constants.cs
  6. 20
      com.unity.uiwidgets/Runtime/foundation/debug.cs
  7. 4
      com.unity.uiwidgets/Runtime/material/slider.cs
  8. 5
      com.unity.uiwidgets/Runtime/painting/image_stream.cs
  9. 12
      com.unity.uiwidgets/Runtime/scheduler/binding.cs
  10. 16
      com.unity.uiwidgets/Runtime/ui2/compositing.cs
  11. 21
      com.unity.uiwidgets/Runtime/ui2/hooks.cs
  12. 2
      com.unity.uiwidgets/Runtime/ui2/native_bindings.cs
  13. 43
      com.unity.uiwidgets/Runtime/ui2/painting.cs
  14. 1
      com.unity.uiwidgets/Runtime/ui2/window.cs
  15. 93
      engine/Build.bee.cs
  16. 7
      engine/src/common/settings.h
  17. 10
      engine/src/engine.cc
  18. 14
      engine/src/flow/skia_gpu_object.cc
  19. 2
      engine/src/flow/skia_gpu_object.h
  20. 2
      engine/src/lib/ui/compositing/scene.cc
  21. 35
      engine/src/lib/ui/compositing/scene_builder.cc
  22. 2
      engine/src/lib/ui/compositing/scene_builder.h
  23. 49
      engine/src/lib/ui/painting/gradient.cc
  24. 7
      engine/src/lib/ui/painting/image_decoder.cc
  25. 13
      engine/src/lib/ui/painting/image_decoder.h
  26. 18
      engine/src/lib/ui/ui_mono_state.cc
  27. 10
      engine/src/lib/ui/window/window.cc
  28. 2
      engine/src/lib/ui/window/window.h
  29. 65
      engine/src/runtime/mono_api.cc
  30. 4
      engine/src/runtime/mono_api.h
  31. 108
      engine/src/runtime/runtime_controller.cc
  32. 30
      engine/src/runtime/runtime_controller.h
  33. 2
      engine/src/runtime/runtime_delegate.h
  34. 8
      engine/src/shell/common/animator.cc
  35. 229
      engine/src/shell/common/engine.cc
  36. 15
      engine/src/shell/common/engine.h
  37. 622
      engine/src/shell/common/shell.cc
  38. 335
      engine/src/shell/common/shell.h
  39. 2
      engine/src/shell/common/vsync_waiter.h
  40. 3
      com.unity.uiwidgets/Runtime/async2.meta
  41. 3
      com.unity.uiwidgets/Runtime/developer.meta
  42. 3
      com.unity.uiwidgets/Runtime/engine2.meta
  43. 3
      com.unity.uiwidgets/Runtime/scheduler2.meta
  44. 7
      engine/src/runtime/start_up.cc
  45. 9
      engine/src/runtime/start_up.h
  46. 194
      engine/src/shell/common/canvas_spy.cc
  47. 165
      engine/src/shell/common/canvas_spy.h
  48. 64
      engine/src/shell/common/run_configuration.cc
  49. 42
      engine/src/shell/common/run_configuration.h
  50. 24
      engine/third_party/Unity/IUnityUIWidgets.h
  51. 360
      com.unity.uiwidgets/Runtime/async2/future.cs
  52. 3
      com.unity.uiwidgets/Runtime/async2/future.cs.meta
  53. 812
      com.unity.uiwidgets/Runtime/async2/future_impl.cs
  54. 3
      com.unity.uiwidgets/Runtime/async2/future_impl.cs.meta
  55. 129
      com.unity.uiwidgets/Runtime/async2/schedule_microtask.cs
  56. 3
      com.unity.uiwidgets/Runtime/async2/schedule_microtask.cs.meta
  57. 142
      com.unity.uiwidgets/Runtime/async2/timer.cs
  58. 3
      com.unity.uiwidgets/Runtime/async2/timer.cs.meta
  59. 1001
      com.unity.uiwidgets/Runtime/async2/zone.cs
  60. 3
      com.unity.uiwidgets/Runtime/async2/zone.cs.meta
  61. 8
      com.unity.uiwidgets/Runtime/developer/extension.cs
  62. 3
      com.unity.uiwidgets/Runtime/developer/extension.cs.meta
  63. 11
      com.unity.uiwidgets/Runtime/developer/timeline.cs
  64. 3
      com.unity.uiwidgets/Runtime/developer/timeline.cs.meta
  65. 3
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs.meta
  66. 155
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
  67. 674
      com.unity.uiwidgets/Runtime/scheduler2/binding.cs
  68. 3
      com.unity.uiwidgets/Runtime/scheduler2/binding.cs.meta
  69. 7
      com.unity.uiwidgets/Runtime/scheduler2/debug.cs
  70. 3
      com.unity.uiwidgets/Runtime/scheduler2/debug.cs.meta
  71. 30
      com.unity.uiwidgets/Runtime/scheduler2/priority.cs
  72. 3
      com.unity.uiwidgets/Runtime/scheduler2/priority.cs.meta
  73. 307
      com.unity.uiwidgets/Runtime/scheduler2/ticker.cs
  74. 3
      com.unity.uiwidgets/Runtime/scheduler2/ticker.cs.meta
  75. 48
      engine/src/assets/asset_manager.cc
  76. 35
      engine/src/assets/asset_manager.h
  77. 26
      engine/src/assets/asset_resolver.h
  78. 41
      engine/src/assets/directory_asset_bundle.cc
  79. 30
      engine/src/assets/directory_asset_bundle.h
  80. 14
      engine/src/shell/gpu/gpu_surface_delegate.h
  81. 328
      engine/src/shell/gpu/gpu_surface_gl.cc
  82. 68
      engine/src/shell/gpu/gpu_surface_gl.h
  83. 100
      engine/src/shell/gpu/gpu_surface_gl_delegate.cc
  84. 65
      engine/src/shell/gpu/gpu_surface_gl_delegate.h
  85. 90
      engine/src/shell/gpu/gpu_surface_software.cc
  86. 44
      engine/src/shell/gpu/gpu_surface_software.h
  87. 11
      engine/src/shell/gpu/gpu_surface_software_delegate.cc
  88. 22
      engine/src/shell/gpu/gpu_surface_software_delegate.h
  89. 1001
      engine/src/shell/platform/embedder/embedder.cc
  90. 459
      engine/src/shell/platform/embedder/embedder.h
  91. 252
      engine/src/shell/platform/embedder/embedder_engine.cc
  92. 84
      engine/src/shell/platform/embedder/embedder_engine.h

7
Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/app.cs


using Unity.UIWidgets.foundation;
using Unity.UIWidgets.material;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.scheduler2;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;

this._options = new GalleryOptions(
theme: GalleryTheme.kLightGalleryTheme,
textScaleFactor: GalleryTextScaleValue.kAllGalleryTextScaleValues[0],
timeDilation: SchedulerBinding.instance.timeDilation,
timeDilation: scheduler_.timeDilation,
platform: Application.platform,
showPerformanceOverlay: this.widget.enablePerformanceOverlay
);

this._timeDilationTimer = null;
if (newOptions.timeDilation > 1.0f) {
this._timeDilationTimer = Window.instance.run(new TimeSpan(0, 0, 0, 0, 150),
() => { SchedulerBinding.instance.timeDilation = newOptions.timeDilation; });
() => { scheduler_.timeDilation = newOptions.timeDilation; });
SchedulerBinding.instance.timeDilation = newOptions.timeDilation;
scheduler_.timeDilation = newOptions.timeDilation;
}
}

18
com.unity.uiwidgets/Runtime/async/priority_queue.cs


get { return this._data.Count; }
}
public bool isEmpty {
get { return count == 0; }
}
public bool isNotEmpty {
get { return count != 0; }
}
public T first {
get {
return peek();
}
}
public T removeFirst() {
return dequeue();
}
public override string ToString() {
string s = "";
for (int i = 0; i < this._data.Count; ++i) {

2
com.unity.uiwidgets/Runtime/debugger/inspector_service.cs


}
public bool debugEnabled {
get { return D.debugEnabled; }
get { return foundation_.kDebugMode; }
}
public void close() {

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


namespace Unity.UIWidgets.foundation {
using System;
using RSG;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.ui2;
namespace Unity.UIWidgets.foundation {
public abstract class BindingBase {
protected BindingBase() {
D.assert(!_debugInitialized);
initInstances();
D.assert(_debugInitialized);
}
static bool _debugInitialized = false;
public Window window => Window.instance;
protected virtual void initInstances() {
D.assert(!_debugInitialized);
D.assert(() => {
_debugInitialized = true;
return true;
});
}
protected bool locked => _lockCount > 0;
int _lockCount = 0;
protected Future lockEvents(Func<Future> callback) {
developer.Timeline.startSync("Lock events");
D.assert(callback != null);
_lockCount += 1;
Future future = callback();
D.assert(future != null,
() =>
"The lockEvents() callback returned null; " +
"it should return a Promise that completes when the lock is to expire.");
future.whenComplete(() => {
_lockCount -= 1;
if (!locked) {
developer.Timeline.finishSync();
unlocked();
}
return null;
});
return future;
}
protected virtual void unlocked() {
D.assert(!locked);
}
}
}

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


using UnityEngine;
namespace Unity.UIWidgets.foundation {
public class FoundationConstants {
public static bool kReleaseMode = !Debug.isDebugBuild;
public static class foundation_ {
public static readonly bool kReleaseMode = !Debug.isDebugBuild;
#if UIWidgets_PROFILE
public const bool kProfileMode = true;
#else
public const bool kProfileMode = false;
#endif
public static readonly bool kDebugMode = !kReleaseMode && !kProfileMode;
public const float precisionErrorTolerance = 1e-10f;
#if UNITY_WEBGL
public const bool kIsWeb = true;
#else
public const bool kIsWeb = false;
#endif
}
}

20
com.unity.uiwidgets/Runtime/foundation/debug.cs


Debug.LogException(new AssertionError(message, ex));
}
public static bool debugEnabled {
get {
#if UIWidgets_DEBUG
return true;
#else
return false;
#endif
}
}
[Conditional("UIWidgets_DEBUG")]
[Conditional("UNITY_ASSERTIONS")]
public static void assert(Func<bool> result, Func<string> message = null) {
if (!result()) {
throw new AssertionError(message != null ? message() : "");

[Conditional("UIWidgets_DEBUG")]
[Conditional("UNITY_ASSERTIONS")]
public static void assert(bool result, Func<string> message = null) {
if (!result) {
throw new AssertionError(message != null ? message() : "");

public static bool debugPaintBaselinesEnabled = false;
public static bool debugPrintRecognizerCallbacksTrace = false;
public static bool debugPrintBeginFrameBanner = false;
public static bool debugPrintEndFrameBanner = false;
public static bool debugPrintScheduleFrameStacks = false;
public static bool debugPaintSizeEnabled = false;

4
com.unity.uiwidgets/Runtime/material/slider.cs


using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.scheduler2;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;

this._state.interactionTimer?.cancel();
this._state.interactionTimer = Window.instance.run(
new TimeSpan(0, 0, 0, 0,
(int) (_minimumInteractionTimeMilliSeconds * SchedulerBinding.instance.timeDilation)),
(int) (_minimumInteractionTimeMilliSeconds * scheduler_.timeDilation)),
() => {
this._state.interactionTimer = null;
if (!this._active &&

5
com.unity.uiwidgets/Runtime/painting/image_stream.cs


using RSG;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.scheduler2;
using SchedulerBinding = Unity.UIWidgets.scheduler.SchedulerBinding;
namespace Unity.UIWidgets.painting {
public class ImageInfo : IEquatable<ImageInfo> {

}
TimeSpan delay = this._frameDuration.Value - (timestamp - this._shownTimestamp.Value);
delay = new TimeSpan((long) (delay.Ticks * SchedulerBinding.instance.timeDilation));
delay = new TimeSpan((long) (delay.Ticks * scheduler_.timeDilation));
this._timer = Window.instance.run(delay, this._scheduleAppFrame);
}

12
com.unity.uiwidgets/Runtime/scheduler/binding.cs


using System.Text;
using RSG.Promises;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.scheduler2;
using FrameCallback = Unity.UIWidgets.ui.FrameCallback;
namespace Unity.UIWidgets.scheduler {
class _FrameCallbackEntry {

}
D.assert(() => {
if (D.debugPrintScheduleFrameStacks) {
if (scheduler_.debugPrintScheduleFrameStacks) {
Debug.LogFormat("scheduleFrame() called. Current phase is {0}.", this.schedulerPhase);
}

}
D.assert(() => {
if (D.debugPrintScheduleFrameStacks) {
if (scheduler_.debugPrintScheduleFrameStacks) {
Debug.LogFormat("scheduleForcedFrame() called. Current phase is {0}.", this.schedulerPhase);
}

});
D.assert(() => {
if (D.debugPrintBeginFrameBanner || D.debugPrintEndFrameBanner) {
if (scheduler_.debugPrintBeginFrameBanner || scheduler_.debugPrintEndFrameBanner) {
var frameTimeStampDescription = new StringBuilder();
if (rawTimeStamp != null) {
_debugDescribeTimeStamp(

this._debugBanner =
$"▄▄▄▄▄▄▄▄ Frame {this._profileFrameNumber.ToString().PadRight(7)} {frameTimeStampDescription.ToString().PadLeft(18)} ▄▄▄▄▄▄▄▄";
if (D.debugPrintBeginFrameBanner) {
if (scheduler_.debugPrintBeginFrameBanner) {
Debug.Log(this._debugBanner);
}
}

} finally {
this._schedulerPhase = SchedulerPhase.idle;
D.assert(() => {
if (D.debugPrintEndFrameBanner) {
if (scheduler_.debugPrintEndFrameBanner) {
Debug.Log(new string('▀', this._debugBanner.Length));
}

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


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

D.assert(() => {
if (_layerStack.isNotEmpty()) {
_EngineLayerWrapper currentLayer = _layerStack.last();
currentLayer._debugChildren ??= new List<_EngineLayerWrapper>();
currentLayer._debugChildren = currentLayer._debugChildren ?? new List<_EngineLayerWrapper>();
currentLayer._debugChildren.Add(newLayer);
}

_EngineLayerWrapper wrapper = retainedLayer as _EngineLayerWrapper;
SceneBuilder_addRetained(_ptr, wrapper._ptr);
}
public void addPicture(
Offset offset,
Picture picture,
bool isComplexHint = false,
bool willChangeHint = false
) {
int hints = (isComplexHint ? 1 : 0) | (willChangeHint ? 2 : 0);
SceneBuilder_addPicture(_ptr, offset.dx, offset.dy, picture._ptr, hints);
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_constructor();

[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);
[DllImport(NativeBindings.dllName)]
static extern void SceneBuilder_addRetained(IntPtr ptr, IntPtr retainedLayer);
}

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


namespace Unity.UIWidgets.ui2 {
public static class Hooks {
public static void hook() {
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#else
[RuntimeInitializeOnLoadMethod]
#endif
static void hook() {
Mono_throwException,
Mono_timelineGetMicros);
Mono_throwException);
Window_hook(
Window_constructor,

throw new Exception(Marshal.PtrToStringAnsi(exception));
}
delegate long Mono_TimelineGetMicrosCallback();
[MonoPInvokeCallback(typeof(Mono_TimelineGetMicrosCallback))]
static long Mono_timelineGetMicros() {
return Environment.TickCount * 1000L;
}
static extern void Mono_hook(Mono_ThrowExceptionCallback throwException,
Mono_TimelineGetMicrosCallback timelineGetMicros);
static extern void Mono_hook(Mono_ThrowExceptionCallback throwException);
delegate IntPtr Window_constructorCallback(IntPtr ptr);

2
com.unity.uiwidgets/Runtime/ui2/native_bindings.cs


}
protected NativeWrapperDisposable(IntPtr ptr) {
D.assert(_ptr != IntPtr.Zero);
D.assert(ptr != IntPtr.Zero);
_ptr = ptr;
}

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


}
}
else {
_objects ??= new object[_kObjectCount];
_objectPtrs ??= new IntPtr[_kObjectCount];
_objects = _objects ?? new object[_kObjectCount];
_objectPtrs = _objectPtrs ?? new IntPtr[_kObjectCount];
_objects[_kShaderIndex] = value;
_objectPtrs[_kShaderIndex] = value._ptr;

}
}
else {
_objects ??= new object[_kObjectCount];
_objectPtrs ??= new IntPtr[_kObjectCount];
_objects = _objects ?? new object[_kObjectCount];
_objectPtrs = _objectPtrs ?? new IntPtr[_kObjectCount];
if (((_ColorFilter) _objects[_kColorFilterIndex])?.creator != value) {
_objects[_kColorFilterIndex] = nativeFilter;

}
}
else {
_objects ??= new object[_kObjectCount];
_objectPtrs ??= new IntPtr[_kObjectCount];
_objects = _objects ?? new object[_kObjectCount];
_objectPtrs = _objectPtrs ?? new IntPtr[_kObjectCount];
if (((_ImageFilter) _objects[_kImageFilterIndex])?.creator != value) {
_objects[_kImageFilterIndex] = nativeFilter;

float rotation = 0.0f,
bool largeArc = false,
bool clockwise = true) {
radius ??= Radius.zero;
radius = radius ?? Radius.zero;
D.assert(PaintingUtils._offsetIsValid(arcEnd));
D.assert(PaintingUtils._radiusIsValid(radius));

float rotation = 0.0f,
bool largeArc = false,
bool clockwise = true) {
radius ??= Radius.zero;
radius = radius ?? Radius.zero;
D.assert(PaintingUtils._offsetIsValid(arcEndDelta));
D.assert(PaintingUtils._radiusIsValid(radius));

internal const int _kTypeBlur = 0;
internal const int _kTypeMatrix = 1;
internal _ImageFilter _toNativeImageFilter() => _nativeFilter ??= _makeNativeImageFilter();
internal _ImageFilter _toNativeImageFilter() => _nativeFilter = _nativeFilter ?? _makeNativeImageFilter();
_ImageFilter _makeNativeImageFilter() {
if (_data == null) {

var colorsArray = PaintingUtils._encodeColorList(colors);
var colorStopsArray = colorStops?.ToArray() ?? new float[] { };
fixed (float* endPointsBuffer = &endPointsArray[0])
fixed (uint* colorsBuffer = &colorsArray[0])
fixed (float* colorStopsBuffer = &colorStopsArray[0])
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (float* endPointsBuffer = endPointsArray)
fixed (uint* colorsBuffer = colorsArray)
fixed (float* colorStopsBuffer = colorStopsArray)
fixed (float* matrix4Buffer = matrix4) {
var gradient = new Gradient(Gradient_constructor());
Gradient_initLinear(
gradient._ptr, endPointsBuffer, endPointsArray.Length,

var colorsArray = PaintingUtils._encodeColorList(colors);
var colorStopsArray = colorStops?.ToArray() ?? new float[] { };
fixed (uint* colorsBuffer = &colorsArray[0])
fixed (float* colorStopsBuffer = &colorStopsArray[0])
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (uint* colorsBuffer = colorsArray)
fixed (float* colorStopsBuffer = colorStopsArray)
fixed (float* matrix4Buffer = matrix4) {
var gradient = new Gradient(Gradient_constructor());
if (focal == null || (focal == center && focalRadius == 0.0f)) {

var colorsArray = PaintingUtils._encodeColorList(colors);
var colorStopsArray = colorStops?.ToArray() ?? new float[] { };
fixed (uint* colorsBuffer = &colorsArray[0])
fixed (float* colorStopsBuffer = &colorStopsArray[0])
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (uint* colorsBuffer = colorsArray)
fixed (float* colorStopsBuffer = colorStopsArray)
fixed (float* matrix4Buffer = matrix4) {
var gradient = new Gradient(Gradient_constructor());
Gradient_initSweep(gradient._ptr,
center.dx, center.dy,

throw new ArgumentException("\"matrix4\" must have 16 entries.");
}
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (float* matrix4Buffer = matrix4) {
ImageShader_initWithImage(_ptr, image._ptr, (int) tmx, (int) tmy, matrix4Buffer);
}
}

throw new ArgumentException("\"recorder\" must not already be associated with another Canvas.");
}
cullRect ??= Rect.largest;
cullRect = cullRect ?? Rect.largest;
_ptr = Canvas_constructor(recorder._ptr, cullRect.left, cullRect.top,
cullRect.right,
cullRect.bottom);

public void drawColor(Color color, BlendMode blendMode) {
D.assert(color != null);
D.assert(blendMode != null);
Canvas_drawColor(_ptr, color.value, (int) blendMode);
}

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


public class Window {
internal IntPtr _ptr;
internal object _binding;
internal Window() {
_setNeedsReportTimings = Window_setNeedsReportTimings;

93
engine/Build.bee.cs


{
Sources =
{
"src/assets/asset_manager.cc",
"src/assets/asset_manager.h",
"src/assets/asset_resolver.h",
"src/assets/directory_asset_bundle.cc",
"src/assets/directory_asset_bundle.h",
"src/common/settings.cc",
"src/common/settings.h",
"src/common/task_runners.cc",

"src/runtime/mono_microtask_queue.h",
"src/runtime/mono_state.cc",
"src/runtime/mono_state.h",
//"src/runtime/runtime_controller.cc",
//"src/runtime/runtime_controller.h",
"src/runtime/runtime_controller.cc",
"src/runtime/runtime_controller.h",
"src/runtime/start_up.cc",
"src/runtime/start_up.h",
//"src/shell/common/engine.cc",
//"src/shell/common/engine.h",
"src/shell/common/canvas_spy.cc",
"src/shell/common/canvas_spy.h",
"src/shell/common/engine.cc",
"src/shell/common/engine.h",
"src/shell/common/persistent_cache.cc",
"src/shell/common/persistent_cache.h",
"src/shell/common/pipeline.cc",

"src/shell/common/pointer_data_dispatcher.h",
"src/shell/common/rasterizer.cc",
"src/shell/common/rasterizer.h",
//"src/shell/common/shell.cc",
//"src/shell/common/shell.h",
"src/shell/common/run_configuration.cc",
"src/shell/common/run_configuration.h",
"src/shell/common/shell.cc",
"src/shell/common/shell.h",
"src/shell/common/shell_io_manager.cc",
"src/shell/common/shell_io_manager.h",
"src/shell/common/surface.cc",

"src/shell/common/vsync_waiter_fallback.cc",
"src/shell/common/vsync_waiter_fallback.h",
"src/shell/gpu/gpu_surface_delegate.h",
"src/shell/gpu/gpu_surface_gl.cc",
"src/shell/gpu/gpu_surface_gl.h",
"src/shell/gpu/gpu_surface_gl_delegate.cc",
"src/shell/gpu/gpu_surface_gl_delegate.h",
"src/shell/gpu/gpu_surface_software.cc",
"src/shell/gpu/gpu_surface_software.h",
"src/shell/gpu/gpu_surface_software_delegate.cc",
"src/shell/gpu/gpu_surface_software_delegate.h",
"src/shell/platform/embedder/embedder.cc",
"src/shell/platform/embedder/embedder.h",
"src/shell/platform/embedder/embedder_engine.cc",
"src/shell/platform/embedder/embedder_engine.h",
"src/shell/platform/embedder/embedder_external_texture_gl.cc",
"src/shell/platform/embedder/embedder_external_texture_gl.h",
"src/shell/platform/embedder/embedder_external_view.cc",
"src/shell/platform/embedder/embedder_external_view.h",
"src/shell/platform/embedder/embedder_external_view_embedder.cc",
"src/shell/platform/embedder/embedder_external_view_embedder.h",
"src/shell/platform/embedder/embedder_layers.cc",
"src/shell/platform/embedder/embedder_layers.h",
"src/shell/platform/embedder/embedder_platform_message_response.cc",
"src/shell/platform/embedder/embedder_platform_message_response.h",
"src/shell/platform/embedder/embedder_render_target.cc",
"src/shell/platform/embedder/embedder_render_target.h",
"src/shell/platform/embedder/embedder_render_target_cache.cc",
"src/shell/platform/embedder/embedder_render_target_cache.h",
"src/shell/platform/embedder/embedder_surface.cc",
"src/shell/platform/embedder/embedder_surface.h",
"src/shell/platform/embedder/embedder_surface_gl.cc",
"src/shell/platform/embedder/embedder_surface_gl.h",
"src/shell/platform/embedder/embedder_surface_software.cc",
"src/shell/platform/embedder/embedder_surface_software.h",
"src/shell/platform/embedder/embedder_task_runner.cc",
"src/shell/platform/embedder/embedder_task_runner.h",
"src/shell/platform/embedder/embedder_thread_host.cc",
"src/shell/platform/embedder/embedder_thread_host.h",
"src/shell/platform/embedder/platform_view_embedder.cc",
"src/shell/platform/embedder/platform_view_embedder.h",
"src/shell/platform/embedder/vsync_waiter_embedder.cc",
"src/shell/platform/embedder/vsync_waiter_embedder.h",
"src/shell/platform/unity/gfx_worker_task_runner.cc",
"src/shell/platform/unity/gfx_worker_task_runner.h",
"src/shell/platform/unity/unity_surface_manager.cc",
"src/shell/platform/unity/unity_surface_manager.h",
"src/shell/platform/unity/uiwidgets_panel.cc",
"src/shell/platform/unity/uiwidgets_panel.h",
"src/shell/platform/unity/uiwidgets_system.cc",
"src/shell/platform/unity/uiwidgets_system.h",
"src/shell/platform/unity/win32_task_runner.cc",
"src/shell/platform/unity/win32_task_runner.h",
"src/shell/version/version.cc",
"src/shell/version/version.h",

np.LinkerSettings().Add(l => l.WithCustomFlags_workaround(new[] {"/DEBUG:FULL"}));
SetupFml(np);
SetupRadidJson(np);
SetupSkia(np);
SetupTxt(np);

}
static void SetupRadidJson(NativeProgram np)
{
// gn desc .\out\host_debug_unopt\ //third_party/rapidjson:rapidjson
np.Defines.Add(new[]
{
"RAPIDJSON_HAS_STDSTRING",
"RAPIDJSON_HAS_CXX11_RANGE_FOR",
"RAPIDJSON_HAS_CXX11_RVALUE_REFS",
"RAPIDJSON_HAS_CXX11_TYPETRAITS",
"RAPIDJSON_HAS_CXX11_NOEXCEPT"
});
np.IncludeDirectories.Add(flutterRoot + "/third_party/rapidjson/include");
}
// static void SetupSkiaAndroid(NativeProgram np)
// {

7
engine/src/common/settings.h


using TaskObserverAdd =
std::function<void(intptr_t /* key */, fml::closure /* callback */)>;
using TaskObserverRemove = std::function<void(intptr_t /* key */)>;
using UnhandledExceptionCallback =
std::function<bool(const std::string& /* error */,
const std::string& /* stack trace */)>;
using UnhandledExceptionCallback = std::function<bool(
const std::string& /* error */, const std::string& /* stack trace */)>;
// TODO(chinmaygarde): Deprecate all the "path" struct members in favor of the
// callback that generates the mapping from these paths.

// Engine settings
TaskObserverAdd task_observer_add;
TaskObserverRemove task_observer_remove;
fml::closure mono_entrypoint_callback;
// The main isolate is current when this callback is made. This is a good spot
// to perform native Dart bindings for libraries not built in.
fml::closure root_isolate_create_callback;

10
engine/src/engine.cc


#include <assert.h>
#include "Unity/IUnityGraphics.h"
#include "Unity/IUnityUIWidgets.h"
#include "shell/platform/unity/uiwidgets_system.h"
static IUnityInterfaces* s_UnityInterfaces = NULL;
static IUnityGraphics* s_Graphics = NULL;

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginLoad(IUnityInterfaces* unityInterfaces) {
s_UnityInterfaces = unityInterfaces;
s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
uiwidgets::UIWidgetsSystem::GetInstancePtr()->BindUnityInterfaces(unityInterfaces);
s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
uiwidgets::UIWidgetsSystem::GetInstancePtr()->UnBindUnityInterfaces();
}
// --------------------------------------------------------------------------

14
engine/src/flow/skia_gpu_object.cc


drain_pending_(false),
context_(context) {}
SkiaUnrefQueue::~SkiaUnrefQueue() { FML_DCHECK(objects_.empty()); }
SkiaUnrefQueue::~SkiaUnrefQueue() {
if (!objects_.empty()) {
Drain(false);
}
}
void SkiaUnrefQueue::Unref(SkRefCnt* object) {
std::scoped_lock lock(mutex_);

}
}
void SkiaUnrefQueue::Drain() {
void SkiaUnrefQueue::Drain(bool performDeferredCleanup) {
TRACE_EVENT0("uiwidgets", "SkiaUnrefQueue::Drain");
std::deque<SkRefCnt*> skia_objects;
{

skia_object->unref();
}
if (context_ && skia_objects.size() > 0) {
context_->performDeferredCleanup(std::chrono::milliseconds(0));
if (performDeferredCleanup) {
if (context_ && skia_objects.size() > 0) {
context_->performDeferredCleanup(std::chrono::milliseconds(0));
}
}
}

2
engine/src/flow/skia_gpu_object.h


// to go away), we may need to pre-emptively drain the unref queue. It is the
// responsibility of the caller to ensure that no further unrefs are queued
// after this call.
void Drain();
void Drain(bool performDeferredCleanup = true);
private:
const fml::RefPtr<fml::TaskRunner> task_runner_;

2
engine/src/lib/ui/compositing/scene.cc


return std::move(layer_tree_);
}
UIWIDGETS_API(void) Scene_dispose(Scene* ptr) { ptr->Release(); }
} // namespace uiwidgets

35
engine/src/lib/ui/compositing/scene_builder.cc


SceneBuilder::~SceneBuilder() = default;
fml::RefPtr<EngineLayer> SceneBuilder::pushTransform(float* matrix4) {
fml::RefPtr<EngineLayer> SceneBuilder::pushTransform(const float* matrix4) {
SkMatrix sk_matrix = ToSkMatrix(matrix4);
auto layer = std::make_shared<TransformLayer>(sk_matrix);
PushLayer(layer);

if (layer_stack_.size() > 1) {
layer_stack_.pop_back();
}
}
UIWIDGETS_API(SceneBuilder*) SceneBuilder_constructor() {
const auto builder = fml::MakeRefCounted<SceneBuilder>();
builder->AddRef();
return builder.get();
}
UIWIDGETS_API(void) SceneBuilder_dispose(SceneBuilder* ptr) { ptr->Release(); }
UIWIDGETS_API(void)
SceneBuilder_pushTransform(SceneBuilder* ptr, const float* matrix4) {
ptr->pushTransform(matrix4);
}
UIWIDGETS_API(void)
SceneBuilder_pushOffset(SceneBuilder* ptr, float dx, float dy) {
ptr->pushOffset(dx, dy);
}
UIWIDGETS_API(void)
SceneBuilder_pop(SceneBuilder* ptr) { ptr->pop(); }
UIWIDGETS_API(Scene*) SceneBuilder_build(SceneBuilder* ptr) {
const auto scene = ptr->build();
scene->AddRef();
return scene.get();
}
UIWIDGETS_API(void)
SceneBuilder_addPicture(SceneBuilder* ptr, float dx, float dy, Picture* picture,
int hints) {
ptr->addPicture(dx, dy, picture, hints);
}
} // namespace uiwidgets

2
engine/src/lib/ui/compositing/scene_builder.h


}
~SceneBuilder();
fml::RefPtr<EngineLayer> pushTransform(float* matrix4);
fml::RefPtr<EngineLayer> pushTransform(const float* matrix4);
fml::RefPtr<EngineLayer> pushOffset(float dx, float dy);
fml::RefPtr<EngineLayer> pushClipRect(float left, float right, float top,

49
engine/src/lib/ui/painting/gradient.cc


CanvasGradient::~CanvasGradient() = default;
UIWIDGETS_API(CanvasGradient*)
Gradient_constructor() {
const auto gradiant = CanvasGradient::Create();
gradiant->AddRef();
return gradiant.get();
}
UIWIDGETS_API(void) Gradient_dispose(CanvasGradient* ptr) { ptr->Release(); }
UIWIDGETS_API(void)
Gradient_initLinear(CanvasGradient* ptr, const float* end_points,
int end_points_length, const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, const float* matrix4) {
ptr->initLinear(end_points, end_points_length, colors, colors_length,
color_stops, color_stops_length, tile_mode, matrix4);
}
UIWIDGETS_API(void)
Gradient_initRadial(CanvasGradient* ptr, float center_x, float center_y,
float radius, const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, const float* matrix4) {
ptr->initRadial(center_x, center_y, radius, colors, colors_length,
color_stops, color_stops_length, tile_mode, matrix4);
}
UIWIDGETS_API(void)
Gradient_initConical(CanvasGradient* ptr, float start_x, float start_y,
float start_radius, float end_x, float end_y,
float end_radius, const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, const float* matrix4) {
ptr->initTwoPointConical(start_x, start_y, start_radius, end_x, end_y,
end_radius, colors, colors_length, color_stops,
color_stops_length, tile_mode, matrix4);
}
UIWIDGETS_API(void)
Gradient_initSweep(CanvasGradient* ptr, float center_x, float center_y,
const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, float start_angle, float end_angle,
const float* matrix4) {
ptr->initSweep(center_x, center_y, colors, colors_length, color_stops,
color_stops_length, tile_mode, start_angle, end_angle,
matrix4);
}
} // namespace uiwidgets

7
engine/src/lib/ui/painting/image_decoder.cc


#include "src/codec/SkCodecImageGenerator.h"
namespace uiwidgets {
ImageDecoder::ImageDecoder(
TaskRunners runners,
std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
fml::WeakPtr<IOManager> io_manager) {}
fml::WeakPtr<ImageDecoder> ImageDecoder::GetWeakPtr() const {
return fml::WeakPtr<ImageDecoder>();
}
} // namespace uiwidgets

13
engine/src/lib/ui/painting/image_decoder.h


#pragma once
#include <flutter/fml/concurrent_message_loop.h>
#include <flutter/fml/memory/weak_ptr.h>
#include "common/task_runners.h"
#include "lib/ui/io_manager.h"
public:
ImageDecoder(
TaskRunners runners,
std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
fml::WeakPtr<IOManager> io_manager);
fml::WeakPtr<ImageDecoder> GetWeakPtr() const;
};
} // namespace uiwidgets

18
engine/src/lib/ui/ui_mono_state.cc


return image_decoder_;
}
UIWIDGETS_API(void)
UIMonoState_scheduleMicrotask(MonoMicrotaskQueue::CallbackFunc callback,
Mono_Handle handle) {
UIMonoState::Current()->ScheduleMicrotask(callback, handle);
}
UIWIDGETS_API(void)
UIMonoState_postTaskForTime(MonoMicrotaskQueue::CallbackFunc callback,
Mono_Handle handle, int64_t target_time_nanos) {
UIMonoState::Current()->GetTaskRunners().GetUITaskRunner()->PostTaskForTime(
[callback, handle]() -> void { callback(handle); },
fml::TimePoint::FromEpochDelta(
fml::TimeDelta::FromNanoseconds(target_time_nanos)));
}
UIWIDGETS_API(int)
UIMonoState_timerMillisecondClock() { return Mono_TimelineGetMicros() / 1000; }
} // namespace uiwidgets

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


typedef Mono_Handle (*Window_constructorCallback)(Window* window);
static Window_constructorCallback Window_constructor_;
Window_constructorCallback Window_constructor_;
static Window_disposeCallback Window_dispose_;
Window_disposeCallback Window_dispose_;
typedef void (*Window_updateWindowMetricsCallback)(
float devicePixelRatio, float width, float height, float depth,

float systemGestureInsetRight, float systemGestureInsetBottom,
float systemGestureInsetLeft);
static Window_updateWindowMetricsCallback Window_updateWindowMetrics_;
Window_updateWindowMetricsCallback Window_updateWindowMetrics_;
static Window_beginFrameCallback Window_beginFrame_;
Window_beginFrameCallback Window_beginFrame_;
static Window_drawFrameCallback Window_drawFrame_;
Window_drawFrameCallback Window_drawFrame_;
UIWIDGETS_API(void)
Window_hook(Window_constructorCallback Window_constructor,

2
engine/src/lib/ui/window/window.h


virtual void ScheduleFrame() = 0;
virtual void Render(Scene* scene) = 0;
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
virtual FontCollection& GetFontCollection() = 0;
// virtual FontCollection& GetFontCollection() = 0;
virtual void SetNeedsReportTimings(bool value) = 0;
protected:

65
engine/src/runtime/mono_api.cc


#include <flutter/fml/logging.h>
#include <flutter/fml/thread_local.h>
#include "mono_isolate.h"
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<_Mono_Isolate> tls_isolate;
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<Mono_Isolate> tls_isolate;
return new _Mono_Isolate{isolate_data};
return new _Mono_Isolate(isolate_data);
delete static_cast<MonoState*>(data_);
delete static_cast<std::shared_ptr<MonoIsolate>*>(data_);
Mono_Isolate Mono_CurrentIsolate() { return tls_isolate.get(); }
Mono_Isolate Mono_CurrentIsolate() {
Mono_Isolate* ptr = tls_isolate.get();
if (!ptr) {
return nullptr;
}
return *ptr;
}
FML_DCHECK(tls_isolate.get() == nullptr);
tls_isolate.reset(isolate);
Mono_Isolate* ptr = tls_isolate.get();
FML_DCHECK(ptr == nullptr || *ptr == nullptr);
if (!ptr) {
ptr = new Mono_Isolate();
tls_isolate.reset(ptr);
}
*ptr = isolate;
FML_DCHECK(tls_isolate.get() != nullptr);
tls_isolate.reset(nullptr);
Mono_Isolate* ptr = tls_isolate.get();
FML_DCHECK(ptr != nullptr && *ptr != nullptr);
*ptr = nullptr;
Mono_Isolate current = tls_isolate.get();
Mono_Isolate* ptr = tls_isolate.get();
FML_DCHECK(ptr != nullptr);
const Mono_Isolate current = *ptr;
tls_isolate.reset(nullptr);
*ptr = nullptr;
delete current;
}

Mono_ThrowExceptionCallback_(exception);
}
typedef int64_t (*Mono_TimelineGetMicrosCallback)();
static Mono_TimelineGetMicrosCallback Mono_TimelineGetMicrosCallback_;
int64_t Mono_TimelineGetMicros() {
return fml::TimePoint::Now().ToEpochDelta().ToMicroseconds();
}
int64_t Mono_TimelineGetMicros() { return Mono_TimelineGetMicrosCallback_(); }
void Mono_NotifyIdle(int64_t deadline) {}
Mono_hook(Mono_ThrowExceptionCallback throwException,
Mono_TimelineGetMicrosCallback timelineGetMicros) {
Mono_hook(Mono_ThrowExceptionCallback throwException) {
Mono_TimelineGetMicrosCallback_ = timelineGetMicros;
} // namespace uiwidgets
UIWIDGETS_API(Mono_Isolate)
Isolate_current() { return Mono_CurrentIsolate(); }
// TODO: This is temp solution
// extern "C" int64_t Dart_TimelineGetMicros() { return uiwidgets::Mono_TimelineGetMicros(); }
UIWIDGETS_API(void)
Isolate_enter(Mono_Isolate isolate) { return Mono_EnterIsolate(isolate); }
extern "C" int64_t Dart_TimelineGetMicros() { return 0; }
UIWIDGETS_API(void)
Isolate_exit() { Mono_ExitIsolate(); }
} // namespace uiwidgets
extern "C" int64_t Dart_TimelineGetMicros() {
return uiwidgets::Mono_TimelineGetMicros();
}

4
engine/src/runtime/mono_api.h


#define UIWIDGETS_API(RETURN) \
extern "C" UNITY_INTERFACE_EXPORT RETURN UNITY_INTERFACE_API
#define UIWIDGETS_CALLBACK(RETURN) static RETURN UNITY_INTERFACE_API
namespace uiwidgets {
typedef void* Mono_Handle;

void Mono_ThrowException(const char* exception);
int64_t Mono_TimelineGetMicros();
void Mono_NotifyIdle(int64_t deadline);
} // namespace uiwidgets

108
engine/src/runtime/runtime_controller.cc


#include "runtime_controller.h"
#include <utility>
#include "flutter/fml/message_loop.h"
#include "flutter/fml/trace_event.h"
#include "lib/ui/compositing/scene.h"

namespace uiwidgets {
RuntimeController::RuntimeController(
RuntimeDelegate& p_client, Settings& p_settings,
TaskRunners p_task_runners,
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
fml::WeakPtr<IOManager> p_io_manager,
fml::RefPtr<SkiaUnrefQueue> p_unref_queue,
fml::WeakPtr<ImageDecoder> p_image_decoder,
const std::function<void(int64_t)>& idle_notification_callback,
const WindowData& p_window_data,
const fml::closure& p_isolate_create_callback,
const fml::closure& p_isolate_shutdown_callback)
: client_(p_client),
settings_(p_settings),
task_runners_(p_task_runners),
snapshot_delegate_(p_snapshot_delegate),
io_manager_(p_io_manager),
unref_queue_(p_unref_queue),
image_decoder_(p_image_decoder),
idle_notification_callback_(idle_notification_callback),
window_data_(std::move(p_window_data)),
isolate_create_callback_(p_isolate_create_callback),
isolate_shutdown_callback_(p_isolate_shutdown_callback) {
auto strong_root_isolate =
MonoIsolate::CreateRootIsolate(settings_, //
task_runners_, //
std::make_unique<Window>(this), //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
RuntimeDelegate& client, const Settings& settings, TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager, fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder, const WindowData& window_data)
: client_(client),
settings_(settings),
task_runners_(task_runners),
snapshot_delegate_(std::move(snapshot_delegate)),
io_manager_(std::move(io_manager)),
unref_queue_(std::move(unref_queue)),
image_decoder_(std::move(image_decoder)),
window_data_(window_data) {
auto strong_root_isolate =
MonoIsolate::CreateRootIsolate(settings_, //
task_runners_, //
std::make_unique<Window>(this), //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
image_decoder_ //
)
.lock();

}
}
bool RuntimeController::IsRootIsolateRunning() const {
//std::shared_ptr<MonoIsolate> root_isolate = root_isolate_.lock();
//if (root_isolate) {
// return root_isolate->GetPhase() == DartIsolate::Phase::Running;
//}
//return false;
return true;
}
return std::unique_ptr<RuntimeController>(new RuntimeController(
client_, //
settings_, //
task_runners_, //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
image_decoder_, //
idle_notification_callback_, //
window_data_, //
isolate_create_callback_, //
isolate_shutdown_callback_ //
));
return std::make_unique<RuntimeController>(client_, //
settings_, //
task_runners_, //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
image_decoder_, //
window_data_ //
);
}
bool RuntimeController::FlushRuntimeStateToIsolate() {

}
MonoState::Scope scope(root_isolate);
// Idle notifications being in isolate scope are part of the contract.
if (idle_notification_callback_) {
TRACE_EVENT0("flutter", "EmbedderIdleNotification");
idle_notification_callback_(deadline);
}
return true;
}

TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
TRACE_EVENT1("uiwidgets", "RuntimeController::DispatchPlatformMessage",
"mode", "basic");
window->DispatchPlatformMessage(std::move(message));
return true;

bool RuntimeController::DispatchPointerDataPacket(
const PointerDataPacket& packet) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket",
TRACE_EVENT1("uiwidgets", "RuntimeController::DispatchPointerDataPacket",
"mode", "basic");
window->DispatchPointerDataPacket(packet);
return true;

Window* RuntimeController::GetWindowIfAvailable() {
std::shared_ptr<MonoIsolate> root_isolate = root_isolate_.lock();

}
// |WindowClient|
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
void RuntimeController::ScheduleFrame() { client_.ScheduleFrame(); }
// |WindowClient|
void RuntimeController::Render(Scene* scene) {

}
// |WindowClient|
FontCollection& RuntimeController::GetFontCollection() {
// return client_.GetFontCollection();
//return nullptr;
}
// FontCollection& RuntimeController::GetFontCollection() {
// return client_.GetFontCollection();
//}
// |WindowClient|
void RuntimeController::SetNeedsReportTimings(bool value) {

std::weak_ptr<MonoIsolate> RuntimeController::GetRootIsolate() {
return root_isolate_;
}
RuntimeController::Locale::Locale(std::string language_code_,
std::string country_code_,

RuntimeController::Locale::~Locale() = default;
} // namespace flutter
} // namespace uiwidgets

30
engine/src/runtime/runtime_controller.h


class RuntimeController final : public WindowClient {
public:
RuntimeController(
RuntimeDelegate& client,
Settings& settings,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
const std::function<void(int64_t)>& idle_notification_callback,
const WindowData& window_data,
const fml::closure& isolate_create_callback,
const fml::closure& isolate_shutdown_callback);
RuntimeController(RuntimeDelegate& client, const Settings& settings,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
const WindowData& window_data);
~RuntimeController() override;

bool NotifyIdle(int64_t deadline);
bool IsRootIsolateRunning() const;
bool DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
bool DispatchPointerDataPacket(const PointerDataPacket& packet);

};
RuntimeDelegate& client_;
Settings& settings_;
const Settings& settings_;
std::function<void(int64_t)> idle_notification_callback_;
std::pair<bool, uint32_t> root_isolate_return_code_ = {false, 0};
const fml::closure isolate_create_callback_;
const fml::closure isolate_shutdown_callback_;
std::shared_ptr<const fml::Mapping> persistent_isolate_data_;
Window* GetWindowIfAvailable();

void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
// |WindowClient|
FontCollection& GetFontCollection() override;
// FontCollection& GetFontCollection() override;
// |WindowClient|
void SetNeedsReportTimings(bool value) override;

2
engine/src/runtime/runtime_delegate.h


virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
// virtual FontCollection& GetFontCollection() = 0;
//virtual FontCollection& GetFontCollection() = 0;
virtual void SetNeedsReportTimings(bool value) = 0;

8
engine/src/shell/common/animator.cc


return (frame_number_ % 2) ? "even" : "odd";
}
static int64_t FxlToMonoOrEarlier(fml::TimePoint time) {
static int64_t FmlToMonoOrEarlier(fml::TimePoint time) {
fml::TimePoint fxl_now = fml::TimePoint::Now();
return (time - fxl_now).ToMicroseconds() + mono_now;
fml::TimePoint fml_now = fml::TimePoint::Now();
return (time - fml_now).ToMicroseconds() + mono_now;
}
void Animator::BeginFrame(fml::TimePoint frame_start_time,

last_frame_begin_time_ = frame_start_time;
last_frame_target_time_ = frame_target_time;
mono_frame_deadline_ = FxlToMonoOrEarlier(frame_target_time);
mono_frame_deadline_ = FmlToMonoOrEarlier(frame_target_time);
{
TRACE_EVENT2("uiwidgets", "Framework Workload", "mode", "basic", "frame",
FrameParity());

229
engine/src/shell/common/engine.cc


#include "flutter/fml/paths.h"
#include "flutter/fml/trace_event.h"
#include "flutter/fml/unique_fd.h"
//#include "lib/snapshot/snapshot.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPictureRecorder.h"
#include "rapidjson/document.h"
#include "rapidjson/document.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPictureRecorder.h"
namespace uiwidgets {

static constexpr char kLocalizationChannel[] = "uiwidgets/localization";
static constexpr char kSettingsChannel[] = "uiwidgets/settings";
static constexpr char kIsolateChannel[] = "uiwidgets/isolate";
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
std::unique_ptr<Animator> animator,
TaskRunners task_runners, const WindowData window_data,
Settings settings, std::unique_ptr<Animator> animator,
concurrent_message_loop_(fml::ConcurrentMessageLoop::Create()),
image_decoder_(task_runners,
vm.GetConcurrentWorkerTaskRunner(),
image_decoder_(task_runners, concurrent_message_loop_->GetTaskRunner(),
io_manager),
task_runners_(std::move(task_runners)),
weak_factory_(this) {

runtime_controller_ = std::make_unique<RuntimeController>(
*this, // runtime delegate
&vm, // VM
std::move(isolate_snapshot), // isolate snapshot
task_runners_, // task runners
*this, // runtime delegate
settings_, // settings
task_runners_, // task runners
std::move(io_manager), // io manager
std::move(unref_queue), // Skia unref queue
image_decoder_.GetWeakPtr(), // image decoder
settings_.advisory_script_uri, // advisory script uri
settings_.advisory_script_entrypoint, // advisory script entrypoint
settings_.idle_notification_callback, // idle notification callback
window_data, // window data
settings_.isolate_create_callback, // isolate create callback
settings_.isolate_shutdown_callback, // isolate shutdown callback
settings_.persistent_isolate_data // persistent isolate data
std::move(io_manager), // io manager
std::move(unref_queue), // Skia unref queue
image_decoder_.GetWeakPtr(), // image decoder
window_data // window data
);
pointer_data_dispatcher_ = dispatcher_maker(*this);

return false;
}
// Using libTXT as the text engine.
font_collection_.RegisterFonts(asset_manager_);
if (settings_.use_test_fonts) {
font_collection_.RegisterTestFonts();
}
//// Using libTXT as the text engine.
// font_collection_.RegisterFonts(asset_manager_);
TRACE_EVENT0("flutter", "Engine::Restart");
TRACE_EVENT0("uiwidgets", "Engine::Restart");
if (!configuration.IsValid()) {
FML_LOG(ERROR) << "Engine run configuration was invalid.";
return false;

UpdateAssetManager(nullptr);
return Run(std::move(configuration)) == Engine::RunStatus::Success;
return Run(std::move(configuration)) == RunStatus::Success;
}
Engine::RunStatus Engine::Run(RunConfiguration configuration) {

}
last_entry_point_ = configuration.GetEntrypoint();
last_entry_point_library_ = configuration.GetEntrypointLibrary();
if (isolate_launch_status == Engine::RunStatus::Failure) {
if (isolate_launch_status == RunStatus::Failure) {
FML_LOG(ERROR) << "Engine not prepare and launch isolate.";
return isolate_launch_status;
} else if (isolate_launch_status ==

std::shared_ptr<DartIsolate> isolate =
runtime_controller_->GetRootIsolate().lock();
bool isolate_running =
isolate && isolate->GetPhase() == DartIsolate::Phase::Running;
if (isolate_running) {
tonic::DartState::Scope scope(isolate.get());
if (settings_.root_isolate_create_callback) {
settings_.root_isolate_create_callback();
}
if (settings_.root_isolate_shutdown_callback) {
isolate->AddIsolateShutdownCallback(
settings_.root_isolate_shutdown_callback);
}
std::string service_id = isolate->GetServiceId();
fml::RefPtr<PlatformMessage> service_id_message =
fml::MakeRefCounted<flutter::PlatformMessage>(
kIsolateChannel,
std::vector<uint8_t>(service_id.begin(), service_id.end()),
nullptr);
HandlePlatformMessage(service_id_message);
}
return isolate_running ? Engine::RunStatus::Success
: Engine::RunStatus::Failure;
return RunStatus::Success;
TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate");
TRACE_EVENT0("uiwidgets", "Engine::PrepareAndLaunchIsolate");
auto isolate_configuration = configuration.TakeIsolateConfiguration();
std::shared_ptr<DartIsolate> isolate =
std::shared_ptr<MonoIsolate> isolate =
runtime_controller_->GetRootIsolate().lock();
if (!isolate) {

// This can happen on iOS after a plugin shows a native window and returns to
// the Flutter ViewController.
if (isolate->GetPhase() == DartIsolate::Phase::Running) {
FML_DLOG(WARNING) << "Isolate was already running!";
return RunStatus::FailureAlreadyRunning;
}
if (!isolate_configuration->PrepareIsolate(*isolate)) {
FML_LOG(ERROR) << "Could not prepare to run the isolate.";
return RunStatus::Failure;
}
if (configuration.GetEntrypointLibrary().empty()) {
if (!isolate->Run(configuration.GetEntrypoint(),
settings_.dart_entrypoint_args)) {
FML_LOG(ERROR) << "Could not run the isolate.";
return RunStatus::Failure;
}
} else {
if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
configuration.GetEntrypoint(),
settings_.dart_entrypoint_args)) {
FML_LOG(ERROR) << "Could not run the isolate.";
return RunStatus::Failure;
}
}
MonoState::Scope scope(isolate);
const fml::closure entrypoint_callback =
configuration.GetMonoEntrypointCallback();
entrypoint_callback();
TRACE_EVENT0("flutter", "Engine::BeginFrame");
TRACE_EVENT0("uiwidgets", "Engine::BeginFrame");
TRACE_EVENT0("flutter", "Engine::ReportTimings");
TRACE_EVENT0("uiwidgets", "Engine::ReportTimings");
auto trace_event = std::to_string(deadline - Dart_TimelineGetMicros());
TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
auto trace_event = std::to_string(deadline - Mono_TimelineGetMicros());
TRACE_EVENT1("uiwidgets", "Engine::NotifyIdle", "deadline_now_delta",
std::pair<bool, uint32_t> Engine::GetUIIsolateReturnCode() {
return runtime_controller_->GetRootIsolateReturnCode();
}
Dart_Port Engine::GetUIIsolateMainPort() {
return runtime_controller_->GetMainPort();
}
std::string Engine::GetUIIsolateName() {
return runtime_controller_->GetIsolateName();
}
bool Engine::UIIsolateHasLivePorts() {
return runtime_controller_->HasLivePorts();
}
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
return runtime_controller_->GetLastError();
}
void Engine::OnOutputSurfaceCreated() {
have_surface_ = true;
StartAnimatorIfPossible();

viewport_metrics_ = metrics;
runtime_controller_->SetViewportMetrics(viewport_metrics_);
if (animator_) {
if (dimensions_changed)
animator_->SetDimensionChangePending();
if (have_surface_)
ScheduleFrame();
if (dimensions_changed) animator_->SetDimensionChangePending();
if (have_surface_) ScheduleFrame();
if (HandleLifecyclePlatformMessage(message.get()))
return;
if (HandleLifecyclePlatformMessage(message.get())) return;
if (HandleLocalizationPlatformMessage(message.get()))
return;
if (HandleLocalizationPlatformMessage(message.get())) return;
if (runtime_controller_->IsRootIsolateRunning() &&
runtime_controller_->DispatchPlatformMessage(std::move(message))) {
if (runtime_controller_->DispatchPlatformMessage(std::move(message))) {
return;
}

rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return false;
if (document.HasParseError() || !document.IsObject()) return false;
if (method->value != "setInitialRoute")
return false;
if (method->value != "setInitialRoute") return false;
auto route = root.FindMember("args");
initial_route_ = std::move(route->value.GetString());
return true;

rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return false;
if (document.HasParseError() || !document.IsObject()) return false;
if (method == root.MemberEnd() || method->value != "setLocale")
return false;
if (method == root.MemberEnd() || method->value != "setLocale") return false;
if (args == root.MemberEnd() || !args->value.IsArray())
return false;
if (args == root.MemberEnd() || !args->value.IsArray()) return false;
if (args->value.Size() % strings_per_locale != 0)
return false;
if (args->value.Size() % strings_per_locale != 0) return false;
std::vector<std::string> locale_data;
for (size_t locale_index = 0; locale_index < args->value.Size();
locale_index += strings_per_locale) {

}
void Engine::DispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) {
TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
std::unique_ptr<PointerDataPacket> packet, uint64_t trace_flow_id) {
TRACE_EVENT0("uiwidgets", "Engine::DispatchPointerDataPacket");
TRACE_FLOW_STEP("uiwidgets", "PointerEvent", trace_flow_id);
void Engine::StopAnimator() {
animator_->Stop();
}
void Engine::StopAnimator() { animator_->Stop(); }
if (activity_running_ && have_surface_)
animator_->Start();
if (activity_running_ && have_surface_) animator_->Start();
}
std::string Engine::DefaultRouteName() {

}
void Engine::Render(std::unique_ptr<uiwidgets::LayerTree> layer_tree) {
if (!layer_tree)
return;
if (!layer_tree) return;
// Ensure frame dimensions are sane.
if (layer_tree->frame_size().isEmpty() ||

animator_->Render(std::move(layer_tree));
}
void Engine::UpdateSemantics(SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) {
delegate_.OnEngineUpdateSemantics(std::move(update), std::move(actions));
}
void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move(message));

}
void Engine::UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) {
delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
}
FontCollection& Engine::GetFontCollection() {
return font_collection_;
}
// FontCollection& Engine::GetFontCollection() { return font_collection_; }
void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) {

animator_->ScheduleSecondaryVsyncCallback(callback);
}
std::shared_ptr<fml::ConcurrentMessageLoop> Engine::GetConcurrentMessageLoop() {
return concurrent_message_loop_;
}
void Engine::HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message) {
fml::RefPtr<PlatformMessageResponse> response = message->response();
if (!response) {

response->CompleteEmpty();
}
const std::string& Engine::GetLastEntrypoint() const {
return last_entry_point_;
}
const std::string& Engine::GetLastEntrypointLibrary() const {
return last_entry_point_library_;
}
} // namespace flutter
} // namespace uiwidgets

15
engine/src/shell/common/engine.h


#include "lib/ui/painting/image_decoder.h"
#include "lib/ui/snapshot_delegate.h"
//#include "lib/ui/text/font_collection.h"
#include <flutter/fml/concurrent_message_loop.h>
#include "include/core/SkPicture.h"
#include "lib/ui/window/platform_message.h"
#include "lib/ui/window/viewport_metrics.h"

virtual void OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) = 0;
virtual void OnPreEngineRestart() = 0;
virtual void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) = 0;
virtual void SetNeedsReportTimings(bool needs_reporting) = 0;
};

// |PointerDataDispatcher::Delegate|
void ScheduleSecondaryVsyncCallback(const fml::closure& callback) override;
std::shared_ptr<fml::ConcurrentMessageLoop> GetConcurrentMessageLoop();
Engine::Delegate& delegate_;
Delegate& delegate_;
std::shared_ptr<fml::ConcurrentMessageLoop> concurrent_message_loop_;
std::unique_ptr<Animator> animator_;
std::unique_ptr<RuntimeController> runtime_controller_;

std::unique_ptr<PointerDataDispatcher> pointer_data_dispatcher_;
std::string last_entry_point_;
std::string last_entry_point_library_;
// std::shared_ptr<AssetManager> asset_manager_;
std::shared_ptr<AssetManager> asset_manager_;
FontCollection font_collection_;
// FontCollection font_collection_;
ImageDecoder image_decoder_;
TaskRunners task_runners_;
fml::WeakPtrFactory<Engine> weak_factory_;

622
engine/src/shell/common/shell.cc


// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/common/shell.h"
#include "shell.h"
#include <future>
#include "flutter/assets/directory_asset_bundle.h"
#include "assets/directory_asset_bundle.h"
#include "flutter/fml/icu_util.h"
//#include "flutter/fml/icu_util.h"
#include "flutter/fml/log_settings.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/make_copyable.h"

#include "flutter/fml/unique_fd.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/start_up.h"
#include "flutter/shell/common/engine.h"
#include "flutter/shell/common/persistent_cache.h"
#include "flutter/shell/common/skia_event_tracer_impl.h"
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/vsync_waiter.h"
#include "include/core/SkGraphics.h"
#include "include/utils/SkBase64.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/utils/SkBase64.h"
#include "third_party/tonic/common/log.h"
#include "runtime/start_up.h"
#include "shell/common/engine.h"
#include "shell/common/persistent_cache.h"
//#include "shell/common/skia_event_tracer_impl.h"
//#include "shell/common/switches.h"
#include "shell/common/vsync_waiter.h"
namespace flutter {
namespace uiwidgets {
constexpr char kSkiaChannel[] = "flutter/skia";
constexpr char kSystemChannel[] = "flutter/system";
constexpr char kSkiaChannel[] = "uiwidgets/skia";
constexpr char kSystemChannel[] = "uiwidgets/system";
DartVMRef vm,
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
if (!task_runners.IsValid()) {

auto shell =
std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
auto shell = std::unique_ptr<Shell>(new Shell(task_runners, settings));
// Create the rasterizer on the raster thread.
std::promise<std::unique_ptr<Rasterizer>> rasterizer_promise;

on_create_rasterizer, //
shell = shell.get() //
]() {
TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
TRACE_EVENT0("uiwidgets", "ShellSetupGPUSubsystem");
std::unique_ptr<Rasterizer> rasterizer(on_create_rasterizer(*shell));
snapshot_delegate_promise.set_value(rasterizer->GetSnapshotDelegate());
rasterizer_promise.set_value(std::move(rasterizer));

auto platform_view = on_create_platform_view(*shell.get());
if (!platform_view || !platform_view->GetWeakPtr()) {
snapshot_delegate_future.get();
rasterizer_future.get();
return nullptr;
}

if (!vsync_waiter) {
snapshot_delegate_future.get();
rasterizer_future.get();
return nullptr;
}

io_task_runner, //
is_backgrounded_sync_switch = shell->GetIsGpuDisabledSyncSwitch() //
]() {
TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
TRACE_EVENT0("uiwidgets", "ShellSetupIOSubsystem");
auto io_manager = std::make_unique<ShellIOManager>(
platform_view.getUnsafe()->CreateResourceContext(),
is_backgrounded_sync_switch, io_task_runner);

auto engine_future = engine_promise.get_future();
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetUITaskRunner(),
fml::MakeCopyable([&engine_promise, //
shell = shell.get(), //
&dispatcher_maker, //
&window_data, //
isolate_snapshot = std::move(isolate_snapshot), //
vsync_waiter = std::move(vsync_waiter), //
&weak_io_manager_future, //
&snapshot_delegate_future, //
&unref_queue_future //
fml::MakeCopyable([&engine_promise, //
shell = shell.get(), //
&dispatcher_maker, //
&window_data, //
vsync_waiter = std::move(vsync_waiter), //
&weak_io_manager_future, //
&snapshot_delegate_future, //
&unref_queue_future //
TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
TRACE_EVENT0("uiwidgets", "ShellSetupUISubsystem");
const auto& task_runners = shell->GetTaskRunners();
// The animator is owned by the UI thread but it gets its vsync pulses

engine_promise.set_value(std::make_unique<Engine>(
*shell, //
dispatcher_maker, //
*shell->GetDartVM(), //
std::move(isolate_snapshot), //
task_runners, //
window_data, //
shell->GetSettings(), //

static void RecordStartupTimestamp() {
if (engine_main_enter_ts == 0) {
engine_main_enter_ts = Dart_TimelineGetMicros();
engine_main_enter_ts = Mono_TimelineGetMicros();
std::vector<std::string>* results,
char delimiter) {
std::vector<std::string>* results, char delimiter) {
std::istringstream ss(input);
std::string token;
while (std::getline(ss, token, delimiter)) {

std::call_once(gShellSettingsInitialization, [&settings] {
RecordStartupTimestamp();
tonic::SetLogHandler(
[](const char* message) { FML_LOG(ERROR) << message; });
InitSkiaEventTracer(settings.trace_skia);
// InitSkiaEventTracer(settings.trace_skia);
}
if (!settings.trace_whitelist.empty()) {

}
if (settings.icu_initialization_required) {
if (settings.icu_data_path.size() != 0) {
fml::icu::InitializeICU(settings.icu_data_path);
} else if (settings.icu_mapper) {
fml::icu::InitializeICUFromMapping(settings.icu_mapper());
} else {
FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
}
// if (settings.icu_data_path.size() != 0) {
// fml::icu::InitializeICU(settings.icu_data_path);
//} else if (settings.icu_mapper) {
// fml::icu::InitializeICUFromMapping(settings.icu_mapper());
//} else {
// FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
//}
TaskRunners task_runners,
Settings settings,
TaskRunners task_runners, Settings settings,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
return Shell::Create(std::move(task_runners), //

}
std::unique_ptr<Shell> Shell::Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
PerformInitializationTasks(settings);
PersistentCache::SetCacheSkSL(settings.cache_sksl);
TRACE_EVENT0("flutter", "Shell::Create");
auto vm = DartVMRef::Create(settings);
FML_CHECK(vm) << "Must be able to initialize the VM.";
auto vm_data = vm->GetVMData();
return Shell::Create(std::move(task_runners), //
std::move(window_data), //
std::move(settings), //
vm_data->GetIsolateSnapshot(), // isolate snapshot
on_create_platform_view, //
on_create_rasterizer, //
std::move(vm) //
);
}
std::unique_ptr<Shell> Shell::Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
DartVMRef vm) {
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
TRACE_EVENT0("flutter", "Shell::CreateWithSnapshots");
TRACE_EVENT0("uiwidgets", "Shell::CreateWithSnapshots");
if (!task_runners.IsValid() || !on_create_platform_view ||
!on_create_rasterizer) {

std::unique_ptr<Shell> shell;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetPlatformTaskRunner(),
fml::MakeCopyable([&latch, //
vm = std::move(vm), //
&shell, //
task_runners = std::move(task_runners), //
window_data, //
settings, //
isolate_snapshot = std::move(isolate_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
fml::MakeCopyable([&latch, //
&shell, //
task_runners = std::move(task_runners), //
window_data, //
settings, //
on_create_platform_view, //
on_create_rasterizer //
shell = CreateShellOnPlatformThread(std::move(vm),
std::move(task_runners), //
window_data, //
settings, //
std::move(isolate_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
shell = CreateShellOnPlatformThread(std::move(task_runners), //
window_data, //
settings, //
on_create_platform_view, //
on_create_rasterizer //
);
latch.Signal();
}));

Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
Shell::Shell(TaskRunners task_runners, Settings settings)
vm_(std::move(vm)),
FML_CHECK(vm_) << "Must have access to VM to create a shell.";
FML_DCHECK(task_runners_.IsValid());
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

this->weak_factory_gpu_ =
std::make_unique<fml::WeakPtrFactory<Shell>>(this);
}));
// Install service protocol handlers.
service_protocol_handlers_[ServiceProtocol::kScreenshotExtensionName] = {
task_runners_.GetRasterTaskRunner(),
std::bind(&Shell::OnServiceProtocolScreenshot, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_[ServiceProtocol::kScreenshotSkpExtensionName] = {
task_runners_.GetRasterTaskRunner(),
std::bind(&Shell::OnServiceProtocolScreenshotSKP, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_[ServiceProtocol::kRunInViewExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolRunInView, this, std::placeholders::_1,
std::placeholders::_2)};
service_protocol_handlers_
[ServiceProtocol::kFlushUIThreadTasksExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolFlushUIThreadTasks, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_
[ServiceProtocol::kSetAssetBundlePathExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolSetAssetBundlePath, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_
[ServiceProtocol::kGetDisplayRefreshRateExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolGetDisplayRefreshRate, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_[ServiceProtocol::kGetSkSLsExtensionName] = {
task_runners_.GetIOTaskRunner(),
std::bind(&Shell::OnServiceProtocolGetSkSLs, this, std::placeholders::_1,
std::placeholders::_2)};
vm_->GetServiceProtocol()->RemoveHandler(this);
fml::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch;

// Since a valid shell will not be returned to the embedder without a valid
// DartVMRef, we can be certain that this is a safe spot to assume a VM is
// running.
::Dart_NotifyLowMemory();
// ::Dart_NotifyLowMemory();
task_runners_.GetRasterTaskRunner()->PostTask(
[rasterizer = rasterizer_->GetWeakPtr()]() {

return;
}
auto run_result = weak_engine->Run(std::move(run_configuration));
if (run_result == flutter::Engine::RunStatus::Failure) {
if (run_result == Engine::RunStatus::Failure) {
FML_LOG(ERROR) << "Could not launch engine with configuration.";
}
result(run_result);

std::optional<DartErrorCode> Shell::GetUIIsolateLastError() const {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (!weak_engine_) {
return std::nullopt;
}
switch (weak_engine_->GetUIIsolateLastError()) {
case tonic::kCompilationErrorType:
return DartErrorCode::CompilationError;
case tonic::kApiErrorType:
return DartErrorCode::ApiError;
case tonic::kUnknownErrorType:
return DartErrorCode::UnknownError;
case tonic::kNoError:
return DartErrorCode::NoError;
}
return DartErrorCode::UnknownError;
}
bool Shell::EngineHasLivePorts() const {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (!weak_engine_) {
return false;
}
return weak_engine_->UIIsolateHasLivePorts();
}
bool Shell::IsSetup() const {
return is_setup_;
}
bool Shell::IsSetup() const { return is_setup_; }
bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
std::unique_ptr<Engine> engine,

is_setup_ = true;
vm_->GetServiceProtocol()->AddHandler(this, GetServiceProtocolDescription());
PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner(
task_runners_.GetIOTaskRunner());

return true;
}
const Settings& Shell::GetSettings() const {
return settings_;
}
const Settings& Shell::GetSettings() const { return settings_; }
const TaskRunners& Shell::GetTaskRunners() const {
return task_runners_;
}
const TaskRunners& Shell::GetTaskRunners() const { return task_runners_; }
fml::WeakPtr<Rasterizer> Shell::GetRasterizer() const {
FML_DCHECK(is_setup_);

return weak_platform_view_;
}
DartVM* Shell::GetDartVM() {
return &vm_;
}
TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
TRACE_EVENT0("uiwidgets", "Shell::OnPlatformViewCreated");
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

// a synchronous fashion.
fml::AutoResetWaitableEvent latch;
auto raster_task =
fml::MakeCopyable([& waiting_for_first_frame = waiting_for_first_frame_,
fml::MakeCopyable([&waiting_for_first_frame = waiting_for_first_frame_,
rasterizer = rasterizer_->GetWeakPtr(), //
surface = std::move(surface), //
&latch]() mutable {

FML_DCHECK(platform_view);
bool should_post_ui_task =
task_runners_.GetUITaskRunner() != task_runners_.GetPlatformTaskRunner();
ui_task_runner = task_runners_.GetUITaskRunner(), ui_task] {
ui_task_runner = task_runners_.GetUITaskRunner(), ui_task,
should_post_ui_task, &latch] {
fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
if (should_post_ui_task) {
fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
} else {
latch.Signal();
}
if (!should_post_ui_task) {
ui_task();
latch.Wait();
}
latch.Wait();
TRACE_EVENT0("flutter", "Shell::OnPlatformViewDestroyed");
TRACE_EVENT0("uiwidgets", "Shell::OnPlatformViewDestroyed");
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

// |PlatformView::Delegate|
void Shell::OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) {
TRACE_EVENT0("flutter", "Shell::OnPlatformViewDispatchPointerDataPacket");
TRACE_FLOW_BEGIN("flutter", "PointerEvent", next_pointer_flow_id_);
TRACE_EVENT0("uiwidgets", "Shell::OnPlatformViewDispatchPointerDataPacket");
TRACE_FLOW_BEGIN("uiwidgets", "PointerEvent", next_pointer_flow_id_);
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetUITaskRunner()->PostTask(

}
// |PlatformView::Delegate|
void Shell::OnPlatformViewDispatchSemanticsAction(int32_t id,
SemanticsAction action,
std::vector<uint8_t> args) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetUITaskRunner()->PostTask(
[engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] {
if (engine) {
engine->DispatchSemanticsAction(id, action, std::move(args));
}
});
}
// |PlatformView::Delegate|
void Shell::OnPlatformViewSetSemanticsEnabled(bool enabled) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetUITaskRunner()->PostTask(
[engine = engine_->GetWeakPtr(), enabled] {
if (engine) {
engine->SetSemanticsEnabled(enabled);
}
});
}
// |PlatformView::Delegate|
void Shell::OnPlatformViewSetAccessibilityFeatures(int32_t flags) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

}
// |PlatformView::Delegate|
void Shell::OnPlatformViewRegisterTexture(
std::shared_ptr<flutter::Texture> texture) {
void Shell::OnPlatformViewRegisterTexture(std::shared_ptr<Texture> texture) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

}
// |Animator::Delegate|
void Shell::OnAnimatorDraw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) {
void Shell::OnAnimatorDraw(fml::RefPtr<Pipeline<LayerTree>> pipeline) {
[& waiting_for_first_frame = waiting_for_first_frame_,
[&waiting_for_first_frame = waiting_for_first_frame_,
&waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
rasterizer = rasterizer_->GetWeakPtr(),
pipeline = std::move(pipeline)]() {

}
// |Engine::Delegate|
void Shell::OnEngineUpdateSemantics(SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetPlatformTaskRunner()->PostTask(
[view = platform_view_->GetWeakPtr(), update = std::move(update),
actions = std::move(actions)] {
if (view) {
view->UpdateSemantics(std::move(update), std::move(actions));
}
});
}
// |Engine::Delegate|
void Shell::OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) {
FML_DCHECK(is_setup_);

rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return;
if (document.HasParseError() || !document.IsObject()) return;
if (method->value != "Skia.setResourceCacheMaxBytes")
return;
if (method->value != "Skia.setResourceCacheMaxBytes") return;
if (args == root.MemberEnd() || !args->value.IsInt())
return;
if (args == root.MemberEnd() || !args->value.IsInt()) return;
task_runners_.GetRasterTaskRunner()->PostTask(
[rasterizer = rasterizer_->GetWeakPtr(), max_bytes = args->value.GetInt(),

latch.Wait();
}
// |Engine::Delegate|
void Shell::UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) {
Handler::Description description(isolate_port, isolate_name);
vm_->GetServiceProtocol()->SetHandlerDescription(this, description);
}
void Shell::SetNeedsReportTimings(bool value) {
needs_report_timings_ = value;
}
void Shell::SetNeedsReportTimings(bool value) { needs_report_timings_ = value; }
void Shell::ReportTimings() {
FML_DCHECK(is_setup_);

first_frame_rasterized_ = true;
ReportTimings();
} else if (!frame_timings_report_scheduled_) {
#if FLUTTER_RELEASE
#if UIWIDGETS_RELEASE
constexpr int kBatchTimeInMilliseconds = 1000;
#else
constexpr int kBatchTimeInMilliseconds = 100;

}
}
// |ServiceProtocol::Handler|
fml::RefPtr<fml::TaskRunner> Shell::GetServiceProtocolHandlerTaskRunner(
std::string_view method) const {
FML_DCHECK(is_setup_);
auto found = service_protocol_handlers_.find(method);
if (found != service_protocol_handlers_.end()) {
return found->second.first;
}
return task_runners_.GetUITaskRunner();
}
// |ServiceProtocol::Handler|
bool Shell::HandleServiceProtocolMessage(
std::string_view method, // one if the extension names specified above.
const ServiceProtocolMap& params,
rapidjson::Document& response) {
auto found = service_protocol_handlers_.find(method);
if (found != service_protocol_handlers_.end()) {
return found->second.second(params, response);
}
return false;
}
// |ServiceProtocol::Handler|
ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription()
const {
return {
engine_->GetUIIsolateMainPort(),
engine_->GetUIIsolateName(),
};
}
static void ServiceProtocolParameterError(rapidjson::Document& response,
std::string error_details) {
auto& allocator = response.GetAllocator();
response.SetObject();
const int64_t kInvalidParams = -32602;
response.AddMember("code", kInvalidParams, allocator);
response.AddMember("message", "Invalid params", allocator);
{
rapidjson::Value details(rapidjson::kObjectType);
details.AddMember("details", error_details, allocator);
response.AddMember("data", details, allocator);
}
}
static void ServiceProtocolFailureError(rapidjson::Document& response,
std::string message) {
auto& allocator = response.GetAllocator();
response.SetObject();
const int64_t kJsonServerError = -32000;
response.AddMember("code", kJsonServerError, allocator);
response.AddMember("message", message, allocator);
}
// Service protocol handler
bool Shell::OnServiceProtocolScreenshot(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
auto screenshot = rasterizer_->ScreenshotLastLayerTree(
Rasterizer::ScreenshotType::CompressedImage, true);
if (screenshot.data) {
response.SetObject();
auto& allocator = response.GetAllocator();
response.AddMember("type", "Screenshot", allocator);
rapidjson::Value image;
image.SetString(static_cast<const char*>(screenshot.data->data()),
screenshot.data->size(), allocator);
response.AddMember("screenshot", image, allocator);
return true;
}
ServiceProtocolFailureError(response, "Could not capture image screenshot.");
return false;
}
// Service protocol handler
bool Shell::OnServiceProtocolScreenshotSKP(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
auto screenshot = rasterizer_->ScreenshotLastLayerTree(
Rasterizer::ScreenshotType::SkiaPicture, true);
if (screenshot.data) {
response.SetObject();
auto& allocator = response.GetAllocator();
response.AddMember("type", "ScreenshotSkp", allocator);
rapidjson::Value skp;
skp.SetString(static_cast<const char*>(screenshot.data->data()),
screenshot.data->size(), allocator);
response.AddMember("skp", skp, allocator);
return true;
}
ServiceProtocolFailureError(response, "Could not capture SKP screenshot.");
return false;
}
// Service protocol handler
bool Shell::OnServiceProtocolRunInView(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (params.count("mainScript") == 0) {
ServiceProtocolParameterError(response,
"'mainScript' parameter is missing.");
return false;
}
if (params.count("assetDirectory") == 0) {
ServiceProtocolParameterError(response,
"'assetDirectory' parameter is missing.");
return false;
}
std::string main_script_path =
fml::paths::FromURI(params.at("mainScript").data());
std::string asset_directory_path =
fml::paths::FromURI(params.at("assetDirectory").data());
auto main_script_file_mapping =
std::make_unique<fml::FileMapping>(fml::OpenFile(
main_script_path.c_str(), false, fml::FilePermission::kRead));
auto isolate_configuration = IsolateConfiguration::CreateForKernel(
std::move(main_script_file_mapping));
RunConfiguration configuration(std::move(isolate_configuration));
configuration.SetEntrypointAndLibrary(engine_->GetLastEntrypoint(),
engine_->GetLastEntrypointLibrary());
configuration.AddAssetResolver(
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
asset_directory_path.c_str(), false, fml::FilePermission::kRead)));
auto& allocator = response.GetAllocator();
response.SetObject();
if (engine_->Restart(std::move(configuration))) {
response.AddMember("type", "Success", allocator);
auto new_description = GetServiceProtocolDescription();
rapidjson::Value view(rapidjson::kObjectType);
new_description.Write(this, view, allocator);
response.AddMember("view", view, allocator);
return true;
} else {
FML_DLOG(ERROR) << "Could not run configuration in engine.";
ServiceProtocolFailureError(response,
"Could not run configuration in engine.");
return false;
}
FML_DCHECK(false);
return false;
}
// Service protocol handler
bool Shell::OnServiceProtocolFlushUIThreadTasks(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
// This API should not be invoked by production code.
// It can potentially starve the service isolate if the main isolate pauses
// at a breakpoint or is in an infinite loop.
//
// It should be invoked from the VM Service and and blocks it until UI thread
// tasks are processed.
response.SetObject();
response.AddMember("type", "Success", response.GetAllocator());
return true;
}
bool Shell::OnServiceProtocolGetDisplayRefreshRate(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
response.SetObject();
response.AddMember("type", "DisplayRefreshRate", response.GetAllocator());
response.AddMember("fps", engine_->GetDisplayRefreshRate(),
response.GetAllocator());
return true;
}
bool Shell::OnServiceProtocolGetSkSLs(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetIOTaskRunner()->RunsTasksOnCurrentThread());
response.SetObject();
response.AddMember("type", "GetSkSLs", response.GetAllocator());
rapidjson::Value shaders_json(rapidjson::kObjectType);
PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
std::vector<PersistentCache::SkSLCache> sksls = persistent_cache->LoadSkSLs();
for (const auto& sksl : sksls) {
size_t b64_size =
SkBase64::Encode(sksl.second->data(), sksl.second->size(), nullptr);
sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
char* b64_char = static_cast<char*>(b64_data->writable_data());
SkBase64::Encode(sksl.second->data(), sksl.second->size(), b64_char);
b64_char[b64_size] = 0; // make it null terminated for printing
rapidjson::Value shader_value(b64_char, response.GetAllocator());
rapidjson::Value shader_key(PersistentCache::SkKeyToFilePath(*sksl.first),
response.GetAllocator());
shaders_json.AddMember(shader_key, shader_value, response.GetAllocator());
}
response.AddMember("SkSLs", shaders_json, response.GetAllocator());
return true;
}
// Service protocol handler
bool Shell::OnServiceProtocolSetAssetBundlePath(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (params.count("assetDirectory") == 0) {
ServiceProtocolParameterError(response,
"'assetDirectory' parameter is missing.");
return false;
}
auto& allocator = response.GetAllocator();
response.SetObject();
auto asset_manager = std::make_shared<AssetManager>();
asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
fml::OpenDirectory(params.at("assetDirectory").data(), false,
fml::FilePermission::kRead)));
if (engine_->UpdateAssetManager(std::move(asset_manager))) {
response.AddMember("type", "Success", allocator);
auto new_description = GetServiceProtocolDescription();
rapidjson::Value view(rapidjson::kObjectType);
new_description.Write(this, view, allocator);
response.AddMember("view", view, allocator);
return true;
} else {
FML_DLOG(ERROR) << "Could not update asset directory.";
ServiceProtocolFailureError(response, "Could not update asset directory.");
return false;
}
FML_DCHECK(false);
return false;
}
Rasterizer::ScreenshotType screenshot_type,
bool base64_encode) {
TRACE_EVENT0("flutter", "Shell::Screenshot");
Rasterizer::ScreenshotType screenshot_type, bool base64_encode) {
TRACE_EVENT0("uiwidgets", "Shell::Screenshot");
fml::AutoResetWaitableEvent latch;
Rasterizer::Screenshot screenshot;
fml::TaskRunner::RunNowOrPostTask(

std::unique_lock<std::mutex> lock(waiting_for_first_frame_mutex_);
bool success = waiting_for_first_frame_condition_.wait_for(
lock, std::chrono::milliseconds(timeout.ToMilliseconds()),
[& waiting_for_first_frame = waiting_for_first_frame_] {
[&waiting_for_first_frame = waiting_for_first_frame_] {
return !waiting_for_first_frame.load();
});
if (success) {

if (!engine_) {
return false;
}
engine_->GetFontCollection().GetFontCollection()->SetupDefaultFontManager();
engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
// engine_->GetFontCollection().GetFontCollection()->SetupDefaultFontManager();
// engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
// After system fonts are reloaded, we send a system channel message
// to notify flutter framework.
rapidjson::Document document;

document.Accept(writer);
std::string message = buffer.GetString();
fml::RefPtr<PlatformMessage> fontsChangeMessage =
fml::MakeRefCounted<flutter::PlatformMessage>(
fml::MakeRefCounted<PlatformMessage>(
kSystemChannel, std::vector<uint8_t>(message.begin(), message.end()),
nullptr);

return is_gpu_disabled_sync_switch_;
}
} // namespace flutter
} // namespace uiwidgets

335
engine/src/shell/common/shell.h


class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler {
public Rasterizer::Delegate {
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// If this is the first instance of a shell in the process, this
/// call also bootstraps the Dart VM.
///
/// @param[in] task_runners The task runners
/// @param[in] settings The settings
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
TaskRunners task_runners,
Settings settings,
TaskRunners task_runners, Settings settings,
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// Unlike the simpler variant of this factory method, this method
/// allows for specification of window data. If this is the first
/// instance of a shell in the process, this call also bootstraps
/// the Dart VM.
///
/// @param[in] task_runners The task runners
/// @param[in] window_data The default data for setting up
/// ui.Window that attached to this
/// intance.
/// @param[in] settings The settings
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
CreateCallback<PlatformView> on_create_platform_view,
CreateCallback<Rasterizer> on_create_rasterizer);
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// Unlike the simpler variant of this factory method, this method
/// allows for the specification of an isolate snapshot that
/// cannot be adequately described in the settings. This call also
/// requires the specification of a running VM instance.
///
/// @param[in] task_runners The task runners
/// @param[in] window_data The default data for setting up
/// ui.Window that attached to this
/// intance.
/// @param[in] settings The settings
/// @param[in] isolate_snapshot A custom isolate snapshot. Takes
/// precedence over any snapshots
/// specified in the settings.
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
/// @param[in] vm A running VM instance.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
static std::unique_ptr<Shell> Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const CreateCallback<Rasterizer>& on_create_rasterizer,
DartVMRef vm);
const CreateCallback<Rasterizer>& on_create_rasterizer);
//----------------------------------------------------------------------------
/// @brief Destroys the shell. This is a synchronous operation and
/// synchronous barrier blocks are introduced on the various
/// threads to ensure shutdown of all shell sub-components before
/// this method returns.
///
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration.
///
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration. The
/// result_callback will be called with the status of the
/// operation.
///
//------------------------------------------------------------------------------
/// @return The settings used to launch this shell.
///
//------------------------------------------------------------------------------
/// @brief If callers wish to interact directly with any shell
/// subcomponents, they must (on the platform thread) obtain a
/// task runner that the component is designed to run on and a
/// weak pointer to that component. They may then post a task to
/// that task runner, do the validity check on that task runner
/// before performing any operation on that component. This
/// accessor allows callers to access the task runners for this
/// shell.
///
/// @return The task runners current in use by the shell.
///
//----------------------------------------------------------------------------
/// @brief Rasterizers may only be accessed on the GPU task runner.
///
/// @return A weak pointer to the rasterizer.
///
//------------------------------------------------------------------------------
/// @brief Engines may only be accessed on the UI thread. This method is
/// deprecated, and implementers should instead use other API
/// available on the Shell or the PlatformView.
///
/// @return A weak pointer to the engine.
///
//----------------------------------------------------------------------------
/// @brief Platform views may only be accessed on the platform task
/// runner.
///
/// @return A weak pointer to the platform view.
///
// Embedders should call this under low memory conditions to free up
// internal caches used.
//
// This method posts a task to the raster threads to signal the Rasterizer to
// free resources.
//----------------------------------------------------------------------------
/// @brief Used by embedders to notify that there is a low memory
/// warning. The shell will attempt to purge caches. Current, only
/// the rasterizer cache is purged.
//----------------------------------------------------------------------------
/// @brief Used by embedders to check if all shell subcomponents are
/// initialized. It is the embedder's responsibility to make this
/// call before accessing any other shell method. A shell that is
/// not setup must be discarded and another one created with
/// updated settings.
///
/// @return Returns if the shell has been setup. Once set up, this does
/// not change for the life-cycle of the shell.
///
//----------------------------------------------------------------------------
/// @brief Captures a screenshot and optionally Base64 encodes the data
/// of the last layer tree rendered by the rasterizer in this
/// shell.
///
/// @param[in] type The type of screenshot to capture.
/// @param[in] base64_encode If the screenshot data should be base64
/// encoded.
///
/// @return The screenshot result.
///
//----------------------------------------------------------------------------
/// @brief Pauses the calling thread until the first frame is presented.
///
/// @return 'kOk' when the first frame has been presented before the timeout
/// successfully, 'kFailedPrecondition' if called from the GPU or UI
/// thread, 'kDeadlineExceeded' if there is a timeout.
///
//----------------------------------------------------------------------------
/// @brief Used by embedders to reload the system fonts in
/// FontCollection.
/// It also clears the cached font families and send system
/// channel message to framework to rebuild affected widgets.
///
/// @return Returns if shell reloads system fonts successfully.
///
//----------------------------------------------------------------------------
/// @brief Used by embedders to get the last error from the Dart UI
/// Isolate, if one exists.
///
/// @return Returns the last error code from the UI Isolate.
///
std::optional<DartErrorCode> GetUIIsolateLastError() const;
//----------------------------------------------------------------------------
/// @brief Used by embedders to check if the Engine is running and has
/// any live ports remaining. For example, the Flutter tester uses
/// this method to check whether it should continue to wait for
/// a running test or not.
///
/// @return Returns if the shell has an engine and the engine has any live
/// Dart ports.
///
bool EngineHasLivePorts() const;
//----------------------------------------------------------------------------
/// @brief Accessor for the disable GPU SyncSwitch
//----------------------------------------------------------------------------
/// @brief Get a pointer to the Dart VM used by this running shell
/// instance.
///
/// @return The Dart VM pointer.
///
DartVM* GetDartVM();
using ServiceProtocolHandler =
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
rapidjson::Document&)>;
DartVMRef vm_;
std::unique_ptr<PlatformView> platform_view_; // on platform task runner
std::unique_ptr<Engine> engine_; // on UI task runner
std::unique_ptr<Rasterizer> rasterizer_; // on GPU task runner

fml::WeakPtr<PlatformView>
weak_platform_view_; // to be shared across threads
std::unordered_map<std::string_view, // method
std::pair<fml::RefPtr<fml::TaskRunner>,
ServiceProtocolHandler> // task-runner/function
// pair
>
service_protocol_handlers_;
bool is_setup_ = false;
uint64_t next_pointer_flow_id_ = 0;

// How many frames have been timed since last report.
size_t UnreportedFramesCount() const;
Shell(DartVMRef vm, TaskRunners task_runners, Settings settings);
Shell(TaskRunners task_runners, Settings settings);
DartVMRef vm,
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer);

// |PlatformView::Delegate|
void OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) override;
// |PlatformView::Delegate|
void OnPlatformViewDispatchSemanticsAction(
int32_t id,
SemanticsAction action,
std::vector<uint8_t> args) override;
// |PlatformView::Delegate|
void OnPlatformViewSetSemanticsEnabled(bool enabled) override;
void OnPlatformViewRegisterTexture(
std::shared_ptr<flutter::Texture> texture) override;
void OnPlatformViewRegisterTexture(std::shared_ptr<Texture> texture) override;
// |PlatformView::Delegate|
void OnPlatformViewUnregisterTexture(int64_t texture_id) override;

void OnAnimatorNotifyIdle(int64_t deadline) override;
// |Animator::Delegate|
void OnAnimatorDraw(
fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) override;
void OnAnimatorDraw(fml::RefPtr<Pipeline<LayerTree>> pipeline) override;
void OnEngineUpdateSemantics(
SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) override;
// |Engine::Delegate|
void OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) override;

void OnPreEngineRestart() override;
// |Engine::Delegate|
void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) override;
// |Engine::Delegate|
void SetNeedsReportTimings(bool value) override;
// |Rasterizer::Delegate|

fml::Milliseconds GetFrameBudget() override;
// |ServiceProtocol::Handler|
fml::RefPtr<fml::TaskRunner> GetServiceProtocolHandlerTaskRunner(
std::string_view method) const override;
// |ServiceProtocol::Handler|
bool HandleServiceProtocolMessage(
std::string_view method, // one if the extension names specified above.
const ServiceProtocolMap& params,
rapidjson::Document& response) override;
// |ServiceProtocol::Handler|
ServiceProtocol::Handler::Description GetServiceProtocolDescription()
const override;
// Service protocol handler
bool OnServiceProtocolScreenshot(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolScreenshotSKP(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolRunInView(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolFlushUIThreadTasks(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolSetAssetBundlePath(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolGetDisplayRefreshRate(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
//
// The returned SkSLs are base64 encoded. Decode before storing them to files.
bool OnServiceProtocolGetSkSLs(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
fml::WeakPtrFactory<Shell> weak_factory_;
// For accessing the Shell via the raster thread, necessary for various

friend class testing::ShellTest;
} // namespace flutter
#endif // SHELL_COMMON_SHELL_H_
} // namespace uiwidgets

2
engine/src/shell/common/vsync_waiter.h


virtual float GetDisplayRefreshRate() const;
protected:
friend class VsyncWaiterEmbedder;
// On some backends, the |FireCallback| needs to be made from a static C
// method.
// TODO(kg):

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


fileFormatVersion: 2
guid: 0dd4bb15542f4ad9a7bef43d7defab5f
timeCreated: 1599458064

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


fileFormatVersion: 2
guid: 32b343b53c4d484f8c149742f9d0a919
timeCreated: 1599028965

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


fileFormatVersion: 2
guid: ffb851d47f1449fa9ea328aa58f27be7
timeCreated: 1597215228

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


fileFormatVersion: 2
guid: 1fea1ea4786b4e6bb65b233b11e8b2d5
timeCreated: 1599458322

7
engine/src/runtime/start_up.cc


#include "start_up.h"
namespace uiwidgets {
int64_t engine_main_enter_ts = 0;
} // namespace uiwidgets

9
engine/src/runtime/start_up.h


#pragma once
#include <stdint.h>
namespace uiwidgets {
extern int64_t engine_main_enter_ts;
} // namespace uiwidgets

194
engine/src/shell/common/canvas_spy.cc


#include "canvas_spy.h"
namespace uiwidgets {
CanvasSpy::CanvasSpy(SkCanvas* target_canvas) {
SkISize canvas_size = target_canvas->getBaseLayerSize();
n_way_canvas_ =
std::make_unique<SkNWayCanvas>(canvas_size.width(), canvas_size.height());
did_draw_canvas_ = std::make_unique<DidDrawCanvas>(canvas_size.width(),
canvas_size.height());
n_way_canvas_->addCanvas(target_canvas);
n_way_canvas_->addCanvas(did_draw_canvas_.get());
}
SkCanvas* CanvasSpy::GetSpyingCanvas() { return n_way_canvas_.get(); }
DidDrawCanvas::DidDrawCanvas(int width, int height)
: SkCanvasVirtualEnforcer<SkNoDrawCanvas>(width, height) {}
DidDrawCanvas::~DidDrawCanvas() {}
void DidDrawCanvas::MarkDrawIfNonTransparentPaint(const SkPaint& paint) {
bool isTransparent = paint.getAlpha() == 0;
did_draw_ |= !isTransparent;
}
bool CanvasSpy::DidDrawIntoCanvas() {
return did_draw_canvas_->DidDrawIntoCanvas();
}
bool DidDrawCanvas::DidDrawIntoCanvas() { return did_draw_; }
void DidDrawCanvas::willSave() {}
SkCanvas::SaveLayerStrategy DidDrawCanvas::getSaveLayerStrategy(
const SaveLayerRec& rec) {
return kNoLayer_SaveLayerStrategy;
}
bool DidDrawCanvas::onDoSaveBehind(const SkRect* bounds) { return false; }
void DidDrawCanvas::willRestore() {}
void DidDrawCanvas::didConcat(const SkMatrix& matrix) {}
void DidDrawCanvas::didConcat44(const SkM44&) {}
void DidDrawCanvas::didScale(SkScalar, SkScalar) {}
void DidDrawCanvas::didTranslate(SkScalar, SkScalar) {}
void DidDrawCanvas::didSetMatrix(const SkMatrix& matrix) {}
void DidDrawCanvas::onClipRect(const SkRect& rect, SkClipOp op,
ClipEdgeStyle edgeStyle) {}
void DidDrawCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op,
ClipEdgeStyle edgeStyle) {}
void DidDrawCanvas::onClipPath(const SkPath& path, SkClipOp op,
ClipEdgeStyle edgeStyle) {}
void DidDrawCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) {}
void DidDrawCanvas::onDrawPaint(const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawBehind(const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPoints(PointMode mode, size_t count,
const SkPoint pts[], const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawArc(const SkRect& rect, SkScalar startAngle,
SkScalar sweepAngle, bool useCenter,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawImage(const SkImage* image, SkScalar left,
SkScalar top, const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawImageRect(const SkImage* image, const SkRect* src,
const SkRect& dst, const SkPaint* paint,
SrcRectConstraint constraint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
const SkRect& dst, const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawImageLattice(const SkImage* image,
const Lattice& lattice,
const SkRect& dst,
const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x,
SkScalar y, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPicture(const SkPicture* picture,
const SkMatrix* matrix,
const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawDrawable(SkDrawable* drawable,
const SkMatrix* matrix) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawVerticesObject(const SkVertices* vertices,
SkBlendMode bmode,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPatch(const SkPoint cubics[12],
const SkColor colors[4],
const SkPoint texCoords[4], SkBlendMode bmode,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[],
int count, SkBlendMode bmode,
const SkRect* cull, const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawShadowRec(const SkPath& path,
const SkDrawShadowRec& rec) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawAnnotation(const SkRect& rect, const char key[],
SkData* data) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
SkCanvas::QuadAAFlags aa,
const SkColor4f& color, SkBlendMode mode) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawEdgeAAImageSet(const ImageSetEntry set[], int count,
const SkPoint dstClips[],
const SkMatrix preViewMatrices[],
const SkPaint* paint,
SrcRectConstraint constraint) {
did_draw_ = true;
}
void DidDrawCanvas::onFlush() {}
} // namespace uiwidgets

165
engine/src/shell/common/canvas_spy.h


#pragma once
#include "flutter/fml/macros.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkCanvasVirtualEnforcer.h"
#include "include/utils/SkNWayCanvas.h"
#include "include/utils/SkNoDrawCanvas.h"
namespace uiwidgets {
class DidDrawCanvas;
class CanvasSpy {
public:
CanvasSpy(SkCanvas* target_canvas);
bool DidDrawIntoCanvas();
SkCanvas* GetSpyingCanvas();
private:
std::unique_ptr<SkNWayCanvas> n_way_canvas_;
std::unique_ptr<DidDrawCanvas> did_draw_canvas_;
FML_DISALLOW_COPY_AND_ASSIGN(CanvasSpy);
};
class DidDrawCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
public:
DidDrawCanvas(int width, int height);
~DidDrawCanvas() override;
bool DidDrawIntoCanvas();
private:
bool did_draw_ = false;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void willSave() override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
bool onDoSaveBehind(const SkRect*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void willRestore() override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void didConcat(const SkMatrix&) override;
void didConcat44(const SkM44&) override;
void didScale(SkScalar, SkScalar) override;
void didTranslate(SkScalar, SkScalar) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void didSetMatrix(const SkMatrix&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkBlendMode,
const SkPaint& paint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPaint(const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawBehind(const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPoints(PointMode, size_t count, const SkPoint pts[],
const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawRect(const SkRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawRegion(const SkRegion&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawOval(const SkRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawArc(const SkRect&, SkScalar, SkScalar, bool,
const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawRRect(const SkRRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPath(const SkPath&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImage(const SkImage*, SkScalar left, SkScalar top,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint*, SrcRectConstraint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawVerticesObject(const SkVertices*, SkBlendMode,
const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[],
const SkColor[], int, SkBlendMode, const SkRect*,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipRegion(const SkRegion&, SkClipOp) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPicture(const SkPicture*, const SkMatrix*,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], SkCanvas::QuadAAFlags,
const SkColor4f&, SkBlendMode) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawEdgeAAImageSet(const ImageSetEntry[], int count, const SkPoint[],
const SkMatrix[], const SkPaint*,
SrcRectConstraint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onFlush() override;
void MarkDrawIfNonTransparentPaint(const SkPaint& paint);
FML_DISALLOW_COPY_AND_ASSIGN(DidDrawCanvas);
};
} // namespace uiwidgets

64
engine/src/shell/common/run_configuration.cc


#include "run_configuration.h"
#include <sstream>
#include <utility>
#include "assets/directory_asset_bundle.h"
#include "flutter/fml/file.h"
#include "flutter/fml/unique_fd.h"
namespace uiwidgets {
RunConfiguration RunConfiguration::InferFromSettings(const Settings& settings) {
auto asset_manager = std::make_shared<AssetManager>();
if (fml::UniqueFD::traits_type::IsValid(settings.assets_dir)) {
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
fml::Duplicate(settings.assets_dir)));
}
asset_manager->PushBack(
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
return {asset_manager, settings.mono_entrypoint_callback};
}
RunConfiguration::RunConfiguration()
: RunConfiguration(std::make_shared<AssetManager>(), fml::closure()) {}
RunConfiguration::RunConfiguration(std::shared_ptr<AssetManager> asset_manager,
fml::closure mono_entrypoint_callback)
: asset_manager_(std::move(asset_manager)),
mono_entrypoint_callback_(std::move(mono_entrypoint_callback)) {}
RunConfiguration::RunConfiguration(RunConfiguration&&) = default;
RunConfiguration::~RunConfiguration() = default;
bool RunConfiguration::IsValid() const {
return static_cast<bool>(asset_manager_);
}
bool RunConfiguration::AddAssetResolver(
std::unique_ptr<AssetResolver> resolver) {
if (!resolver || !resolver->IsValid()) {
return false;
}
asset_manager_->PushBack(std::move(resolver));
return true;
}
std::shared_ptr<AssetManager> RunConfiguration::GetAssetManager() const {
return asset_manager_;
}
void RunConfiguration::SetMonoEntrypointCallback(fml::closure mono_entrypoint_callback) {
mono_entrypoint_callback_ = std::move(mono_entrypoint_callback);
}
fml::closure RunConfiguration::GetMonoEntrypointCallback() const {
return mono_entrypoint_callback_;
}
} // namespace uiwidgets

42
engine/src/shell/common/run_configuration.h


#pragma once
#include <memory>
#include <string>
#include "assets/asset_manager.h"
#include "assets/asset_resolver.h"
#include "common/settings.h"
#include "flutter/fml/macros.h"
namespace uiwidgets {
class RunConfiguration {
public:
static RunConfiguration InferFromSettings(const Settings& settings);
RunConfiguration();
RunConfiguration(std::shared_ptr<AssetManager> asset_manager, fml::closure mono_entrypoint_callback);
RunConfiguration(RunConfiguration&& config);
~RunConfiguration();
bool IsValid() const;
bool AddAssetResolver(std::unique_ptr<AssetResolver> resolver);
std::shared_ptr<AssetManager> GetAssetManager() const;
void SetMonoEntrypointCallback(fml::closure mono_entrypoint_callback);
fml::closure GetMonoEntrypointCallback() const;
private:
std::shared_ptr<AssetManager> asset_manager_;
fml::closure mono_entrypoint_callback_;
FML_DISALLOW_COPY_AND_ASSIGN(RunConfiguration);
};
} // namespace uiwidgets

24
engine/third_party/Unity/IUnityUIWidgets.h


#pragma once
#include "IUnityInterface.h"
#include "IUnityGraphics.h"
namespace UnityUIWidgets {
typedef void (*VoidCallback)();
typedef void (*VoidCallbackLong)(long);
UNITY_DECLARE_INTERFACE(IUnityUIWidgets) {
virtual ~IUnityUIWidgets() {}
virtual void SetUpdateCallback(VoidCallback callback) = 0;
virtual void SetVSyncCallback(VoidCallback callback) = 0;
virtual void SetWaitCallback(VoidCallbackLong callback) = 0;
virtual void SetWakeUpCallback(VoidCallback callback) = 0;
virtual void IssuePluginEventAndData(UnityRenderingEventAndData callback,
int eventId, void* data) = 0;
};
} // namespace UnityUIWidgets
UNITY_REGISTER_INTERFACE_GUID_IN_NAMESPACE(0x4C8BE8056B3C41D7ULL,
0xBC8BF5F2F0AC3532ULL,
IUnityUIWidgets, UnityUIWidgets)

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


using System;
using System.Collections.Generic;
namespace Unity.UIWidgets.async2 {
public struct FutureOr {
public object value;
public Future future;
public bool isFuture => future != null;
public static FutureOr withValue(object value) {
return new FutureOr {value = value};
}
public static FutureOr withFuture(Future future) {
return new FutureOr {future = future};
}
public static readonly FutureOr nullValue = withValue(null);
public static readonly FutureOr trueValue = withValue(true);
public static readonly FutureOr falseValue = withValue(false);
}
public abstract class Future {
static readonly _Future _nullFuture = _Future.zoneValue(null, Zone.root);
static readonly _Future _falseFuture = _Future.zoneValue(false, Zone.root);
public static Future create(Func<FutureOr> computation) {
_Future result = new _Future();
Timer.run(() => {
try {
result._complete(computation());
}
catch (Exception e) {
async_._completeWithErrorCallback(result, e);
}
return null;
});
return result;
}
public static Future microtask(Func<FutureOr> computation) {
_Future result = new _Future();
async_.scheduleMicrotask(() => {
try {
result._complete(computation());
}
catch (Exception e) {
async_._completeWithErrorCallback(result, e);
}
return null;
});
return result;
}
public static Future sync(Func<FutureOr> computation) {
try {
var result = computation();
if (result.isFuture) {
return result.future;
}
else {
return _Future.value(result);
}
}
catch (Exception error) {
var future = new _Future();
AsyncError replacement = Zone.current.errorCallback(error);
if (replacement != null) {
future._asyncCompleteError(async_._nonNullError(replacement.InnerException));
}
else {
future._asyncCompleteError(error);
}
return future;
}
}
public static Future value(FutureOr value = default) {
return _Future.immediate(value);
}
public static Future error(Exception error) {
if (error == null)
throw new ArgumentNullException(nameof(error));
if (!ReferenceEquals(Zone.current, async_._rootZone)) {
AsyncError replacement = Zone.current.errorCallback(error);
if (replacement != null) {
error = async_._nonNullError(replacement.InnerException);
}
}
return _Future.immediateError(error);
}
public static Future delayed(TimeSpan duration, Func<FutureOr> computation = null) {
_Future result = new _Future();
Timer.create(duration, () => {
if (computation == null) {
result._complete(FutureOr.nullValue);
}
else {
try {
result._complete(computation());
}
catch (Exception e) {
async_._completeWithErrorCallback(result, e);
}
}
return null;
});
return result;
}
public static Future wait<T>(IEnumerable<Future> futures, bool eagerError = false, Action<T> cleanUp = null) {
_Future result = new _Future();
List<T> values = null; // Collects the values. Set to null on error.
int remaining = 0; // How many futures are we waiting for.
Exception error = null; // The first error from a future.
Func<Exception, FutureOr> handleError = (Exception theError) => {
remaining--;
if (values != null) {
if (cleanUp != null) {
foreach (var value in values) {
if (value != null) {
// Ensure errors from cleanUp are uncaught.
Future.sync(() => {
cleanUp(value);
return FutureOr.nullValue;
});
}
}
}
values = null;
if (remaining == 0 || eagerError) {
result._completeError(theError);
}
else {
error = theError;
}
}
else if (remaining == 0 && !eagerError) {
result._completeError(error);
}
return FutureOr.nullValue;
};
try {
// As each future completes, put its value into the corresponding
// position in the list of values.
foreach (var future in futures) {
int pos = remaining;
future.then((object value) => {
remaining--;
if (values != null) {
values[pos] = (T) value;
if (remaining == 0) {
result._completeWithValue(values);
}
}
else {
if (cleanUp != null && value != null) {
// Ensure errors from cleanUp are uncaught.
Future.sync(() => {
cleanUp((T) value);
return FutureOr.nullValue;
});
}
if (remaining == 0 && !eagerError) {
result._completeError(error);
}
}
return FutureOr.nullValue;
}, onError: handleError);
// Increment the 'remaining' after the call to 'then'.
// If that call throws, we don't expect any future callback from
// the future, and we also don't increment remaining.
remaining++;
}
if (remaining == 0) {
return Future.value(FutureOr.withValue(new List<T>()));
}
values = new List<T>(remaining);
}
catch (Exception e) {
// The error must have been thrown while iterating over the futures
// list, or while installing a callback handler on the future.
if (remaining == 0 || eagerError) {
// Throw a new Future.error.
// Don't just call `result._completeError` since that would propagate
// the error too eagerly, not giving the callers time to install
// error handlers.
// Also, don't use `_asyncCompleteError` since that one doesn't give
// zones the chance to intercept the error.
return Future.error(e);
}
else {
// Don't allocate a list for values, thus indicating that there was an
// error.
// Set error to the caught exception.
error = e;
}
}
return result;
}
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;
};
Func<Exception, FutureOr> onError = (Exception error) => {
if (!completer.isCompleted) completer.completeError(error);
return FutureOr.nullValue;
};
foreach (var future in futures) {
future.then(onValue, onError: onError);
}
return completer.future;
}
public static Future forEach<T>(IEnumerable<T> elements, Func<T, FutureOr> action) {
var iterator = elements.GetEnumerator();
return doWhile(() => {
if (!iterator.MoveNext()) return FutureOr.falseValue;
var result = action(iterator.Current);
if (result.isFuture) return FutureOr.withFuture(result.future.then(_kTrue));
return FutureOr.trueValue;
});
}
static readonly Func<object, FutureOr> _kTrue = (_) => FutureOr.trueValue;
public static Future doWhile(Func<FutureOr> action) {
_Future doneSignal = new _Future();
ZoneUnaryCallback nextIteration = null;
// Bind this callback explicitly so that each iteration isn't bound in the
// context of all the previous iterations' callbacks.
// This avoids, e.g., deeply nested stack traces from the stack trace
// package.
nextIteration = Zone.current.bindUnaryCallbackGuarded((object keepGoingObj) => {
bool keepGoing = (bool) keepGoingObj;
while (keepGoing) {
FutureOr result;
try {
result = action();
}
catch (Exception error) {
// Cannot use _completeWithErrorCallback because it completes
// the future synchronously.
async_._asyncCompleteWithErrorCallback(doneSignal, error);
return null;
}
if (result.isFuture) {
result.future.then((value) => {
nextIteration((bool) value);
return FutureOr.nullValue;
}, onError: error => {
doneSignal._completeError(error);
return FutureOr.nullValue;
});
return null;
}
keepGoing = (bool) result.value;
}
doneSignal._complete(FutureOr.nullValue);
return null;
});
nextIteration(true);
return doneSignal;
}
public abstract Future then(Func<object, FutureOr> onValue, Func<Exception, FutureOr> onError = null);
public abstract Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null);
public abstract Future whenComplete(Func<object> action);
// public abstract Stream asStream();
public abstract Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null);
}
public class TimeoutException : Exception {
public readonly TimeSpan? duration;
public TimeoutException(string message, TimeSpan? duration = null) : base(message) {
this.duration = duration;
}
public override string ToString() {
string result = "TimeoutException";
if (duration != null) result = $"TimeoutException after {duration}";
if (Message != null) result = $"result: {Message}";
return result;
}
}
public abstract class Completer {
public static Completer create() => new _AsyncCompleter();
public static Completer sync() => new _SyncCompleter();
public abstract Future future { get; }
public abstract void complete(FutureOr value = default);
public abstract void completeError(Exception error);
public abstract bool isCompleted { get; }
}
public static partial class async_ {
internal static void _completeWithErrorCallback(_Future result, Exception error) {
AsyncError replacement = Zone.current.errorCallback(error);
if (replacement != null) {
error = _nonNullError(replacement.InnerException);
}
result._completeError(error);
}
internal static void _asyncCompleteWithErrorCallback(_Future result, Exception error) {
AsyncError replacement = Zone.current.errorCallback(error);
if (replacement != null) {
error = _nonNullError(replacement.InnerException);
}
result._asyncCompleteError(error);
}
internal static Exception _nonNullError(Exception error) =>
error ?? new Exception("Throw of null.");
}
}

3
com.unity.uiwidgets/Runtime/async2/future.cs.meta


fileFormatVersion: 2
guid: bdf10194e91e4558bc97ebad8b81d5a0
timeCreated: 1599458114

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


using System;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.async2 {
using _FutureOnValue = Func<object, FutureOr>;
using _FutureErrorTest = Func<Exception, bool>;
using _FutureAction = Func<object>;
abstract class _Completer : Completer {
protected readonly _Future _future = new _Future();
public override Future future => _future;
public override void completeError(Exception error) {
if (error == null)
throw new ArgumentNullException(nameof(error));
if (!_future._mayComplete) throw new Exception("Future already completed");
AsyncError replacement = Zone.current.errorCallback(error);
if (replacement != null) {
error = async_._nonNullError(replacement.InnerException);
}
_completeError(error);
}
protected abstract void _completeError(Exception error);
public override bool isCompleted => !_future._mayComplete;
}
class _AsyncCompleter : _Completer {
public override void complete(FutureOr value = default) {
if (!_future._mayComplete) throw new Exception("Future already completed");
_future._asyncComplete(value);
}
protected override void _completeError(Exception error) {
_future._asyncCompleteError(error);
}
}
class _SyncCompleter : _Completer {
public override void complete(FutureOr value = default) {
if (!_future._mayComplete) throw new Exception("Future already completed");
_future._complete(value);
}
protected override void _completeError(Exception error) {
_future._completeError(error);
}
}
class _FutureListener {
public const int maskValue = 1;
public const int maskError = 2;
public const int maskTestError = 4;
public const int maskWhencomplete = 8;
public const int stateChain = 0;
public const int stateThen = maskValue;
public const int stateThenOnerror = maskValue | maskError;
public const int stateCatcherror = maskError;
public const int stateCatcherrorTest = maskError | maskTestError;
public const int stateWhencomplete = maskWhencomplete;
public const int maskType = maskValue | maskError | maskTestError | maskWhencomplete;
public const int stateIsAwait = 16;
internal _FutureListener _nextListener;
public readonly _Future result;
public readonly int state;
public readonly Delegate callback;
public readonly Func<Exception, FutureOr> errorCallback;
_FutureListener(_Future result, Delegate callback, Func<Exception, FutureOr> errorCallback, int state) {
this.result = result;
this.state = state;
this.callback = callback;
this.errorCallback = errorCallback;
}
public static _FutureListener then(
_Future result, _FutureOnValue onValue, Func<Exception, FutureOr> errorCallback) {
return new _FutureListener(
result, onValue, errorCallback,
(errorCallback == null) ? stateThen : stateThenOnerror
);
}
public static _FutureListener thenAwait(
_Future result, _FutureOnValue onValue, Func<Exception, FutureOr> errorCallback) {
return new _FutureListener(
result, onValue, errorCallback,
((errorCallback == null) ? stateThen : stateThenOnerror) | stateIsAwait
);
}
public static _FutureListener catchError(_Future result, Func<Exception, FutureOr> errorCallback,
_FutureErrorTest callback) {
return new _FutureListener(
result, callback, errorCallback,
(callback == null) ? stateCatcherror : stateCatcherrorTest
);
}
public static _FutureListener whenComplete(_Future result, _FutureAction callback) {
return new _FutureListener(
result, callback, null,
stateWhencomplete
);
}
internal Zone _zone => result._zone;
public bool handlesValue => (state & maskValue) != 0;
public bool handlesError => (state & maskError) != 0;
public bool hasErrorTest => (state & maskType) == stateCatcherrorTest;
public bool handlesComplete => (state & maskType) == stateWhencomplete;
public bool isAwait => (state & stateIsAwait) != 0;
internal _FutureOnValue _onValue {
get {
D.assert(handlesValue);
return (_FutureOnValue) callback;
}
}
internal Func<Exception, FutureOr> _onError => errorCallback;
internal _FutureErrorTest _errorTest {
get {
D.assert(hasErrorTest);
return (_FutureErrorTest) callback;
}
}
internal _FutureAction _whenCompleteAction {
get {
D.assert(handlesComplete);
return (_FutureAction) callback;
}
}
public bool hasErrorCallback {
get {
D.assert(handlesError);
return _onError != null;
}
}
public FutureOr handleValue(object sourceResult) {
return (FutureOr) _zone.runUnary(arg => _onValue(arg), sourceResult);
}
public bool matchesErrorTest(AsyncError asyncError) {
if (!hasErrorTest) return true;
return (bool) _zone.runUnary(arg => _errorTest((Exception) arg), asyncError.InnerException);
}
public FutureOr handleError(AsyncError asyncError) {
D.assert(handlesError && hasErrorCallback);
var errorCallback = this.errorCallback;
return (FutureOr) _zone.runUnary(arg => errorCallback((Exception) arg), asyncError.InnerException);
}
public object handleWhenComplete() {
D.assert(!handlesError);
return _zone.run(() => _whenCompleteAction());
}
}
public class _Future : Future {
internal const int _stateIncomplete = 0;
internal const int _statePendingComplete = 1;
internal const int _stateChained = 2;
internal const int _stateValue = 4;
internal const int _stateError = 8;
internal int _state = _stateIncomplete;
internal readonly Zone _zone;
internal object _resultOrListeners;
internal _Future() {
_zone = Zone.current;
}
internal _Future(Zone zone) {
_zone = zone;
}
internal static _Future immediate(object result) {
var future = new _Future(Zone.current);
future._asyncComplete(result);
return future;
}
internal static _Future zoneValue(object value, Zone zone) {
var future = new _Future(zone);
future._setValue(value);
return future;
}
internal static _Future immediateError(Exception error) {
var future = new _Future(Zone.current);
future._asyncCompleteError(error);
return future;
}
internal static _Future value(object value) {
return zoneValue(value, Zone.current);
}
internal bool _mayComplete => _state == _stateIncomplete;
internal bool _isPendingComplete => _state == _statePendingComplete;
internal bool _mayAddListener => _state <= _statePendingComplete;
internal bool _isChained => _state == _stateChained;
internal bool _isComplete => _state >= _stateValue;
internal bool _hasError => _state == _stateError;
internal void _setChained(_Future source) {
D.assert(_mayAddListener);
_state = _stateChained;
_resultOrListeners = source;
}
public override Future then(Func<object, FutureOr> f, Func<Exception, FutureOr> onError = null) {
Zone currentZone = Zone.current;
if (!ReferenceEquals(currentZone, async_._rootZone)) {
f = async_._registerUnaryHandler(f, currentZone);
if (onError != null) {
onError = async_._registerErrorHandler(onError, currentZone);
}
}
_Future result = new _Future();
_addListener(_FutureListener.then(result, f, onError));
return result;
}
public override Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null) {
_Future result = new _Future();
if (!ReferenceEquals(result._zone, async_._rootZone)) {
onError = async_._registerErrorHandler(onError, result._zone);
if (test != null) {
test = async_._registerUnaryHandler(test, result._zone);
}
}
_addListener(_FutureListener.catchError(result, onError, test));
return result;
}
public override Future whenComplete(Func<object> action) {
_Future result = new _Future();
if (!ReferenceEquals(result._zone, async_._rootZone)) {
action = async_._registerHandler(action, result._zone);
}
_addListener(_FutureListener.whenComplete(result, action));
return result;
}
// Stream<T> asStream() => new Stream<T>.fromFuture(this);
internal void _setPendingComplete() {
D.assert(_mayComplete);
_state = _statePendingComplete;
}
internal void _clearPendingComplete() {
D.assert(_isPendingComplete);
_state = _stateIncomplete;
}
internal AsyncError _error {
get {
D.assert(_hasError);
return (AsyncError) _resultOrListeners;
}
}
internal _Future _chainSource {
get {
D.assert(_isChained);
return (_Future) _resultOrListeners;
}
}
internal void _setValue(object value) {
D.assert(!_isComplete); // But may have a completion pending.
_state = _stateValue;
_resultOrListeners = value;
}
internal void _setErrorObject(AsyncError error) {
D.assert(!_isComplete); // But may have a completion pending.
_state = _stateError;
_resultOrListeners = error;
}
internal void _setError(Exception error) {
_setErrorObject(new AsyncError(error));
}
internal void _cloneResult(_Future source) {
D.assert(!_isComplete);
D.assert(source._isComplete);
_state = source._state;
_resultOrListeners = source._resultOrListeners;
}
internal void _addListener(_FutureListener listener) {
D.assert(listener._nextListener == null);
if (_mayAddListener) {
listener._nextListener = (_FutureListener) _resultOrListeners;
_resultOrListeners = listener;
}
else {
if (_isChained) {
// Delegate listeners to chained source future.
// If the source is complete, instead copy its values and
// drop the chaining.
_Future source = _chainSource;
if (!source._isComplete) {
source._addListener(listener);
return;
}
_cloneResult(source);
}
D.assert(_isComplete);
// Handle late listeners asynchronously.
_zone.scheduleMicrotask(() => {
_propagateToListeners(this, listener);
return null;
});
}
}
void _prependListeners(_FutureListener listeners) {
if (listeners == null) return;
if (_mayAddListener) {
_FutureListener existingListeners = (_FutureListener) _resultOrListeners;
_resultOrListeners = listeners;
if (existingListeners != null) {
_FutureListener cursor = listeners;
while (cursor._nextListener != null) {
cursor = cursor._nextListener;
}
cursor._nextListener = existingListeners;
}
}
else {
if (_isChained) {
// Delegate listeners to chained source future.
// If the source is complete, instead copy its values and
// drop the chaining.
_Future source = _chainSource;
if (!source._isComplete) {
source._prependListeners(listeners);
return;
}
_cloneResult(source);
}
D.assert(_isComplete);
listeners = _reverseListeners(listeners);
_zone.scheduleMicrotask(() => {
_propagateToListeners(this, listeners);
return null;
});
}
}
_FutureListener _removeListeners() {
// Reverse listeners before returning them, so the resulting list is in
// subscription order.
D.assert(!_isComplete);
_FutureListener current = (_FutureListener) _resultOrListeners;
_resultOrListeners = null;
return _reverseListeners(current);
}
_FutureListener _reverseListeners(_FutureListener listeners) {
_FutureListener prev = null;
_FutureListener current = listeners;
while (current != null) {
_FutureListener next = current._nextListener;
current._nextListener = prev;
prev = current;
current = next;
}
return prev;
}
static void _chainForeignFuture(Future source, _Future target) {
D.assert(!target._isComplete);
D.assert(!(source is _Future));
// Mark the target as chained (and as such half-completed).
target._setPendingComplete();
try {
source.then((value) => {
D.assert(target._isPendingComplete);
// The "value" may be another future if the foreign future
// implementation is mis-behaving,
// so use _complete instead of _completeWithValue.
target._clearPendingComplete(); // Clear this first, it's set again.
target._complete(FutureOr.withValue(value));
return new FutureOr();
},
onError: (Exception error) => {
D.assert(target._isPendingComplete);
target._completeError(error);
return new FutureOr();
});
}
catch (Exception e) {
// This only happens if the `then` call threw synchronously when given
// valid arguments.
// That requires a non-conforming implementation of the Future interface,
// which should, hopefully, never happen.
async_.scheduleMicrotask(() => {
target._completeError(e);
return null;
});
}
}
static void _chainCoreFuture(_Future source, _Future target) {
D.assert(target._mayAddListener); // Not completed, not already chained.
while (source._isChained) {
source = source._chainSource;
}
if (source._isComplete) {
_FutureListener listeners = target._removeListeners();
target._cloneResult(source);
_propagateToListeners(target, listeners);
}
else {
_FutureListener listeners = (_FutureListener) target._resultOrListeners;
target._setChained(source);
source._prependListeners(listeners);
}
}
internal void _complete(FutureOr value) {
D.assert(!_isComplete);
if (value.isFuture) {
if (value.future is _Future coreFuture) {
_chainCoreFuture(coreFuture, this);
}
else {
_chainForeignFuture(value.future, this);
}
}
else {
_FutureListener listeners = _removeListeners();
_setValue(value);
_propagateToListeners(this, listeners);
}
}
internal void _completeWithValue(object value) {
D.assert(!_isComplete);
D.assert(!(value is Future));
_FutureListener listeners = _removeListeners();
_setValue(value);
_propagateToListeners(this, listeners);
}
internal void _completeError(Exception error) {
D.assert(!_isComplete);
_FutureListener listeners = _removeListeners();
_setError(error);
_propagateToListeners(this, listeners);
}
internal void _asyncComplete(object value) {
D.assert(!_isComplete);
// Two corner cases if the value is a future:
// 1. the future is already completed and an error.
// 2. the future is not yet completed but might become an error.
// The first case means that we must not immediately complete the Future,
// as our code would immediately start propagating the error without
// giving the time to install error-handlers.
// However the second case requires us to deal with the value immediately.
// Otherwise the value could complete with an error and report an
// unhandled error, even though we know we are already going to listen to
// it.
if (value is Future future) {
_chainFuture(future);
return;
}
_setPendingComplete();
_zone.scheduleMicrotask(() => {
_completeWithValue(value);
return null;
});
}
internal void _chainFuture(Future value) {
if (value is _Future future) {
if (future._hasError) {
// Delay completion to allow the user to register callbacks.
_setPendingComplete();
_zone.scheduleMicrotask(() => {
_chainCoreFuture(future, this);
return null;
});
}
else {
_chainCoreFuture(future, this);
}
return;
}
// Just listen on the foreign future. This guarantees an async delay.
_chainForeignFuture(value, this);
}
internal void _asyncCompleteError(Exception error) {
D.assert(!_isComplete);
_setPendingComplete();
_zone.scheduleMicrotask(() => {
_completeError(error);
return null;
});
}
static void _propagateToListeners(_Future source, _FutureListener listeners) {
while (true) {
D.assert(source._isComplete);
bool hasError = source._hasError;
if (listeners == null) {
if (hasError) {
AsyncError asyncError = source._error;
source._zone.handleUncaughtError(asyncError);
}
return;
}
// Usually futures only have one listener. If they have several, we
// call handle them separately in recursive calls, continuing
// here only when there is only one listener left.
while (listeners._nextListener != null) {
_FutureListener currentListener = listeners;
listeners = currentListener._nextListener;
currentListener._nextListener = null;
_propagateToListeners(source, currentListener);
}
_FutureListener listener = listeners;
var sourceResult = source._resultOrListeners;
// Do the actual propagation.
// Set initial state of listenerHasError and listenerValueOrError. These
// variables are updated with the outcome of potential callbacks.
// Non-error results, including futures, are stored in
// listenerValueOrError and listenerHasError is set to false. Errors
// are stored in listenerValueOrError as an [AsyncError] and
// listenerHasError is set to true.
bool listenerHasError = hasError;
var listenerValueOrError = sourceResult;
// Only if we either have an error or callbacks, go into this, somewhat
// expensive, branch. Here we'll enter/leave the zone. Many futures
// don't have callbacks, so this is a significant optimization.
if (hasError || listener.handlesValue || listener.handlesComplete) {
Zone zone = listener._zone;
if (hasError && !source._zone.inSameErrorZone(zone)) {
// Don't cross zone boundaries with errors.
AsyncError asyncError = source._error;
source._zone.handleUncaughtError(asyncError);
return;
}
Zone oldZone = null;
if (!ReferenceEquals(Zone.current, zone)) {
// Change zone if it's not current.
oldZone = Zone._enter(zone);
}
// These callbacks are abstracted to isolate the try/catch blocks
// from the rest of the code to work around a V8 glass jaw.
Action handleWhenCompleteCallback = () => {
// The whenComplete-handler is not combined with normal value/error
// handling. This means at most one handleX method is called per
// listener.
D.assert(!listener.handlesValue);
D.assert(!listener.handlesError);
object completeResult = null;
try {
completeResult = listener.handleWhenComplete();
}
catch (Exception e) {
if (hasError && ReferenceEquals(source._error.InnerException, e)) {
listenerValueOrError = source._error;
}
else {
listenerValueOrError = new AsyncError(e);
}
listenerHasError = true;
return;
}
if (completeResult is Future completeResultFuture) {
if (completeResult is _Future completeResultCoreFuture &&
completeResultCoreFuture._isComplete) {
if (completeResultCoreFuture._hasError) {
listenerValueOrError = completeResultCoreFuture._error;
listenerHasError = true;
}
// Otherwise use the existing result of source.
return;
}
// We have to wait for the completeResult future to complete
// before knowing if it's an error or we should use the result
// of source.
var originalSource = source;
listenerValueOrError =
completeResultFuture.then((_) => FutureOr.withFuture(originalSource));
listenerHasError = false;
}
};
Action handleValueCallback = () => {
try {
listenerValueOrError = listener.handleValue(sourceResult);
}
catch (Exception e) {
listenerValueOrError = new AsyncError(e);
listenerHasError = true;
}
};
Action handleError = () => {
try {
AsyncError asyncError = source._error;
if (listener.matchesErrorTest(asyncError) &&
listener.hasErrorCallback) {
listenerValueOrError = listener.handleError(asyncError);
listenerHasError = false;
}
}
catch (Exception e) {
if (ReferenceEquals(source._error.InnerException, e)) {
listenerValueOrError = source._error;
}
else {
listenerValueOrError = new AsyncError(e);
}
listenerHasError = true;
}
};
if (listener.handlesComplete) {
handleWhenCompleteCallback();
}
else if (!hasError) {
if (listener.handlesValue) {
handleValueCallback();
}
}
else {
if (listener.handlesError) {
handleError();
}
}
// If we changed zone, oldZone will not be null.
if (oldZone != null) Zone._leave(oldZone);
// 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) {
// Shortcut if the chain-source is already completed. Just continue
// the loop.
_Future listenerResult = listener.result;
if (chainSource is _Future chainSourceCore) {
if (chainSourceCore._isComplete) {
listeners = listenerResult._removeListeners();
listenerResult._cloneResult(chainSourceCore);
source = chainSourceCore;
continue;
}
else {
_chainCoreFuture(chainSourceCore, listenerResult);
}
}
else {
_chainForeignFuture(chainSource, listenerResult);
}
return;
}
}
_Future result = listener.result;
listeners = result._removeListeners();
if (!listenerHasError) {
result._setValue(listenerValueOrError);
}
else {
AsyncError asyncError = (AsyncError) listenerValueOrError;
result._setErrorObject(asyncError);
}
// Prepare for next round.
source = result;
}
}
public override Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null) {
if (_isComplete) return _Future.immediate(this);
_Future result = new _Future();
Timer timer;
if (onTimeout == null) {
timer = Timer.create(timeLimit, () => {
result._completeError(
new TimeoutException("Future not completed", timeLimit));
return null;
});
}
else {
Zone zone = Zone.current;
onTimeout = async_._registerHandler(onTimeout, zone);
timer = Timer.create(timeLimit, () => {
try {
result._complete((FutureOr) zone.run(() => onTimeout()));
}
catch (Exception e) {
result._completeError(e);
}
return null;
});
}
then(v => {
if (timer.isActive) {
timer.cancel();
result._completeWithValue(v);
}
return FutureOr.nullValue;
}, onError: e => {
if (timer.isActive) {
timer.cancel();
result._completeError(e);
}
return FutureOr.nullValue;
});
return result;
}
}
public static partial class async_ {
internal static Func<object> _registerHandler(Func<object> handler, Zone zone) {
var callback = zone.registerCallback(() => handler());
return () => callback();
}
internal static Func<FutureOr> _registerHandler(Func<FutureOr> handler, Zone zone) {
var callback = zone.registerCallback(() => handler());
return () => (FutureOr) callback();
}
internal static Func<object, FutureOr> _registerUnaryHandler(Func<object, FutureOr> handler, Zone zone) {
var callback = zone.registerUnaryCallback(arg => handler(arg));
return arg => (FutureOr) callback(arg);
}
internal static Func<Exception, bool> _registerUnaryHandler(Func<Exception, bool> handler, Zone zone) {
var callback = zone.registerUnaryCallback(arg => handler((Exception) arg));
return arg => (bool) callback(arg);
}
internal static Func<Exception, FutureOr> _registerErrorHandler(Func<Exception, FutureOr> errorHandler,
Zone zone) {
var callback = zone.registerUnaryCallback(arg => errorHandler((Exception) arg));
return arg => (FutureOr) callback(arg);
}
}
}

3
com.unity.uiwidgets/Runtime/async2/future_impl.cs.meta


fileFormatVersion: 2
guid: 4072406cc46448f99159c137b458841e
timeCreated: 1599458114

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


using System;
using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.ui2;
namespace Unity.UIWidgets.async2 {
class _AsyncCallbackEntry {
public readonly ZoneCallback callback;
public _AsyncCallbackEntry next;
internal _AsyncCallbackEntry(ZoneCallback callback) {
this.callback = callback;
}
}
public static partial class async_ {
static _AsyncCallbackEntry _nextCallback;
static _AsyncCallbackEntry _lastCallback;
static _AsyncCallbackEntry _lastPriorityCallback;
static bool _isInCallbackLoop = false;
static void _microtaskLoop() {
while (_nextCallback != null) {
_lastPriorityCallback = null;
_AsyncCallbackEntry entry = _nextCallback;
_nextCallback = entry.next;
if (_nextCallback == null) _lastCallback = null;
entry.callback();
}
}
static object _startMicrotaskLoop() {
_isInCallbackLoop = true;
try {
// Moved to separate function because try-finally prevents
// good optimization.
_microtaskLoop();
}
finally {
_lastPriorityCallback = null;
_isInCallbackLoop = false;
if (_nextCallback != null) {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
}
return null;
}
static void _scheduleAsyncCallback(ZoneCallback callback) {
_AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
if (_nextCallback == null) {
_nextCallback = _lastCallback = newEntry;
if (!_isInCallbackLoop) {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
}
else {
_lastCallback.next = newEntry;
_lastCallback = newEntry;
}
}
static void _schedulePriorityAsyncCallback(ZoneCallback callback) {
if (_nextCallback == null) {
_scheduleAsyncCallback(callback);
_lastPriorityCallback = _lastCallback;
return;
}
_AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback);
if (_lastPriorityCallback == null) {
entry.next = _nextCallback;
_nextCallback = _lastPriorityCallback = entry;
}
else {
entry.next = _lastPriorityCallback.next;
_lastPriorityCallback.next = entry;
_lastPriorityCallback = entry;
if (entry.next == null) {
_lastCallback = entry;
}
}
}
public static void scheduleMicrotask(ZoneCallback callback) {
_Zone currentZone = (_Zone) Zone.current;
if (ReferenceEquals(_rootZone, currentZone)) {
// No need to bind the callback. We know that the root's scheduleMicrotask
// will be invoked in the root zone.
_rootScheduleMicrotask(null, null, _rootZone, callback);
return;
}
_ZoneFunction<ScheduleMicrotaskHandler> implementation = currentZone._scheduleMicrotask;
if (ReferenceEquals(_rootZone, implementation.zone) &&
_rootZone.inSameErrorZone(currentZone)) {
_rootScheduleMicrotask(
null, null, currentZone, currentZone.registerCallback(callback));
return;
}
Zone.current.scheduleMicrotask(Zone.current.bindCallbackGuarded(callback));
}
}
class _AsyncRun {
internal static void _scheduleImmediate(ZoneCallback callback) {
GCHandle callabackHandle = GCHandle.Alloc(callback);
UIMonoState_scheduleMicrotask(_scheduleMicrotask, (IntPtr) callabackHandle);
}
[MonoPInvokeCallback(typeof(UIMonoState_scheduleMicrotaskCallback))]
static void _scheduleMicrotask(IntPtr callbackHandle) {
GCHandle handle = (GCHandle) callbackHandle;
var callback = (ZoneCallback) handle.Target;
handle.Free();
callback();
}
delegate void UIMonoState_scheduleMicrotaskCallback(IntPtr callbackHandle);
[DllImport(NativeBindings.dllName)]
static extern void UIMonoState_scheduleMicrotask(UIMonoState_scheduleMicrotaskCallback callback,
IntPtr callbackHandle);
}
}

3
com.unity.uiwidgets/Runtime/async2/schedule_microtask.cs.meta


fileFormatVersion: 2
guid: e9d7bdadaa9c46e0b96ba19f4261185a
timeCreated: 1599458114

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


using System;
using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.ui2;
namespace Unity.UIWidgets.async2 {
public abstract class Timer : IDisposable {
public static Timer create(TimeSpan duration, ZoneCallback callback) {
if (Zone.current == Zone.root) {
return Zone.current.createTimer(duration, callback);
}
return Zone.current
.createTimer(duration, Zone.current.bindCallbackGuarded(callback));
}
public static Timer periodic(TimeSpan duration, ZoneUnaryCallback callback) {
if (Zone.current == Zone.root) {
return Zone.current.createPeriodicTimer(duration, callback);
}
var boundCallback = Zone.current.bindUnaryCallbackGuarded(callback);
return Zone.current.createPeriodicTimer(duration, boundCallback);
}
public static void run(ZoneCallback callback) {
Timer.create(TimeSpan.Zero, callback);
}
public abstract void cancel();
public void Dispose() {
cancel();
}
public abstract int tick { get; }
public abstract bool isActive { get; }
internal static Timer _createTimer(TimeSpan duration, ZoneCallback callback) {
return _Timer._createTimer(_ => callback(), (int) duration.TotalMilliseconds, false);
}
internal static Timer _createPeriodicTimer(
TimeSpan duration, ZoneUnaryCallback callback) {
return _Timer._createTimer(callback, (int) duration.TotalMilliseconds, true);
}
}
class _Timer : Timer {
int _tick = 0;
ZoneUnaryCallback _callback;
int _wakeupTime;
readonly int _milliSeconds;
readonly bool _repeating;
_Timer(ZoneUnaryCallback callback, int wakeupTime, int milliSeconds, bool repeating) {
_callback = callback;
_wakeupTime = wakeupTime;
_milliSeconds = milliSeconds;
_repeating = repeating;
}
internal static _Timer _createTimer(ZoneUnaryCallback callback, int milliSeconds, bool repeating) {
if (milliSeconds < 0) {
milliSeconds = 0;
}
int now = UIMonoState_timerMillisecondClock();
int wakeupTime = (milliSeconds == 0) ? now : (now + 1 + milliSeconds);
_Timer timer = new _Timer(callback, wakeupTime, milliSeconds, repeating);
timer._enqueue();
return timer;
}
public override void cancel() {
_callback = null;
}
public override bool isActive => _callback != null;
public override int tick => _tick;
void _advanceWakeupTime() {
if (_milliSeconds > 0) {
_wakeupTime += _milliSeconds;
}
else {
_wakeupTime = UIMonoState_timerMillisecondClock();
}
}
void _enqueue() {
GCHandle callabackHandle = GCHandle.Alloc(this);
UIMonoState_postTaskForTime(_postTaskForTime, (IntPtr) callabackHandle, _wakeupTime * 1000L);
}
[MonoPInvokeCallback(typeof(UIMonoState_postTaskForTimeCallback))]
static void _postTaskForTime(IntPtr callbackHandle) {
GCHandle timerHandle = (GCHandle) callbackHandle;
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;
}
}
timer._tick += 1;
callback(timer);
if (timer._repeating && (timer._callback != null)) {
timer._advanceWakeupTime();
timer._enqueue();
}
}
}
[DllImport(NativeBindings.dllName)]
static extern int UIMonoState_timerMillisecondClock();
delegate void UIMonoState_postTaskForTimeCallback(IntPtr callbackHandle);
[DllImport(NativeBindings.dllName)]
static extern void UIMonoState_postTaskForTime(UIMonoState_postTaskForTimeCallback callback,
IntPtr callbackHandle, long targetTimeNanos);
}
}

3
com.unity.uiwidgets/Runtime/async2/timer.cs.meta


fileFormatVersion: 2
guid: dc44ad1967714937b709d5f22c6b3bec
timeCreated: 1599458114

1001
com.unity.uiwidgets/Runtime/async2/zone.cs
文件差异内容过多而无法显示
查看文件

3
com.unity.uiwidgets/Runtime/async2/zone.cs.meta


fileFormatVersion: 2
guid: d8dbf866190b44e6a47e0ff7c0e2bdc4
timeCreated: 1599458114

8
com.unity.uiwidgets/Runtime/developer/extension.cs


using System.Collections;
namespace developer {
public static partial class developer_ {
public static void postEvent(string eventKind, Hashtable eventData) {
}
}
}

3
com.unity.uiwidgets/Runtime/developer/extension.cs.meta


fileFormatVersion: 2
guid: d2dcff701560471ab813d010a98a7d36
timeCreated: 1599030815

11
com.unity.uiwidgets/Runtime/developer/timeline.cs


using System.Collections;
namespace developer {
public class Timeline {
public static void startSync(string name, Hashtable arguments = null) {
}
public static void finishSync() {
}
}
}

3
com.unity.uiwidgets/Runtime/developer/timeline.cs.meta


fileFormatVersion: 2
guid: 263dee475b944a33a99e0d8925f904c4
timeCreated: 1599028971

3
com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs.meta


fileFormatVersion: 2
guid: 305c123a2a944eba8f2b397a962323ff
timeCreated: 1597215247

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


using System;
using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui2;
using UnityEngine;
using UnityEngine.UI;
using NativeBindings = Unity.UIWidgets.ui2.NativeBindings;
namespace Unity.UIWidgets.engine2 {
public class UIWidgetsPanel : RawImage {
public IntPtr isolate { get; private set; }
IntPtr _ptr;
GCHandle _handle;
RenderTexture _renderTexture;
int _width;
int _height;
float _devicePixelRatio;
int _currentWidth {
get { return Mathf.RoundToInt(rectTransform.rect.width * canvas.scaleFactor); }
}
int _currentHeight {
get { return Mathf.RoundToInt(rectTransform.rect.height * canvas.scaleFactor); }
}
float _currentDevicePixelRatio {
get {
float currentDpi = Screen.dpi;
if (currentDpi == 0) {
currentDpi = canvas.GetComponent<CanvasScaler>().fallbackScreenDPI;
}
return currentDpi / 96;
}
}
protected override void OnEnable() {
base.OnEnable();
_recreateRenderTexture(_currentWidth, _currentHeight, _currentDevicePixelRatio);
_handle = GCHandle.Alloc(this);
_ptr = UIWidgetsPanel_constructor((IntPtr) _handle, UIWidgetsPanel_entrypoint);
UIWidgetsPanel_onEnable(_ptr, _renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio);
}
protected virtual void main() {
Debug.Log(Debug.isDebugBuild);
}
public void entryPoint() {
try {
isolate = Isolate.current;
main();
}
catch (Exception ex) {
Debug.LogException(new Exception("exception in main", ex));
}
}
protected override void OnRectTransformDimensionsChange() {
if (_ptr != IntPtr.Zero) {
if (_recreateRenderTexture(_currentWidth, _currentHeight, _currentDevicePixelRatio)) {
UIWidgetsPanel_onRenderTexture(_ptr,
_renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio);
}
}
}
protected override void OnDisable() {
UIWidgetsPanel_onDisable(_ptr);
UIWidgetsPanel_dispose(_ptr);
_ptr = IntPtr.Zero;
_handle.Free();
_handle = default;
base.OnDisable();
}
bool _recreateRenderTexture(int width, int height, float devicePixelRatio) {
if (_renderTexture != null && _width == width && _height == height &&
_devicePixelRatio == devicePixelRatio) {
return false;
}
if (_renderTexture) {
_destroyRenderTexture();
}
_createRenderTexture(width, height, devicePixelRatio);
return true;
}
void _createRenderTexture(int width, int height, float devicePixelRatio) {
D.assert(_renderTexture == null);
var desc = new RenderTextureDescriptor(
width, height, RenderTextureFormat.ARGB32, 0) {
useMipMap = false,
autoGenerateMips = false,
};
_renderTexture = new RenderTexture(desc) {hideFlags = HideFlags.HideAndDontSave};
_renderTexture.Create();
_width = width;
_height = height;
_devicePixelRatio = devicePixelRatio;
texture = _renderTexture;
}
void _destroyRenderTexture() {
D.assert(_renderTexture != null);
texture = null;
ObjectUtils.SafeDestroy(_renderTexture);
_renderTexture = null;
}
delegate void UIWidgetsPanel_EntrypointCallback(IntPtr handle);
[MonoPInvokeCallback(typeof(UIWidgetsPanel_EntrypointCallback))]
static void UIWidgetsPanel_entrypoint(IntPtr handle) {
GCHandle gcHandle = (GCHandle) handle;
UIWidgetsPanel panel = (UIWidgetsPanel) gcHandle.Target;
panel.entryPoint();
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr UIWidgetsPanel_constructor(IntPtr handle,
UIWidgetsPanel_EntrypointCallback entrypointCallback);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_dispose(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onEnable(IntPtr ptr,
IntPtr nativeTexturePtr, int width, int height, float dpi);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onDisable(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onRenderTexture(
IntPtr ptr, IntPtr nativeTexturePtr, int width, int height, float dpi);
}
}

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


using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using developer;
using Unity.UIWidgets.async;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui2;
using UnityEngine;
using FrameTiming = Unity.UIWidgets.ui2.FrameTiming;
using Timer = Unity.UIWidgets.async2.Timer;
namespace Unity.UIWidgets.scheduler2 {
public static partial class scheduler_ {
public static float timeDilation {
get { return _timeDilation; }
set {
D.assert(value > 0.0f);
if (_timeDilation == value)
return;
SchedulerBinding.instance?.resetEpoch();
_timeDilation = value;
}
}
static float _timeDilation = 1.0f;
}
public delegate void FrameCallback(TimeSpan timeStamp);
public delegate T TaskCallback<out T>();
public delegate bool SchedulingStrategy(int priority = 0, SchedulerBinding scheduler = null);
interface _TaskEntry : IComparable<_TaskEntry> {
int priority { get; }
string debugStack { get; }
void run();
}
class _TaskEntry<T> : _TaskEntry {
internal _TaskEntry(TaskCallback<T> task, int priority) {
this.task = task;
this.priority = priority;
D.assert(() => {
debugStack = StackTraceUtility.ExtractStackTrace();
return true;
});
completer = Completer.create();
}
public readonly TaskCallback<T> task;
public int priority { get; }
public string debugStack { get; private set; }
public Completer completer;
public void run() {
if (!foundation_.kReleaseMode) {
completer.complete(FutureOr.withValue(task()));
}
else {
completer.complete(FutureOr.withValue(task()));
}
}
public int CompareTo(_TaskEntry other) {
return -priority.CompareTo(other.priority);
}
}
class _FrameCallbackEntry {
internal _FrameCallbackEntry(FrameCallback callback, bool rescheduling = false) {
this.callback = callback;
D.assert(() => {
if (rescheduling) {
D.assert(() => {
if (debugCurrentCallbackStack == null) {
throw new UIWidgetsError(
"scheduleFrameCallback called with rescheduling true, but no callback is in scope.\n" +
"The \"rescheduling\" argument should only be set to true if the " +
"callback is being reregistered from within the callback itself, " +
"and only then if the callback itself is entirely synchronous. \n" +
"If this is the initial registration of the callback, or if the " +
"callback is asynchronous, then do not use the \"rescheduling\" " +
"argument.");
}
return true;
});
debugStack = debugCurrentCallbackStack;
}
else {
debugStack = StackTraceUtility.ExtractStackTrace();
}
return true;
});
}
public readonly FrameCallback callback;
public static string debugCurrentCallbackStack;
public string debugStack;
}
public enum SchedulerPhase {
idle,
transientCallbacks,
midFrameMicrotasks,
persistentCallbacks,
postFrameCallbacks,
}
public class SchedulerBinding : BindingBase {
protected override void initInstances() {
base.initInstances();
instance = this;
//SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
readInitialLifecycleStateFromNativeWindow();
if (!foundation_.kReleaseMode) {
int frameNumber = 0;
addTimingsCallback((List<FrameTiming> timings) => {
foreach (FrameTiming frameTiming in timings) {
frameNumber += 1;
_profileFramePostEvent(frameNumber, frameTiming);
}
});
}
}
readonly List<TimingsCallback> _timingsCallbacks = new List<TimingsCallback>();
public void addTimingsCallback(TimingsCallback callback) {
_timingsCallbacks.Add(callback);
if (_timingsCallbacks.Count == 1) {
D.assert(window.onReportTimings == null);
window.onReportTimings = _executeTimingsCallbacks;
}
D.assert(window.onReportTimings == _executeTimingsCallbacks);
}
public void removeTimingsCallback(TimingsCallback callback) {
D.assert(_timingsCallbacks.Contains(callback));
_timingsCallbacks.Remove(callback);
if (_timingsCallbacks.isEmpty()) {
window.onReportTimings = null;
}
}
void _executeTimingsCallbacks(List<FrameTiming> timings) {
List<TimingsCallback> clonedCallbacks =
new List<TimingsCallback>(_timingsCallbacks);
foreach (TimingsCallback callback in clonedCallbacks) {
try {
if (_timingsCallbacks.Contains(callback)) {
callback(timings);
}
}
catch (Exception ex) {
InformationCollector collector = null;
D.assert(() => {
collector = (StringBuilder sb) => {
sb.AppendLine("The TimingsCallback that gets executed was " + callback);
};
return true;
});
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: ex,
context: "while executing callbacks for FrameTiming",
informationCollector: collector
));
}
}
}
public static SchedulerBinding instance {
get { return (SchedulerBinding) Window.instance._binding; }
set { Window.instance._binding = value; }
}
public AppLifecycleState? lifecycleState => _lifecycleState;
AppLifecycleState? _lifecycleState;
protected void readInitialLifecycleStateFromNativeWindow() {
if (_lifecycleState == null) {
handleAppLifecycleStateChanged(_parseAppLifecycleMessage(window.initialLifecycleState));
}
}
protected virtual void handleAppLifecycleStateChanged(AppLifecycleState state) {
_lifecycleState = state;
switch (state) {
case AppLifecycleState.resumed:
case AppLifecycleState.inactive:
_setFramesEnabledState(true);
break;
case AppLifecycleState.paused:
case AppLifecycleState.detached:
_setFramesEnabledState(false);
break;
}
}
static AppLifecycleState _parseAppLifecycleMessage(string message) {
switch (message) {
case "AppLifecycleState.paused":
return AppLifecycleState.paused;
case "AppLifecycleState.resumed":
return AppLifecycleState.resumed;
case "AppLifecycleState.inactive":
return AppLifecycleState.inactive;
case "AppLifecycleState.detached":
return AppLifecycleState.detached;
}
throw new Exception("unknown AppLifecycleState: " + message);
}
public SchedulingStrategy schedulingStrategy = scheduler_.defaultSchedulingStrategy;
readonly PriorityQueue<_TaskEntry> _taskQueue = new PriorityQueue<_TaskEntry>();
public Future scheduleTask<T>(
TaskCallback<T> task,
Priority priority) {
bool isFirstTask = _taskQueue.isEmpty;
_TaskEntry<T> entry = new _TaskEntry<T>(
task,
priority.value
);
_taskQueue.enqueue(entry);
if (isFirstTask && !locked)
_ensureEventLoopCallback();
return entry.completer.future;
}
protected override void unlocked() {
base.unlocked();
if (_taskQueue.isNotEmpty)
_ensureEventLoopCallback();
}
bool _hasRequestedAnEventLoopCallback = false;
void _ensureEventLoopCallback() {
D.assert(!locked);
D.assert(_taskQueue.count != 0);
if (_hasRequestedAnEventLoopCallback)
return;
_hasRequestedAnEventLoopCallback = true;
Timer.run(_runTasks);
}
object _runTasks() {
_hasRequestedAnEventLoopCallback = false;
if (handleEventLoopCallback())
_ensureEventLoopCallback(); // runs next task when there's time
return null;
}
bool handleEventLoopCallback() {
if (_taskQueue.isEmpty || locked)
return false;
_TaskEntry entry = _taskQueue.first;
if (schedulingStrategy(priority: entry.priority, scheduler: this)) {
try {
_taskQueue.removeFirst();
entry.run();
}
catch (Exception exception) {
string callbackStack = null;
D.assert(() => {
callbackStack = entry.debugStack;
return true;
});
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: exception,
library: "scheduler library",
context: "during a task callback",
informationCollector: callbackStack == null
? (InformationCollector) null
: sb => {
sb.AppendLine("\nThis exception was thrown in the context of a scheduler callback. " +
"When the scheduler callback was _registered_ (as opposed to when the " +
"exception was thrown), this was the stack: " + callbackStack);
}
));
}
return _taskQueue.isNotEmpty;
}
return false;
}
int _nextFrameCallbackId = 0;
Dictionary<int, _FrameCallbackEntry> _transientCallbacks = new Dictionary<int, _FrameCallbackEntry>();
readonly HashSet<int> _removedIds = new HashSet<int>();
public int transientCallbackCount => _transientCallbacks.Count;
public int scheduleFrameCallback(FrameCallback callback, bool rescheduling = false) {
scheduleFrame();
_nextFrameCallbackId += 1;
_transientCallbacks[_nextFrameCallbackId] =
new _FrameCallbackEntry(callback, rescheduling: rescheduling);
return _nextFrameCallbackId;
}
public void cancelFrameCallbackWithId(int id) {
D.assert(id > 0);
_transientCallbacks.Remove(id);
_removedIds.Add(id);
}
readonly List<FrameCallback> _persistentCallbacks = new List<FrameCallback>();
public void addPersistentFrameCallback(FrameCallback callback) {
_persistentCallbacks.Add(callback);
}
readonly List<FrameCallback> _postFrameCallbacks = new List<FrameCallback>();
public void addPostFrameCallback(FrameCallback callback) {
_postFrameCallbacks.Add(callback);
}
Completer _nextFrameCompleter;
Future endOfFrame {
get {
if (_nextFrameCompleter == null) {
if (schedulerPhase == SchedulerPhase.idle)
scheduleFrame();
_nextFrameCompleter = Completer.create();
addPostFrameCallback((TimeSpan timeStamp) => {
_nextFrameCompleter.complete();
_nextFrameCompleter = null;
});
}
return _nextFrameCompleter.future;
}
}
public bool hasScheduledFrame => _hasScheduledFrame;
bool _hasScheduledFrame = false;
public SchedulerPhase schedulerPhase => _schedulerPhase;
SchedulerPhase _schedulerPhase = SchedulerPhase.idle;
public bool framesEnabled => _framesEnabled;
bool _framesEnabled = true;
void _setFramesEnabledState(bool enabled) {
if (_framesEnabled == enabled)
return;
_framesEnabled = enabled;
if (enabled)
scheduleFrame();
}
protected void ensureFrameCallbacksRegistered() {
window.onBeginFrame = window.onBeginFrame ?? _handleBeginFrame;
window.onDrawFrame = window.onDrawFrame ?? _handleDrawFrame;
}
public void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame();
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
public void scheduleFrame() {
if (_hasScheduledFrame || !_framesEnabled)
return;
D.assert(() => {
if (scheduler_.debugPrintScheduleFrameStacks) {
Debug.LogFormat("scheduleFrame() called. Current phase is {0}.", schedulerPhase);
}
return true;
});
ensureFrameCallbacksRegistered();
Window.instance.scheduleFrame();
_hasScheduledFrame = true;
}
public void scheduleForcedFrame() {
if (!framesEnabled)
return;
if (_hasScheduledFrame)
return;
D.assert(() => {
if (scheduler_.debugPrintScheduleFrameStacks) {
Debug.LogFormat("scheduleForcedFrame() called. Current phase is {0}.", schedulerPhase);
}
return true;
});
ensureFrameCallbacksRegistered();
Window.instance.scheduleFrame();
_hasScheduledFrame = true;
}
bool _warmUpFrame = false;
public void scheduleWarmUpFrame() {
if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle)
return;
_warmUpFrame = true;
Timeline.startSync("Warm-up frame");
bool hadScheduledFrame = _hasScheduledFrame;
// We use timers here to ensure that microtasks flush in between.
Timer.run(() => {
D.assert(_warmUpFrame);
handleBeginFrame(null);
return null;
});
Timer.run(() => {
D.assert(_warmUpFrame);
handleDrawFrame();
// We call resetEpoch after this frame so that, in the hot reload case,
// the very next frame pretends to have occurred immediately after this
// warm-up frame. The warm-up frame's timestamp will typically be far in
// the past (the time of the last real frame), so if we didn't reset the
// epoch we would see a sudden jump from the old time in the warm-up frame
// to the new time in the "real" frame. The biggest problem with this is
// that implicit animations end up being triggered at the old time and
// then skipping every frame and finishing in the new time.
resetEpoch();
_warmUpFrame = false;
if (hadScheduledFrame)
scheduleFrame();
return null;
});
// Lock events so touch events etc don't insert themselves until the
// scheduled frame has finished.
lockEvents(() => endOfFrame.then(v => {
Timeline.finishSync();
return FutureOr.nullValue;
}));
}
TimeSpan? _firstRawTimeStampInEpoch;
TimeSpan _epochStart = TimeSpan.Zero;
TimeSpan _lastRawTimeStamp = TimeSpan.Zero;
public void resetEpoch() {
_epochStart = _adjustForEpoch(_lastRawTimeStamp);
_firstRawTimeStampInEpoch = null;
}
TimeSpan _adjustForEpoch(TimeSpan rawTimeStamp) {
var rawDurationSinceEpoch = _firstRawTimeStampInEpoch == null
? TimeSpan.Zero
: rawTimeStamp - _firstRawTimeStampInEpoch.Value;
return new TimeSpan((long) (rawDurationSinceEpoch.Ticks / scheduler_.timeDilation) +
_epochStart.Ticks);
}
public TimeSpan currentFrameTimeStamp {
get {
D.assert(_currentFrameTimeStamp != null);
return _currentFrameTimeStamp.Value;
}
}
TimeSpan? _currentFrameTimeStamp;
public TimeSpan currentSystemFrameTimeStamp => _lastRawTimeStamp;
int _debugFrameNumber = 0;
string _debugBanner;
bool _ignoreNextEngineDrawFrame = false;
void _handleBeginFrame(TimeSpan rawTimeStamp) {
if (_warmUpFrame) {
D.assert(!_ignoreNextEngineDrawFrame);
_ignoreNextEngineDrawFrame = true;
return;
}
handleBeginFrame(rawTimeStamp);
}
void _handleDrawFrame() {
if (_ignoreNextEngineDrawFrame) {
_ignoreNextEngineDrawFrame = false;
return;
}
handleDrawFrame();
}
public void handleBeginFrame(TimeSpan? rawTimeStamp) {
Timeline.startSync("Frame");
_firstRawTimeStampInEpoch = _firstRawTimeStampInEpoch ?? rawTimeStamp;
_currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
if (rawTimeStamp != null)
_lastRawTimeStamp = rawTimeStamp.Value;
D.assert(() => {
_debugFrameNumber += 1;
if (scheduler_.debugPrintBeginFrameBanner || scheduler_.debugPrintEndFrameBanner) {
StringBuilder frameTimeStampDescription = new StringBuilder();
if (rawTimeStamp != null) {
_debugDescribeTimeStamp(_currentFrameTimeStamp.Value, frameTimeStampDescription);
}
else {
frameTimeStampDescription.Append("(warm-up frame)");
}
_debugBanner =
$"▄▄▄▄▄▄▄▄ Frame {_debugFrameNumber.ToString().PadRight(7)} ${frameTimeStampDescription.ToString().PadLeft(18)} ▄▄▄▄▄▄▄▄";
if (scheduler_.debugPrintBeginFrameBanner)
Debug.Log(_debugBanner);
}
return true;
});
D.assert(_schedulerPhase == SchedulerPhase.idle);
_hasScheduledFrame = false;
try {
Timeline.startSync("Animate");
_schedulerPhase = SchedulerPhase.transientCallbacks;
var callbacks = _transientCallbacks;
_transientCallbacks = new Dictionary<int, _FrameCallbackEntry>();
foreach (var entry in callbacks) {
if (!_removedIds.Contains(entry.Key)) {
_invokeFrameCallback(
entry.Value.callback, _currentFrameTimeStamp.Value, entry.Value.debugStack);
}
}
_removedIds.Clear();
}
finally {
_schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
}
public void handleDrawFrame() {
D.assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
Timeline.finishSync();
try {
_schedulerPhase = SchedulerPhase.persistentCallbacks;
foreach (FrameCallback callback in _persistentCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp.Value);
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
var localPostFrameCallbacks = new List<FrameCallback>(_postFrameCallbacks);
_postFrameCallbacks.Clear();
foreach (FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp.Value);
}
finally {
_schedulerPhase = SchedulerPhase.idle;
D.assert(() => {
if (scheduler_.debugPrintEndFrameBanner)
Debug.Log(new string('▀', _debugBanner.Length));
_debugBanner = null;
return true;
});
_currentFrameTimeStamp = null;
}
}
void _profileFramePostEvent(int frameNumber, FrameTiming frameTiming) {
developer_.postEvent("Flutter.Frame", new Hashtable {
{"number", frameNumber},
{"startTime", frameTiming.timestampInMicroseconds(FramePhase.buildStart)},
{"elapsed", (int) (frameTiming.totalSpan.TotalMilliseconds * 1000)},
{"build", (int) (frameTiming.buildDuration.TotalMilliseconds * 1000)},
{"raster", (int) (frameTiming.rasterDuration.TotalMilliseconds * 1000)},
});
}
static void _debugDescribeTimeStamp(TimeSpan timeStamp, StringBuilder buffer) {
if (timeStamp.TotalDays > 0)
buffer.AppendFormat("{0}d ", timeStamp.Days);
if (timeStamp.TotalHours > 0)
buffer.AppendFormat("{0}h ", timeStamp.Hours);
if (timeStamp.TotalMinutes > 0)
buffer.AppendFormat("{0}m ", timeStamp.Minutes);
if (timeStamp.TotalSeconds > 0)
buffer.AppendFormat("{0}s ", timeStamp.Seconds);
buffer.AppendFormat("{0}", timeStamp.Milliseconds);
int microseconds = (int) (timeStamp.Ticks % 10000 / 10);
if (microseconds > 0)
buffer.AppendFormat(".{0}", microseconds.ToString().PadLeft(3, '0'));
buffer.Append("ms");
}
void _invokeFrameCallback(FrameCallback callback, TimeSpan timeStamp, string callbackStack = null) {
D.assert(callback != null);
D.assert(_FrameCallbackEntry.debugCurrentCallbackStack == null);
D.assert(() => {
_FrameCallbackEntry.debugCurrentCallbackStack = callbackStack;
return true;
});
try {
callback(timeStamp);
}
catch (Exception ex) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: ex,
library: "scheduler library",
context: "during a scheduler callback",
informationCollector: callbackStack == null
? (InformationCollector) null
: information => {
information.AppendLine(
"\nThis exception was thrown in the context of a scheduler callback. " +
"When the scheduler callback was _registered_ (as opposed to when the " +
"exception was thrown), this was the stack:"
);
foreach (var line in UIWidgetsError.defaultStackFilter(
callbackStack.TrimEnd().Split('\n'))) {
information.AppendLine(line);
}
}
));
}
D.assert(() => {
_FrameCallbackEntry.debugCurrentCallbackStack = null;
return true;
});
}
}
public static partial class scheduler_ {
public static bool defaultSchedulingStrategy(int priority, SchedulerBinding scheduler) {
if (scheduler.transientCallbackCount > 0)
return priority >= Priority.animation.value;
return true;
}
}
}

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


fileFormatVersion: 2
guid: 0756240ed259436a82cdc6ee65831a4f
timeCreated: 1599458325

7
com.unity.uiwidgets/Runtime/scheduler2/debug.cs


namespace Unity.UIWidgets.scheduler2 {
public static partial class scheduler_ {
public static bool debugPrintBeginFrameBanner = false;
public static bool debugPrintEndFrameBanner = false;
public static bool debugPrintScheduleFrameStacks = false;
}
}

3
com.unity.uiwidgets/Runtime/scheduler2/debug.cs.meta


fileFormatVersion: 2
guid: 486e9bc3d81445fba548c7cddf682b4d
timeCreated: 1599458325

30
com.unity.uiwidgets/Runtime/scheduler2/priority.cs


using UnityEngine;
namespace Unity.UIWidgets.scheduler2 {
public class Priority {
Priority(int value) {
_value = value;
}
public int value => _value;
int _value;
public static readonly Priority idle = new Priority(0);
public static readonly Priority animation = new Priority(100000);
public static readonly Priority touch = new Priority(200000);
public static readonly int kMaxOffset = 10000;
public static Priority operator +(Priority it, int offset) {
if (Mathf.Abs(offset) > kMaxOffset) {
offset = kMaxOffset * (int) Mathf.Sign(offset);
}
return new Priority(it._value + offset);
}
public static Priority operator -(Priority it, int offset) => it + (-offset);
}
}

3
com.unity.uiwidgets/Runtime/scheduler2/priority.cs.meta


fileFormatVersion: 2
guid: 814da0eaecc042059b36143e73f60f48
timeCreated: 1599458325

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


using System;
using System.Text;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;
namespace Unity.UIWidgets.scheduler2 {
public delegate void TickerCallback(TimeSpan elapsed);
public interface TickerProvider {
Ticker createTicker(TickerCallback onTick);
}
public class Ticker : IDisposable {
public Ticker(TickerCallback onTick, string debugLabel = null) {
D.assert(() => {
_debugCreationStack = StackTraceUtility.ExtractStackTrace();
return true;
});
_onTick = onTick;
this.debugLabel = debugLabel;
}
TickerFuture _future;
public bool muted {
get => _muted;
set {
if (value == _muted)
return;
_muted = value;
if (value) {
unscheduleTick();
}
else if (shouldScheduleTick) {
scheduleTick();
}
}
}
bool _muted = false;
public bool isTicking {
get {
if (_future == null)
return false;
if (muted)
return false;
if (SchedulerBinding.instance.framesEnabled)
return true;
if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.idle)
return true;
return false;
}
}
public bool isActive {
get { return _future != null; }
}
TimeSpan? _startTime;
public TickerFuture start() {
D.assert(() => {
if (isActive) {
throw new UIWidgetsError(
"A ticker was started twice.\nA ticker that is already active cannot be started again without first stopping it.\n" +
"The affected ticker was: " + toString(debugIncludeStack: true));
}
return true;
});
D.assert(_startTime == null);
_future = new TickerFuture();
if (shouldScheduleTick) {
scheduleTick();
}
if (SchedulerBinding.instance.schedulerPhase > SchedulerPhase.idle &&
SchedulerBinding.instance.schedulerPhase < SchedulerPhase.postFrameCallbacks) {
_startTime = SchedulerBinding.instance.currentFrameTimeStamp;
}
return _future;
}
public void stop(bool canceled = false) {
if (!isActive)
return;
var localFuture = _future;
_future = null;
_startTime = null;
D.assert(!isActive);
unscheduleTick();
if (canceled) {
localFuture._cancel(this);
}
else {
localFuture._complete();
}
}
readonly TickerCallback _onTick;
int? _animationId;
protected bool scheduled {
get => _animationId != null;
}
protected bool shouldScheduleTick => !muted && isActive && !scheduled;
void _tick(TimeSpan timeStamp) {
D.assert(isTicking);
D.assert(scheduled);
_animationId = null;
_startTime = _startTime ?? timeStamp;
_onTick(timeStamp - _startTime.Value);
if (shouldScheduleTick)
scheduleTick(rescheduling: true);
}
protected void scheduleTick(bool rescheduling = false) {
D.assert(!scheduled);
D.assert(shouldScheduleTick);
_animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick, rescheduling: rescheduling);
}
protected void unscheduleTick() {
if (scheduled) {
SchedulerBinding.instance.cancelFrameCallbackWithId(_animationId.Value);
_animationId = null;
}
D.assert(!shouldScheduleTick);
}
public void absorbTicker(Ticker originalTicker) {
D.assert(!isActive);
D.assert(_future == null);
D.assert(_startTime == null);
D.assert(_animationId == null);
D.assert((originalTicker._future == null) == (originalTicker._startTime == null),
() => "Cannot absorb Ticker after it has been disposed.");
if (originalTicker._future != null) {
_future = originalTicker._future;
_startTime = originalTicker._startTime;
if (shouldScheduleTick) {
scheduleTick();
}
originalTicker._future = null;
originalTicker.unscheduleTick();
}
originalTicker.Dispose();
}
public virtual void Dispose() {
if (_future != null) {
var localFuture = _future;
_future = null;
D.assert(!isActive);
unscheduleTick();
localFuture._cancel(this);
}
D.assert(() => {
_startTime = TimeSpan.Zero;
return true;
});
}
public readonly string debugLabel;
internal string _debugCreationStack;
public override string ToString() {
return toString(debugIncludeStack: false);
}
public string toString(bool debugIncludeStack = false) {
var buffer = new StringBuilder();
buffer.Append(GetType() + "(");
D.assert(() => {
buffer.Append(debugLabel ?? "");
return true;
});
buffer.Append(')');
D.assert(() => {
if (debugIncludeStack) {
buffer.AppendLine();
buffer.AppendLine("The stack trace when the " + GetType() + " was actually created was: ");
foreach (var line in UIWidgetsError.defaultStackFilter(
_debugCreationStack.TrimEnd().Split('\n'))) {
buffer.AppendLine(line);
}
}
return true;
});
return buffer.ToString();
}
}
public class TickerFuture : Future {
internal TickerFuture() {
}
public static TickerFuture complete() {
var result = new TickerFuture();
result._complete();
return result;
}
readonly Completer _primaryCompleter = Completer.create();
Completer _secondaryCompleter;
bool? _completed; // null means unresolved, true means complete, false means canceled
internal void _complete() {
D.assert(_completed == null);
_completed = true;
_primaryCompleter.complete();
_secondaryCompleter?.complete();
}
internal void _cancel(Ticker ticker) {
D.assert(_completed == null);
_completed = false;
_secondaryCompleter?.completeError(new TickerCanceled(ticker));
}
public void whenCompleteOrCancel(VoidCallback callback) {
orCancel.then((value) => {
callback();
return FutureOr.nullValue;
}, ex => {
callback();
return FutureOr.nullValue;
});
}
public Future orCancel {
get {
if (_secondaryCompleter == null) {
_secondaryCompleter = Completer.create();
if (_completed != null) {
if (_completed.Value) {
_secondaryCompleter.complete();
}
else {
_secondaryCompleter.completeError(new TickerCanceled());
}
}
}
return _secondaryCompleter.future;
}
}
// public override Stream asStream() {
// return _primaryCompleter.future.asStream();
// }
public override Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null) {
return _primaryCompleter.future.catchError(onError, test: test);
}
public override Future then(Func<object, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
return _primaryCompleter.future.then(onValue, onError: onError);
}
public override Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null) {
return _primaryCompleter.future.timeout(timeLimit, onTimeout: onTimeout);
}
public override Future whenComplete(Func<object> action) {
return _primaryCompleter.future.whenComplete(action);
}
public override string ToString() =>
$"{Diagnostics.describeIdentity(this)}({(_completed == null ? "active" : (_completed.Value ? "complete" : "canceled"))})";
}
public class TickerCanceled : Exception {
public TickerCanceled(Ticker ticker = null) {
this.ticker = ticker;
}
public readonly Ticker ticker;
public override string ToString() {
if (ticker != null) {
return "This ticker was canceled: " + ticker;
}
return "The ticker was canceled before the \"orCancel\" property was first used.";
}
}
}

3
com.unity.uiwidgets/Runtime/scheduler2/ticker.cs.meta


fileFormatVersion: 2
guid: 9ee135f21ca64943a5f75a04a0e30cc3
timeCreated: 1599458326

48
engine/src/assets/asset_manager.cc


#include "asset_manager.h"
#include "flutter/fml/trace_event.h"
namespace uiwidgets {
AssetManager::AssetManager() = default;
AssetManager::~AssetManager() = default;
void AssetManager::PushFront(std::unique_ptr<AssetResolver> resolver) {
if (resolver == nullptr || !resolver->IsValid()) {
return;
}
resolvers_.push_front(std::move(resolver));
}
void AssetManager::PushBack(std::unique_ptr<AssetResolver> resolver) {
if (resolver == nullptr || !resolver->IsValid()) {
return;
}
resolvers_.push_back(std::move(resolver));
}
// |AssetResolver|
std::unique_ptr<fml::Mapping> AssetManager::GetAsMapping(
const std::string& asset_name) const {
if (asset_name.empty()) {
return std::unique_ptr<fml::Mapping>(nullptr);
}
TRACE_EVENT1("uiwidgets", "AssetManager::GetAsMapping", "name",
asset_name.c_str());
for (const auto& resolver : resolvers_) {
auto mapping = resolver->GetAsMapping(asset_name);
if (mapping != nullptr) {
return mapping;
}
}
FML_DLOG(WARNING) << "Could not find asset: " << asset_name;
return std::unique_ptr<fml::Mapping>(nullptr);
}
// |AssetResolver|
bool AssetManager::IsValid() const { return !resolvers_.empty(); }
} // namespace uiwidgets

35
engine/src/assets/asset_manager.h


#pragma once
#include <deque>
#include <memory>
#include <string>
#include "asset_resolver.h"
#include "flutter/fml/macros.h"
namespace uiwidgets {
class AssetManager final : public AssetResolver {
public:
AssetManager();
~AssetManager() override;
void PushFront(std::unique_ptr<AssetResolver> resolver);
void PushBack(std::unique_ptr<AssetResolver> resolver);
// |AssetResolver|
bool IsValid() const override;
// |AssetResolver|
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;
private:
std::deque<std::unique_ptr<AssetResolver>> resolvers_;
FML_DISALLOW_COPY_AND_ASSIGN(AssetManager);
};
} // namespace uiwidgets

26
engine/src/assets/asset_resolver.h


#pragma once
#include <string>
#include <vector>
#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
namespace uiwidgets {
class AssetResolver {
public:
AssetResolver() = default;
virtual ~AssetResolver() = default;
virtual bool IsValid() const = 0;
[[nodiscard]] virtual std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const = 0;
private:
FML_DISALLOW_COPY_AND_ASSIGN(AssetResolver);
};
} // namespace uiwidgets

41
engine/src/assets/directory_asset_bundle.cc


#include "directory_asset_bundle.h"
#include <utility>
#include "flutter/fml/file.h"
#include "flutter/fml/mapping.h"
namespace uiwidgets {
DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor)
: descriptor_(std::move(descriptor)) {
if (!fml::IsDirectory(descriptor_)) {
return;
}
is_valid_ = true;
}
DirectoryAssetBundle::~DirectoryAssetBundle() = default;
// |AssetResolver|
bool DirectoryAssetBundle::IsValid() const { return is_valid_; }
// |AssetResolver|
std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping(
const std::string& asset_name) const {
if (!is_valid_) {
FML_DLOG(WARNING) << "Asset bundle was not valid.";
return std::unique_ptr<fml::Mapping>(nullptr);
}
auto mapping = std::make_unique<fml::FileMapping>(fml::OpenFile(
descriptor_, asset_name.c_str(), false, fml::FilePermission::kRead));
if (!mapping->IsValid()) {
return std::unique_ptr<fml::Mapping>(nullptr);
}
return mapping;
}
} // namespace uiwidgets

30
engine/src/assets/directory_asset_bundle.h


#pragma once
#include "asset_resolver.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_counted.h"
#include "flutter/fml/unique_fd.h"
namespace uiwidgets {
class DirectoryAssetBundle : public AssetResolver {
public:
explicit DirectoryAssetBundle(fml::UniqueFD descriptor);
~DirectoryAssetBundle() override;
private:
const fml::UniqueFD descriptor_;
bool is_valid_ = false;
// |AssetResolver|
bool IsValid() const override;
// |AssetResolver|
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;
FML_DISALLOW_COPY_AND_ASSIGN(DirectoryAssetBundle);
};
} // namespace uiwidgets

14
engine/src/shell/gpu/gpu_surface_delegate.h


#pragma once
#include "flow/embedded_views.h"
namespace uiwidgets {
class GPUSurfaceDelegate {
public:
virtual ~GPUSurfaceDelegate() {}
virtual ExternalViewEmbedder* GetExternalViewEmbedder() = 0;
};
} // namespace uiwidgets

328
engine/src/shell/gpu/gpu_surface_gl.cc


#include "gpu_surface_gl.h"
#include "flutter/fml/base32.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/size.h"
#include "flutter/fml/trace_event.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContextOptions.h"
#include "shell/common/persistent_cache.h"
// These are common defines present on all OpenGL headers. However, we don't
// want to perform GL header reasolution on each platform we support. So just
// define these upfront. It is unlikely we will need more. But, if we do, we can
// add the same here.
#define GPU_GL_RGBA8 0x8058
#define GPU_GL_RGBA4 0x8056
#define GPU_GL_RGB565 0x8D62
namespace uiwidgets {
// Default maximum number of budgeted resources in the cache.
static const int kGrCacheMaxCount = 8192;
// Default maximum number of bytes of GPU memory of budgeted resources in the
// cache.
// The shell will dynamically increase or decrease this cache based on the
// viewport size, unless a user has specifically requested a size on the Skia
// system channel.
static const size_t kGrCacheMaxByteSize = 24 * (1 << 20);
GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
render_to_surface_(render_to_surface),
weak_factory_(this) {
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
}
GrContextOptions options;
if (PersistentCache::cache_sksl()) {
FML_LOG(INFO) << "Cache SkSL";
options.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kSkSL;
}
PersistentCache::MarkStrategySet();
options.fPersistentCache = PersistentCache::GetCacheForProcess();
options.fAvoidStencilBuffers = true;
// To get video playback on the widest range of devices, we limit Skia to
// ES2 shading language when the ES3 external image extension is missing.
options.fPreferExternalImagesOverES3 = true;
// TODO(goderbauer): remove option when skbug.com/7523 is fixed.
// A similar work-around is also used in shell/common/io_manager.cc.
options.fDisableGpuYUVConversion = true;
auto context = GrContext::MakeGL(delegate_->GetGLInterface(), options);
if (context == nullptr) {
FML_LOG(ERROR) << "Failed to setup Skia Gr context.";
return;
}
context_ = std::move(context);
context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
context_owner_ = true;
valid_ = true;
std::vector<PersistentCache::SkSLCache> caches =
PersistentCache::GetCacheForProcess()->LoadSkSLs();
int compiled_count = 0;
for (const auto& cache : caches) {
compiled_count += context_->precompileShader(*cache.first, *cache.second);
}
FML_LOG(INFO) << "Found " << caches.size() << " SkSL shaders; precompiled "
<< compiled_count;
delegate_->GLContextClearCurrent();
}
GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrContext> gr_context,
GPUSurfaceGLDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
context_(gr_context),
render_to_surface_(render_to_surface),
weak_factory_(this) {
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
}
delegate_->GLContextClearCurrent();
valid_ = true;
context_owner_ = false;
}
GPUSurfaceGL::~GPUSurfaceGL() {
if (!valid_) {
return;
}
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR) << "Could not make the context current to destroy the "
"GrContext resources.";
return;
}
onscreen_surface_ = nullptr;
if (context_owner_) {
context_->releaseResourcesAndAbandonContext();
}
context_ = nullptr;
delegate_->GLContextClearCurrent();
}
// |Surface|
bool GPUSurfaceGL::IsValid() { return valid_; }
static SkColorType FirstSupportedColorType(GrContext* context,
GrGLenum* format) {
#define RETURN_IF_RENDERABLE(x, y) \
if (context->colorTypeSupportedAsSurface((x))) { \
*format = (y); \
return (x); \
}
RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GPU_GL_RGBA8);
RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GPU_GL_RGBA4);
RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GPU_GL_RGB565);
return kUnknown_SkColorType;
}
static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context,
const SkISize& size, intptr_t fbo) {
GrGLenum format;
const SkColorType color_type = FirstSupportedColorType(context, &format);
GrGLFramebufferInfo framebuffer_info = {};
framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo);
framebuffer_info.fFormat = format;
GrBackendRenderTarget render_target(size.width(), // width
size.height(), // height
0, // sample count
0, // stencil bits (TODO)
framebuffer_info // framebuffer info
);
sk_sp<SkColorSpace> colorspace = SkColorSpace::MakeSRGB();
SkSurfaceProps surface_props(
SkSurfaceProps::InitType::kLegacyFontHost_InitType);
return SkSurface::MakeFromBackendRenderTarget(
context, // gr context
render_target, // render target
GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin, // origin
color_type, // color type
colorspace, // colorspace
&surface_props // surface properties
);
}
bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
if (onscreen_surface_ != nullptr &&
size == SkISize::Make(onscreen_surface_->width(),
onscreen_surface_->height())) {
// Surface size appears unchanged. So bail.
return true;
}
// We need to do some updates.
TRACE_EVENT0("uiwidgets", "UpdateSurfacesSize");
// Either way, we need to get rid of previous surface.
onscreen_surface_ = nullptr;
if (size.isEmpty()) {
FML_LOG(ERROR) << "Cannot create surfaces of empty size.";
return false;
}
sk_sp<SkSurface> onscreen_surface;
onscreen_surface =
WrapOnscreenSurface(context_.get(), // GL context
size, // root surface size
delegate_->GLContextFBO() // window FBO ID
);
if (onscreen_surface == nullptr) {
// If the onscreen surface could not be wrapped. There is absolutely no
// point in moving forward.
FML_LOG(ERROR) << "Could not wrap onscreen surface.";
return false;
}
onscreen_surface_ = std::move(onscreen_surface);
return true;
}
// |Surface|
SkMatrix GPUSurfaceGL::GetRootTransformation() const {
return delegate_->GLContextSurfaceTransformation();
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
if (delegate_ == nullptr) {
return nullptr;
}
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR)
<< "Could not make the context current to acquire the frame.";
return nullptr;
}
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface.
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
});
}
const auto root_surface_transformation = GetRootTransformation();
sk_sp<SkSurface> surface =
AcquireRenderSurface(size, root_surface_transformation);
if (surface == nullptr) {
return nullptr;
}
surface->getCanvas()->setMatrix(root_surface_transformation);
SurfaceFrame::SubmitCallback submit_callback =
[weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
SkCanvas* canvas) {
return weak ? weak->PresentSurface(canvas) : false;
};
return std::make_unique<SurfaceFrame>(
surface, delegate_->SurfaceSupportsReadback(), submit_callback);
}
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
return false;
}
{
TRACE_EVENT0("uiwidgets", "SkCanvas::Flush");
onscreen_surface_->getCanvas()->flush();
onscreen_surface_->getContext()->submit(true);
}
if (!delegate_->GLContextPresent()) {
return false;
}
if (delegate_->GLContextFBOResetAfterPresent()) {
auto current_size =
SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height());
// The FBO has changed, ask the delegate for the new FBO and do a surface
// re-wrap.
auto new_onscreen_surface =
WrapOnscreenSurface(context_.get(), // GL context
current_size, // root surface size
delegate_->GLContextFBO() // window FBO ID
);
if (!new_onscreen_surface) {
return false;
}
onscreen_surface_ = std::move(new_onscreen_surface);
}
return true;
}
sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(
const SkISize& untransformed_size,
const SkMatrix& root_surface_transformation) {
const auto transformed_rect = root_surface_transformation.mapRect(
SkRect::MakeWH(untransformed_size.width(), untransformed_size.height()));
const auto transformed_size =
SkISize::Make(transformed_rect.width(), transformed_rect.height());
if (!CreateOrUpdateSurfaces(transformed_size)) {
return nullptr;
}
return onscreen_surface_;
}
// |Surface|
GrContext* GPUSurfaceGL::GetContext() { return context_.get(); }
// |Surface|
ExternalViewEmbedder* GPUSurfaceGL::GetExternalViewEmbedder() {
return delegate_->GetExternalViewEmbedder();
}
// |Surface|
bool GPUSurfaceGL::MakeRenderContextCurrent() {
return delegate_->GLContextMakeCurrent();
}
} // namespace uiwidgets

68
engine/src/shell/gpu/gpu_surface_gl.h


#pragma once
#include <functional>
#include <memory>
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "include/gpu/GrContext.h"
#include "shell/common/surface.h"
#include "shell/gpu/gpu_surface_gl_delegate.h"
namespace uiwidgets {
class GPUSurfaceGL : public Surface {
public:
GPUSurfaceGL(GPUSurfaceGLDelegate* delegate, bool render_to_surface);
// Creates a new GL surface reusing an existing GrContext.
GPUSurfaceGL(sk_sp<GrContext> gr_context, GPUSurfaceGLDelegate* delegate,
bool render_to_surface);
// |Surface|
~GPUSurfaceGL() override;
// |Surface|
bool IsValid() override;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
// |Surface|
SkMatrix GetRootTransformation() const override;
// |Surface|
GrContext* GetContext() override;
// |Surface|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |Surface|
bool MakeRenderContextCurrent() override;
private:
GPUSurfaceGLDelegate* delegate_;
sk_sp<GrContext> context_;
sk_sp<SkSurface> onscreen_surface_;
bool context_owner_;
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface. This is a
// hack to make avoid allocating resources for the root surface when an
// external view embedder is present.
const bool render_to_surface_;
bool valid_ = false;
fml::WeakPtrFactory<GPUSurfaceGL> weak_factory_;
bool CreateOrUpdateSurfaces(const SkISize& size);
sk_sp<SkSurface> AcquireRenderSurface(
const SkISize& untransformed_size,
const SkMatrix& root_surface_transformation);
bool PresentSurface(SkCanvas* canvas);
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGL);
};
} // namespace uiwidgets

100
engine/src/shell/gpu/gpu_surface_gl_delegate.cc


#pragma once
#include "gpu_surface_gl_delegate.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
namespace uiwidgets {
GPUSurfaceGLDelegate::~GPUSurfaceGLDelegate() = default;
bool GPUSurfaceGLDelegate::GLContextFBOResetAfterPresent() const {
return false;
}
bool GPUSurfaceGLDelegate::SurfaceSupportsReadback() const { return true; }
SkMatrix GPUSurfaceGLDelegate::GLContextSurfaceTransformation() const {
SkMatrix matrix;
matrix.setIdentity();
return matrix;
}
GPUSurfaceGLDelegate::GLProcResolver GPUSurfaceGLDelegate::GetGLProcResolver()
const {
return nullptr;
}
static bool IsProcResolverOpenGLES(
GPUSurfaceGLDelegate::GLProcResolver proc_resolver) {
// Version string prefix that identifies an OpenGL ES implementation.
#define GPU_GL_VERSION 0x1F02
constexpr char kGLESVersionPrefix[] = "OpenGL ES";
using GLGetStringProc = const char* (*)(uint32_t);
GLGetStringProc gl_get_string =
reinterpret_cast<GLGetStringProc>(proc_resolver("glGetString"));
FML_CHECK(gl_get_string)
<< "The GL proc resolver could not resolve glGetString";
const char* gl_version_string = gl_get_string(GPU_GL_VERSION);
FML_CHECK(gl_version_string)
<< "The GL proc resolver's glGetString(GL_VERSION) failed";
return strncmp(gl_version_string, kGLESVersionPrefix,
strlen(kGLESVersionPrefix)) == 0;
}
static sk_sp<const GrGLInterface> CreateGLInterface(
GPUSurfaceGLDelegate::GLProcResolver proc_resolver) {
if (proc_resolver == nullptr) {
// If there is no custom proc resolver, ask Skia to guess the native
// interface. This often leads to interesting results on most platforms.
return GrGLMakeNativeInterface();
}
struct ProcResolverContext {
GPUSurfaceGLDelegate::GLProcResolver resolver;
};
ProcResolverContext context = {proc_resolver};
GrGLGetProc gl_get_proc = [](void* context,
const char gl_proc_name[]) -> GrGLFuncPtr {
auto proc_resolver_context =
reinterpret_cast<ProcResolverContext*>(context);
return reinterpret_cast<GrGLFuncPtr>(
proc_resolver_context->resolver(gl_proc_name));
};
// glGetString indicates an OpenGL ES interface.
if (IsProcResolverOpenGLES(proc_resolver)) {
return GrGLMakeAssembledGLESInterface(&context, gl_get_proc);
}
// Fallback to OpenGL.
if (auto interface = GrGLMakeAssembledGLInterface(&context, gl_get_proc)) {
return interface;
}
FML_LOG(ERROR) << "Could not create a valid GL interface.";
return nullptr;
}
sk_sp<const GrGLInterface> GPUSurfaceGLDelegate::GetGLInterface() const {
return CreateGLInterface(GetGLProcResolver());
}
sk_sp<const GrGLInterface>
GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface() {
return CreateGLInterface(nullptr);
}
ExternalViewEmbedder* GPUSurfaceGLDelegate::GetExternalViewEmbedder() {
return nullptr;
}
} // namespace uiwidgets

65
engine/src/shell/gpu/gpu_surface_gl_delegate.h


#pragma once
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "include/core/SkMatrix.h"
#include "include/gpu/gl/GrGLInterface.h"
#include "shell/gpu/gpu_surface_delegate.h"
namespace uiwidgets {
class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
public:
~GPUSurfaceGLDelegate() override;
// |GPUSurfaceDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
// Called to make the main GL context current on the current thread.
virtual bool GLContextMakeCurrent() = 0;
// Called to clear the current GL context on the thread. This may be called on
// either the GPU or IO threads.
virtual bool GLContextClearCurrent() = 0;
// Called to present the main GL surface. This is only called for the main GL
// context and not any of the contexts dedicated for IO.
virtual bool GLContextPresent() = 0;
// The ID of the main window bound framebuffer. Typically FBO0.
virtual intptr_t GLContextFBO() const = 0;
// The rendering subsystem assumes that the ID of the main window bound
// framebuffer remains constant throughout. If this assumption in incorrect,
// embedders are required to return true from this method. In such cases,
// GLContextFBO() will be called again to acquire the new FBO ID for rendering
// subsequent frames.
virtual bool GLContextFBOResetAfterPresent() const;
// Indicates whether or not the surface supports pixel readback as used in
// circumstances such as a BackdropFilter.
virtual bool SurfaceSupportsReadback() const;
// A transformation applied to the onscreen surface before the canvas is
// flushed.
virtual SkMatrix GLContextSurfaceTransformation() const;
sk_sp<const GrGLInterface> GetGLInterface() const;
// TODO(chinmaygarde): The presence of this method is to work around the fact
// that not all platforms can accept a custom GL proc table. Migrate all
// platforms to move GL proc resolution to the embedder and remove this
// method.
static sk_sp<const GrGLInterface> GetDefaultPlatformGLInterface();
using GLProcResolver =
std::function<void* /* proc name */ (const char* /* proc address */)>;
// Provide a custom GL proc resolver. If no such resolver is present, Skia
// will attempt to do GL proc address resolution on its own. Embedders that
// have specific opinions on GL API selection or need to add their own
// instrumentation to specific GL calls can specify custom GL functions
// here.
virtual GLProcResolver GetGLProcResolver() const;
};
} // namespace uiwidgets

90
engine/src/shell/gpu/gpu_surface_software.cc


#include "gpu_surface_software.h"
#include <memory>
#include "flutter/fml/logging.h"
namespace uiwidgets {
GPUSurfaceSoftware::GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
render_to_surface_(render_to_surface),
weak_factory_(this) {}
GPUSurfaceSoftware::~GPUSurfaceSoftware() = default;
// |Surface|
bool GPUSurfaceSoftware::IsValid() { return delegate_ != nullptr; }
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceSoftware::AcquireFrame(
const SkISize& logical_size) {
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface.
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
});
}
if (!IsValid()) {
return nullptr;
}
const auto size = SkISize::Make(logical_size.width(), logical_size.height());
sk_sp<SkSurface> backing_store = delegate_->AcquireBackingStore(size);
if (backing_store == nullptr) {
return nullptr;
}
if (size != SkISize::Make(backing_store->width(), backing_store->height())) {
return nullptr;
}
// If the surface has been scaled, we need to apply the inverse scaling to the
// underlying canvas so that coordinates are mapped to the same spot
// irrespective of surface scaling.
SkCanvas* canvas = backing_store->getCanvas();
canvas->resetMatrix();
SurfaceFrame::SubmitCallback on_submit =
[self = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
SkCanvas* canvas) -> bool {
// If the surface itself went away, there is nothing more to do.
if (!self || !self->IsValid() || canvas == nullptr) {
return false;
}
canvas->flush();
return self->delegate_->PresentBackingStore(surface_frame.SkiaSurface());
};
return std::make_unique<SurfaceFrame>(backing_store, true, on_submit);
}
// |Surface|
SkMatrix GPUSurfaceSoftware::GetRootTransformation() const {
// This backend does not currently support root surface transformations. Just
// return identity.
SkMatrix matrix;
matrix.reset();
return matrix;
}
// |Surface|
GrContext* GPUSurfaceSoftware::GetContext() {
// There is no GrContext associated with a software surface.
return nullptr;
}
// |Surface|
ExternalViewEmbedder* GPUSurfaceSoftware::GetExternalViewEmbedder() {
return delegate_->GetExternalViewEmbedder();
}
} // namespace uiwidgets

44
engine/src/shell/gpu/gpu_surface_software.h


#pragma once
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "shell/common/surface.h"
#include "shell/gpu/gpu_surface_software_delegate.h"
namespace uiwidgets {
class GPUSurfaceSoftware : public Surface {
public:
GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate,
bool render_to_surface);
~GPUSurfaceSoftware() override;
// |Surface|
bool IsValid() override;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
// |Surface|
SkMatrix GetRootTransformation() const override;
// |Surface|
GrContext* GetContext() override;
// |Surface|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
private:
GPUSurfaceSoftwareDelegate* delegate_;
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface. This is a
// hack to make avoid allocating resources for the root surface when an
// external view embedder is present.
const bool render_to_surface_;
fml::WeakPtrFactory<GPUSurfaceSoftware> weak_factory_;
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceSoftware);
};
} // namespace uiwidgets

11
engine/src/shell/gpu/gpu_surface_software_delegate.cc


#include "gpu_surface_software_delegate.h"
namespace uiwidgets {
GPUSurfaceSoftwareDelegate::~GPUSurfaceSoftwareDelegate() = default;
ExternalViewEmbedder* GPUSurfaceSoftwareDelegate::GetExternalViewEmbedder() {
return nullptr;
}
} // namespace uiwidgets

22
engine/src/shell/gpu/gpu_surface_software_delegate.h


#pragma once
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "include/core/SkSurface.h"
#include "shell/gpu/gpu_surface_delegate.h"
namespace uiwidgets {
class GPUSurfaceSoftwareDelegate : public GPUSurfaceDelegate {
public:
~GPUSurfaceSoftwareDelegate() override;
// |GPUSurfaceDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
virtual sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) = 0;
virtual bool PresentBackingStore(sk_sp<SkSurface> backing_store) = 0;
};
} // namespace uiwidgets

1001
engine/src/shell/platform/embedder/embedder.cc
文件差异内容过多而无法显示
查看文件

459
engine/src/shell/platform/embedder/embedder.h


#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef enum {
kSuccess = 0,
kInvalidLibraryVersion,
kInvalidArguments,
kInternalInconsistency,
} UIWidgetsEngineResult;
typedef enum {
kOpenGL,
kSoftware,
} UIWidgetsRendererType;
typedef enum {
kUIWidgetsAccessibilityFeatureAccessibleNavigation = 1 << 0,
kUIWidgetsAccessibilityFeatureInvertColors = 1 << 1,
kUIWidgetsAccessibilityFeatureDisableAnimations = 1 << 2,
kUIWidgetsAccessibilityFeatureBoldText = 1 << 3,
kUIWidgetsAccessibilityFeatureReduceMotion = 1 << 4,
} UIWidgetsAccessibilityFeature;
typedef enum {
kUIWidgetsTextDirectionUnknown = 0,
kUIWidgetsTextDirectionRTL = 1,
kUIWidgetsTextDirectionLTR = 2,
} UIWidgetsTextDirection;
typedef struct _UIWidgetsEngine* UIWidgetsEngine;
typedef struct {
float scaleX;
float skewX;
float transX;
float skewY;
float scaleY;
float transY;
float pers0;
float pers1;
float pers2;
} UIWidgetsTransformation;
typedef void (*VoidCallback)(void* /* user data */);
typedef enum {
kUIWidgetsOpenGLTargetTypeTexture,
kUIWidgetsOpenGLTargetTypeFramebuffer,
} UIWidgetsOpenGLTargetType;
typedef struct {
uint32_t target;
uint32_t name;
uint32_t format;
void* user_data;
VoidCallback destruction_callback;
size_t width;
size_t height;
} UIWidgetsOpenGLTexture;
typedef struct {
uint32_t target;
uint32_t name;
void* user_data;
VoidCallback destruction_callback;
} UIWidgetsOpenGLFramebuffer;
typedef bool (*BoolCallback)(void* /* user data */);
typedef UIWidgetsTransformation (*TransformationCallback)(
void* /* user data */);
typedef uint32_t (*UIntCallback)(void* /* user data */);
typedef bool (*SoftwareSurfacePresentCallback)(void* /* user data */,
const void* /* allocation */,
size_t /* row bytes */,
size_t /* height */);
typedef void* (*ProcResolver)(void* /* user data */, const char* /* name */);
typedef bool (*TextureFrameCallback)(void* /* user data */,
int64_t /* texture identifier */,
size_t /* width */, size_t /* height */,
UIWidgetsOpenGLTexture* /* texture out */);
typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */);
typedef struct {
size_t struct_size;
BoolCallback make_current;
BoolCallback clear_current;
BoolCallback present;
UIntCallback fbo_callback;
BoolCallback make_resource_current;
bool fbo_reset_after_present;
TransformationCallback surface_transformation;
ProcResolver gl_proc_resolver;
TextureFrameCallback gl_external_texture_frame_callback;
} UIWidgetsOpenGLRendererConfig;
typedef struct {
size_t struct_size;
SoftwareSurfacePresentCallback surface_present_callback;
} UIWidgetsSoftwareRendererConfig;
typedef struct {
UIWidgetsRendererType type;
union {
UIWidgetsOpenGLRendererConfig open_gl;
UIWidgetsSoftwareRendererConfig software;
};
} UIWidgetsRendererConfig;
typedef struct {
size_t struct_size;
size_t width;
size_t height;
float pixel_ratio;
} UIWidgetsWindowMetricsEvent;
typedef enum {
kCancel,
kUp,
kDown,
kMove,
kAdd,
kRemove,
kHover,
} UIWidgetsPointerPhase;
typedef enum {
kUIWidgetsPointerDeviceKindMouse = 1,
kUIWidgetsPointerDeviceKindTouch,
} UIWidgetsPointerDeviceKind;
typedef enum {
kUIWidgetsPointerButtonMousePrimary = 1 << 0,
kUIWidgetsPointerButtonMouseSecondary = 1 << 1,
kUIWidgetsPointerButtonMouseMiddle = 1 << 2,
kUIWidgetsPointerButtonMouseBack = 1 << 3,
kUIWidgetsPointerButtonMouseForward = 1 << 4,
} UIWidgetsPointerMouseButtons;
typedef enum {
kUIWidgetsPointerSignalKindNone,
kUIWidgetsPointerSignalKindScroll,
} UIWidgetsPointerSignalKind;
typedef struct {
size_t struct_size;
UIWidgetsPointerPhase phase;
size_t timestamp;
float x;
float y;
int32_t device;
UIWidgetsPointerSignalKind signal_kind;
float scroll_delta_x;
float scroll_delta_y;
UIWidgetsPointerDeviceKind device_kind;
int64_t buttons;
} UIWidgetsPointerEvent;
struct _UIWidgetsPlatformMessageResponseHandle;
typedef struct _UIWidgetsPlatformMessageResponseHandle
UIWidgetsPlatformMessageResponseHandle;
typedef struct {
size_t struct_size;
const char* channel;
const uint8_t* message;
size_t message_size;
const UIWidgetsPlatformMessageResponseHandle* response_handle;
} UIWidgetsPlatformMessage;
typedef void (*UIWidgetsPlatformMessageCallback)(
const UIWidgetsPlatformMessage* /* message*/, void* /* user data */);
typedef void (*UIWidgetsDataCallback)(const uint8_t* /* data */,
size_t /* size */, void* /* user data */);
typedef struct {
float left;
float top;
float right;
float bottom;
} UIWidgetsRect;
typedef struct {
float x;
float y;
} UIWidgetsPoint;
typedef struct {
float width;
float height;
} UIWidgetsSize;
typedef struct {
UIWidgetsRect rect;
UIWidgetsSize upper_left_corner_radius;
UIWidgetsSize upper_right_corner_radius;
UIWidgetsSize lower_right_corner_radius;
UIWidgetsSize lower_left_corner_radius;
} UIWidgetsRoundedRect;
typedef int64_t UIWidgetsPlatformViewIdentifier;
typedef struct _UIWidgetsTaskRunner* UIWidgetsTaskRunner;
typedef struct {
UIWidgetsTaskRunner runner;
uint64_t task;
} UIWidgetsTask;
typedef void (*UIWidgetsTaskRunnerPostTaskCallback)(
UIWidgetsTask /* task */, uint64_t /* target time nanos */,
void* /* user data */);
typedef struct {
size_t struct_size;
void* user_data;
BoolCallback runs_task_on_current_thread_callback;
UIWidgetsTaskRunnerPostTaskCallback post_task_callback;
size_t identifier;
} UIWidgetsTaskRunnerDescription;
typedef struct {
size_t struct_size;
const UIWidgetsTaskRunnerDescription* platform_task_runner;
const UIWidgetsTaskRunnerDescription* ui_task_runner;
const UIWidgetsTaskRunnerDescription* render_task_runner;
} UIWidgetsCustomTaskRunners;
typedef struct {
UIWidgetsOpenGLTargetType type;
union {
UIWidgetsOpenGLTexture texture;
UIWidgetsOpenGLFramebuffer framebuffer;
};
} UIWidgetsOpenGLBackingStore;
typedef struct {
const void* allocation;
size_t row_bytes;
size_t height;
void* user_data;
VoidCallback destruction_callback;
} UIWidgetsSoftwareBackingStore;
typedef enum {
kUIWidgetsPlatformViewMutationTypeOpacity,
kUIWidgetsPlatformViewMutationTypeClipRect,
kUIWidgetsPlatformViewMutationTypeClipRoundedRect,
kUIWidgetsPlatformViewMutationTypeTransformation,
} UIWidgetsPlatformViewMutationType;
typedef struct {
UIWidgetsPlatformViewMutationType type;
union {
double opacity;
UIWidgetsRect clip_rect;
UIWidgetsRoundedRect clip_rounded_rect;
UIWidgetsTransformation transformation;
};
} UIWidgetsPlatformViewMutation;
typedef struct {
size_t struct_size;
UIWidgetsPlatformViewIdentifier identifier;
size_t mutations_count;
const UIWidgetsPlatformViewMutation** mutations;
} UIWidgetsPlatformView;
typedef enum {
kUIWidgetsBackingStoreTypeOpenGL,
kUIWidgetsBackingStoreTypeSoftware,
} UIWidgetsBackingStoreType;
typedef struct {
size_t struct_size;
void* user_data;
UIWidgetsBackingStoreType type;
bool did_update;
union {
UIWidgetsOpenGLBackingStore open_gl;
UIWidgetsSoftwareBackingStore software;
};
} UIWidgetsBackingStore;
typedef struct {
size_t struct_size;
UIWidgetsSize size;
} UIWidgetsBackingStoreConfig;
typedef enum {
kUIWidgetsLayerContentTypeBackingStore,
kUIWidgetsLayerContentTypePlatformView,
} UIWidgetsLayerContentType;
typedef struct {
size_t struct_size;
UIWidgetsLayerContentType type;
union {
const UIWidgetsBackingStore* backing_store;
const UIWidgetsPlatformView* platform_view;
};
UIWidgetsPoint offset;
UIWidgetsSize size;
} UIWidgetsLayer;
typedef bool (*UIWidgetsBackingStoreCreateCallback)(
const UIWidgetsBackingStoreConfig* config,
UIWidgetsBackingStore* backing_store_out, void* user_data);
typedef bool (*UIWidgetsBackingStoreCollectCallback)(
const UIWidgetsBackingStore* renderer, void* user_data);
typedef bool (*UIWidgetsLayersPresentCallback)(const UIWidgetsLayer** layers,
size_t layers_count,
void* user_data);
typedef struct {
size_t struct_size;
void* user_data;
UIWidgetsBackingStoreCreateCallback create_backing_store_callback;
UIWidgetsBackingStoreCollectCallback collect_backing_store_callback;
UIWidgetsLayersPresentCallback present_layers_callback;
} UIWidgetsCompositor;
typedef struct {
size_t struct_size;
const char* language_code;
const char* country_code;
const char* script_code;
const char* variant_code;
} UIWidgetsLocale;
typedef enum {
kUIWidgetsNativeThreadTypePlatform,
kUIWidgetsNativeThreadTypeRender,
kUIWidgetsNativeThreadTypeUI,
kUIWidgetsNativeThreadTypeWorker,
} UIWidgetsNativeThreadType;
typedef void (*UIWidgetsNativeThreadCallback)(UIWidgetsNativeThreadType type,
void* user_data);
typedef void (*UIWidgetsTaskObserverAdd)(intptr_t key, void* callback,
void* user_data);
typedef void (*UIWidgetsTaskObserverRemove)(intptr_t key, void* user_data);
typedef void (*UIWidgetsMonoEntrypointCallback)(void* user_data);
typedef struct {
size_t struct_size;
const char* assets_path;
const char* icu_data_path;
int command_line_argc;
const char* const* command_line_argv;
UIWidgetsPlatformMessageCallback platform_message_callback;
VoidCallback root_isolate_create_callback;
const char* persistent_cache_path;
bool is_persistent_cache_read_only;
VsyncCallback vsync_callback;
const UIWidgetsCustomTaskRunners* custom_task_runners;
const UIWidgetsCompositor* compositor;
UIWidgetsTaskObserverAdd task_observer_add;
UIWidgetsTaskObserverRemove task_observer_remove;
UIWidgetsMonoEntrypointCallback custom_mono_entrypoint;
UIWidgetsWindowMetricsEvent initial_window_metrics;
} UIWidgetsProjectArgs;
UIWidgetsEngineResult UIWidgetsEngineRun(const UIWidgetsRendererConfig* config,
const UIWidgetsProjectArgs* args,
void* user_data,
UIWidgetsEngine* engine_out);
UIWidgetsEngineResult UIWidgetsEngineShutdown(UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEngineInitialize(
const UIWidgetsRendererConfig* config, const UIWidgetsProjectArgs* args,
void* user_data, UIWidgetsEngine* engine_out);
UIWidgetsEngineResult UIWidgetsEngineDeinitialize(UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEngineRunInitialized(UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEngineSendWindowMetricsEvent(
UIWidgetsEngine engine, const UIWidgetsWindowMetricsEvent* event);
UIWidgetsEngineResult UIWidgetsEngineSendPointerEvent(
UIWidgetsEngine engine, const UIWidgetsPointerEvent* events,
size_t events_count);
UIWidgetsEngineResult UIWidgetsEngineSendPlatformMessage(
UIWidgetsEngine engine, const UIWidgetsPlatformMessage* message);
UIWidgetsEngineResult UIWidgetsPlatformMessageCreateResponseHandle(
UIWidgetsEngine engine, UIWidgetsDataCallback data_callback,
void* user_data, UIWidgetsPlatformMessageResponseHandle** response_out);
UIWidgetsEngineResult UIWidgetsPlatformMessageReleaseResponseHandle(
UIWidgetsEngine engine, UIWidgetsPlatformMessageResponseHandle* response);
UIWidgetsEngineResult UIWidgetsEngineSendPlatformMessageResponse(
UIWidgetsEngine engine,
const UIWidgetsPlatformMessageResponseHandle* handle, const uint8_t* data,
size_t data_length);
UIWidgetsEngineResult __UIWidgetsEngineFlushPendingTasksNow();
UIWidgetsEngineResult UIWidgetsEngineRegisterExternalTexture(
UIWidgetsEngine engine, int64_t texture_identifier);
UIWidgetsEngineResult UIWidgetsEngineUnregisterExternalTexture(
UIWidgetsEngine engine, int64_t texture_identifier);
UIWidgetsEngineResult UIWidgetsEngineMarkExternalTextureFrameAvailable(
UIWidgetsEngine engine, int64_t texture_identifier);
UIWidgetsEngineResult UIWidgetsEngineUpdateAccessibilityFeatures(
UIWidgetsEngine engine, UIWidgetsAccessibilityFeature features);
UIWidgetsEngineResult UIWidgetsEngineOnVsync(UIWidgetsEngine engine,
intptr_t baton,
uint64_t frame_start_time_nanos,
uint64_t frame_target_time_nanos);
UIWidgetsEngineResult UIWidgetsEngineReloadSystemFonts(UIWidgetsEngine engine);
void UIWidgetsEngineTraceEventDurationBegin(const char* name);
void UIWidgetsEngineTraceEventDurationEnd(const char* name);
void UIWidgetsEngineTraceEventInstant(const char* name);
UIWidgetsEngineResult UIWidgetsEnginePostRenderThreadTask(
UIWidgetsEngine engine, VoidCallback callback, void* callback_data);
uint64_t UIWidgetsEngineGetCurrentTime();
UIWidgetsEngineResult UIWidgetsEngineRunTask(UIWidgetsEngine engine,
const UIWidgetsTask* task);
UIWidgetsEngineResult UIWidgetsEngineUpdateLocales(
UIWidgetsEngine engine, const UIWidgetsLocale** locales,
size_t locales_count);
UIWidgetsEngineResult UIWidgetsEngineNotifyLowMemoryWarning(
UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEnginePostCallbackOnAllNativeThreads(
UIWidgetsEngine engine, UIWidgetsNativeThreadCallback callback,
void* user_data);
#if defined(__cplusplus)
} // extern "C"
#endif

252
engine/src/shell/platform/embedder/embedder_engine.cc


#include "embedder_engine.h"
#include <utility>
#include "flutter/fml/make_copyable.h"
#include "shell/platform/embedder/vsync_waiter_embedder.h"
namespace uiwidgets {
struct ShellArgs {
WindowData window_data;
Settings settings;
Shell::CreateCallback<PlatformView> on_create_platform_view;
Shell::CreateCallback<Rasterizer> on_create_rasterizer;
ShellArgs(const WindowData& p_window_data, const Settings& p_settings,
Shell::CreateCallback<PlatformView> p_on_create_platform_view,
Shell::CreateCallback<Rasterizer> p_on_create_rasterizer)
: window_data(p_window_data),
settings(p_settings),
on_create_platform_view(std::move(p_on_create_platform_view)),
on_create_rasterizer(std::move(p_on_create_rasterizer)) {}
};
EmbedderEngine::EmbedderEngine(
std::unique_ptr<EmbedderThreadHost> thread_host,
const TaskRunners& task_runners, const WindowData& window_data,
const Settings& settings, RunConfiguration run_configuration,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback)
: thread_host_(std::move(thread_host)),
task_runners_(task_runners),
run_configuration_(std::move(run_configuration)),
shell_args_(std::make_unique<ShellArgs>(
window_data, settings, std::move(on_create_platform_view),
std::move(on_create_rasterizer))),
external_texture_callback_(std::move(external_texture_callback)) {}
EmbedderEngine::~EmbedderEngine() = default;
bool EmbedderEngine::LaunchShell() {
if (!shell_args_) {
FML_DLOG(ERROR) << "Invalid shell arguments.";
return false;
}
if (shell_) {
FML_DLOG(ERROR) << "Shell already initialized";
}
shell_ = Shell::Create(
task_runners_, shell_args_->window_data, shell_args_->settings,
shell_args_->on_create_platform_view, shell_args_->on_create_rasterizer);
// Reset the args no matter what. They will never be used to initialize a
// shell again.
shell_args_.reset();
return IsValid();
}
bool EmbedderEngine::CollectShell() {
shell_.reset();
return IsValid();
}
bool EmbedderEngine::RunRootIsolate() {
if (!IsValid() || !run_configuration_.IsValid()) {
return false;
}
shell_->RunEngine(std::move(run_configuration_));
return true;
}
bool EmbedderEngine::IsValid() const { return static_cast<bool>(shell_); }
const TaskRunners& EmbedderEngine::GetTaskRunners() const {
return task_runners_;
}
bool EmbedderEngine::NotifyCreated() {
if (!IsValid()) {
return false;
}
shell_->GetPlatformView()->NotifyCreated();
return true;
}
bool EmbedderEngine::NotifyDestroyed() {
if (!IsValid()) {
return false;
}
shell_->GetPlatformView()->NotifyDestroyed();
return true;
}
bool EmbedderEngine::SetViewportMetrics(ViewportMetrics metrics) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->SetViewportMetrics(std::move(metrics));
return true;
}
bool EmbedderEngine::DispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) {
if (!IsValid() || !packet) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->DispatchPointerDataPacket(std::move(packet));
return true;
}
bool EmbedderEngine::SendPlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (!IsValid() || !message) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->DispatchPlatformMessage(message);
return true;
}
bool EmbedderEngine::RegisterTexture(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->RegisterTexture(
std::make_unique<EmbedderExternalTextureGL>(texture,
external_texture_callback_));
return true;
}
bool EmbedderEngine::UnregisterTexture(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->UnregisterTexture(texture);
return true;
}
bool EmbedderEngine::MarkTextureFrameAvailable(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->MarkTextureFrameAvailable(texture);
return true;
}
bool EmbedderEngine::SetAccessibilityFeatures(int32_t flags) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->SetAccessibilityFeatures(flags);
return true;
}
bool EmbedderEngine::OnVsyncEvent(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
if (!IsValid()) {
return false;
}
return VsyncWaiterEmbedder::OnEmbedderVsync(baton, frame_start_time,
frame_target_time);
}
bool EmbedderEngine::ReloadSystemFonts() {
if (!IsValid()) {
return false;
}
return shell_->ReloadSystemFonts();
}
bool EmbedderEngine::PostRenderThreadTask(const fml::closure& task) {
if (!IsValid()) {
return false;
}
shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(task);
return true;
}
bool EmbedderEngine::RunTask(const UIWidgetsTask* task) {
// The shell doesn't need to be running or valid for access to the thread
// host. This is why there is no `IsValid` check here. This allows embedders
// to perform custom task runner interop before the shell is running.
if (task == nullptr) {
return false;
}
return thread_host_->PostTask(reinterpret_cast<int64_t>(task->runner),
task->task);
}
bool EmbedderEngine::PostTaskOnEngineManagedNativeThreads(
std::function<void(UIWidgetsNativeThreadType)> closure) const {
if (!IsValid() || closure == nullptr) {
return false;
}
const auto trampoline = [closure](UIWidgetsNativeThreadType type,
fml::RefPtr<fml::TaskRunner> runner) {
runner->PostTask([closure, type] { closure(type); });
};
// Post the task to all thread host threads.
const auto& task_runners = shell_->GetTaskRunners();
trampoline(kUIWidgetsNativeThreadTypeRender,
task_runners.GetRasterTaskRunner());
trampoline(kUIWidgetsNativeThreadTypeWorker, task_runners.GetIOTaskRunner());
trampoline(kUIWidgetsNativeThreadTypeUI, task_runners.GetUITaskRunner());
trampoline(kUIWidgetsNativeThreadTypePlatform,
task_runners.GetPlatformTaskRunner());
// Post the task to all worker threads.
auto engine = shell_->GetEngine();
engine->GetConcurrentMessageLoop()->PostTaskToAllWorkers(
[closure]() { closure(kUIWidgetsNativeThreadTypeWorker); });
return true;
}
Shell& EmbedderEngine::GetShell() {
FML_DCHECK(shell_);
return *shell_.get();
}
} // namespace uiwidgets

84
engine/src/shell/platform/embedder/embedder_engine.h


#pragma once
#include <memory>
#include <unordered_map>
#include "flutter/fml/macros.h"
#include "shell/common/shell.h"
#include "shell/common/thread_host.h"
#include "shell/platform/embedder/embedder.h"
#include "shell/platform/embedder/embedder_engine.h"
#include "shell/platform/embedder/embedder_external_texture_gl.h"
#include "shell/platform/embedder/embedder_thread_host.h"
namespace uiwidgets {
struct ShellArgs;
class EmbedderEngine {
public:
EmbedderEngine(std::unique_ptr<EmbedderThreadHost> thread_host,
const TaskRunners& task_runners, const WindowData& window_data, const Settings& settings,
RunConfiguration run_configuration,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback);
~EmbedderEngine();
bool LaunchShell();
bool CollectShell();
const TaskRunners& GetTaskRunners() const;
bool NotifyCreated();
bool NotifyDestroyed();
bool RunRootIsolate();
bool IsValid() const;
bool SetViewportMetrics(ViewportMetrics metrics);
bool DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet);
bool SendPlatformMessage(fml::RefPtr<PlatformMessage> message);
bool RegisterTexture(int64_t texture);
bool UnregisterTexture(int64_t texture);
bool MarkTextureFrameAvailable(int64_t texture);
bool SetAccessibilityFeatures(int32_t flags);
bool OnVsyncEvent(intptr_t baton, fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
bool ReloadSystemFonts();
bool PostRenderThreadTask(const fml::closure& task);
bool RunTask(const UIWidgetsTask* task);
bool PostTaskOnEngineManagedNativeThreads(
std::function<void(UIWidgetsNativeThreadType)> closure) const;
Shell& GetShell();
private:
const std::unique_ptr<EmbedderThreadHost> thread_host_;
TaskRunners task_runners_;
RunConfiguration run_configuration_;
std::unique_ptr<ShellArgs> shell_args_;
std::unique_ptr<Shell> shell_;
const EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderEngine);
};
} // namespace uiwidgets

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存