浏览代码

add image codec.

/siyaoH-1.17-PlatformMessage
Kevin Gu 4 年前
当前提交
dddde002
共有 31 个文件被更改,包括 1062 次插入213 次删除
  1. 47
      com.unity.uiwidgets/Runtime/async2/future.cs
  2. 3
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
  3. 8
      com.unity.uiwidgets/Runtime/services/asset_bundle.cs
  4. 44
      com.unity.uiwidgets/Runtime/ui2/compositing.cs
  5. 17
      com.unity.uiwidgets/Runtime/ui2/hooks.cs
  6. 50
      com.unity.uiwidgets/Runtime/ui2/isolate.cs
  7. 51
      com.unity.uiwidgets/Runtime/ui2/native_bindings.cs
  8. 313
      com.unity.uiwidgets/Runtime/ui2/painting.cs
  9. 4
      com.unity.uiwidgets/Runtime/ui2/window.cs
  10. 8
      engine/Build.bee.cs
  11. 14
      engine/src/flow/skia_gpu_object.cc
  12. 2
      engine/src/flow/skia_gpu_object.h
  13. 12
      engine/src/lib/ui/compositing/scene_builder.cc
  14. 6
      engine/src/lib/ui/painting/engine_layer.cc
  15. 15
      engine/src/lib/ui/painting/image.cc
  16. 2
      engine/src/lib/ui/painting/image.h
  17. 377
      engine/src/lib/ui/painting/image_decoder.cc
  18. 55
      engine/src/lib/ui/painting/image_decoder.h
  19. 42
      engine/src/lib/ui/painting/image_encoding.cc
  20. 14
      engine/src/lib/ui/painting/image_encoding.h
  21. 3
      engine/src/lib/ui/painting/picture.cc
  22. 14
      engine/src/lib/ui/window/platform_message_response_mono.cc
  23. 46
      engine/src/render_api_d3d11.cc
  24. 60
      engine/src/runtime/mono_api.cc
  25. 1
      engine/src/runtime/mono_api.h
  26. 2
      engine/src/runtime/mono_isolate.cc
  27. 36
      engine/src/shell/common/shell.cc
  28. 16
      engine/src/shell/platform/embedder/embedder_task_runner.cc
  29. 3
      engine/src/shell/platform/embedder/embedder_task_runner.h
  30. 7
      engine/src/shell/platform/unity/uiwidgets_system.h
  31. 3
      engine/third_party/Unity/IUnityUIWidgets.h

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


}
public static readonly FutureOr nil = value(null);
public static implicit operator FutureOr(string v) => value(v);
public static implicit operator FutureOr(byte[] v) => value(v);

public abstract Future then(Func<object, FutureOr> onValue, Func<Exception, FutureOr> onError = null);
public Future then(Action<object> onValue, Func<Exception, FutureOr> onError = null) {
return then(v => {
onValue(v);
return FutureOr.nil;
}, onError);
}
public Future catchError(Action<Exception> onError, Func<Exception, bool> test = null) {
return catchError(e => {
onError(e);
return FutureOr.nil;
}, test);
}
public Future whenComplete(Action action) {
return whenComplete(() => {
action();
return FutureOr.nil;
});
}
// public abstract Stream asStream();
public abstract Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null);

return _future.then(onValue, onError);
}
public Future<R> then<R>(Func<T, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
public Future then_(Func<T, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(obj => onValue((T) obj), onError);
}
public Future<R> then_<R>(Func<T, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
}
public Future then_(Action<T> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(obj => onValue((T) obj), onError);
}
public override Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null) {

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

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


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

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


public abstract Future<byte[]> load(string key);
public virtual Future<string> loadString(string key, bool cache = true) {
return load(key).then<string>(data => {
return load(key).then_<string>(data => {
if (data == null)
throw new UIWidgetsError($"Unable to load asset: {key}");

public override Future<T> loadStructuredData<T>(string key, Func<string, Future<T>> parser) {
D.assert(key != null);
D.assert(parser != null);
return loadString(key).then<T>(value => parser(value));
return loadString(key).then_<T>(value => parser(value));
}
public override string ToString() => $"{foundation_.describeIdentity(this)}({_baseUrl})";

Completer completer = null;
Future<T> result = null;
loadString(key, cache: false).then<T>(value => parser(value)).then<object>((T value) => {
loadString(key, cache: false).then_<T>(value => parser(value)).then_<object>((T value) => {
result = new SynchronousFuture<T>(value);
_structuredDataCache[key] = result;
if (completer != null) {

public override Future<byte[]> load(string key) {
byte[] encoded = Encoding.UTF8.GetBytes(key);
return ServicesBinding.instance.defaultBinaryMessenger.send(
"uiwidgets/assets", encoded).then<byte[]>(asset => {
"uiwidgets/assets", encoded).then_<byte[]>(asset => {
if (asset == null)
throw new UIWidgetsError($"Unable to load asset: {key}");
return asset;

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


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

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

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


#endif
static unsafe void hook() {
Mono_hook(
Mono_throwException);
Mono_throwException,
Mono_shutdown);
Window_hook(
Window_constructor,

throw new Exception(Marshal.PtrToStringAnsi(exception));
}
delegate void Mono_ShutdownCallback(IntPtr isolate);
[MonoPInvokeCallback(typeof(Mono_ShutdownCallback))]
static void Mono_shutdown(IntPtr isolate) {
try {
Isolate.shutdown(isolate);
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
static extern void Mono_hook(Mono_ThrowExceptionCallback throwException);
static extern void Mono_hook(Mono_ThrowExceptionCallback throwException, Mono_ShutdownCallback shutdown);
delegate IntPtr Window_constructorCallback(IntPtr ptr);

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


using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.UIWidgets.foundation;
using UnityEngine;
namespace Unity.UIWidgets.ui2 {
public class Isolate {

IntPtr _ptr;
readonly Dictionary<IntPtr, WeakReference<NativeWrapper>> _nativeWrappers =
new Dictionary<IntPtr, WeakReference<NativeWrapper>>();
bool _inShutdown = false;
internal void addNativeWrapper(NativeWrapper wrapper) {
lock (_nativeWrappers) {
_nativeWrappers.Add(wrapper._ptr, new WeakReference<NativeWrapper>(wrapper));
}
}
internal void removeNativeWrapper(IntPtr ptr) {
lock (_nativeWrappers) {
if (_inShutdown) {
return;
}
_nativeWrappers.Remove(ptr);
}
}
public bool isValid => _ptr != IntPtr.Zero;
public static Isolate current {

D.assert(value.isValid);
return value;
}
var isolate = new Isolate(ptr);
_isolates.Add(ptr, isolate);
return isolate;

return ptr;
}
internal static void remove(Isolate isolate) {
D.assert(isolate != null && isolate.isValid);
_isolates.Remove(isolate._ptr);
public static bool checkExists() {
IntPtr ptr = Isolate_current();
return ptr != IntPtr.Zero;
}
internal static void shutdown(IntPtr ptr) {
var isolate = _isolates[ptr];
D.assert(isolate._ptr == ptr);
lock (isolate._nativeWrappers) {
isolate._inShutdown = true;
foreach (var entry in isolate._nativeWrappers) {
if (entry.Value.TryGetTarget(out NativeWrapper target)) {
target._dispose();
}
}
isolate._nativeWrappers.Clear();
isolate._inShutdown = false;
}
_isolates.Remove(ptr);
isolate._ptr = IntPtr.Zero;
}

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


#else
internal const string dllName = "libUIWidgets_d";
#endif
protected internal IntPtr _ptr { get; protected set; }
protected internal IntPtr _ptr { get; private set; }
Isolate _isolate;
_setPtr(ptr);
}
protected void _setPtr(IntPtr ptr) {
_isolate = Isolate.current;
_isolate.addNativeWrapper(this);
~NativeWrapper() {
internal void _dispose(bool finalizer = false) {
D.assert(_isolate.isValid);
_isolate.removeNativeWrapper(_ptr);
if (!finalizer) {
GC.SuppressFinalize(this);
}
~NativeWrapper() {
_dispose(true);
}
public abstract class NativeWrapperDisposable : IDisposable {
protected internal IntPtr _ptr { get; protected set; }
public abstract class NativeWrapperDisposable : NativeWrapper, IDisposable {
protected NativeWrapperDisposable(IntPtr ptr) {
D.assert(ptr != IntPtr.Zero);
_ptr = ptr;
protected NativeWrapperDisposable(IntPtr ptr) : base(ptr) {
~NativeWrapperDisposable() {
if (_ptr != IntPtr.Zero) {
DisposePtr(_ptr);
_ptr = IntPtr.Zero;
}
}
protected abstract void DisposePtr(IntPtr ptr);
if (_ptr != IntPtr.Zero) {
DisposePtr(_ptr);
_ptr = IntPtr.Zero;
}
GC.SuppressFinalize(this);
_dispose();
}
}
}

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


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

antiAliasWithSaveLayer,
}
public static partial class ui_ {
const int _kDoNotResizeDimension = -1;
}
public class Paint {
internal readonly byte[] _data = new byte[_kDataByteCount];

png,
}
enum PixelFormat {
public enum PixelFormat {
/**
* TODO: _ImageInfo
*/
[StructLayout(LayoutKind.Sequential)]
struct _ImageInfo {
internal _ImageInfo(int width, int height, int format, int? rowBytes = null) {
this.width = width;
this.height = height;
this.format = format;
this.rowBytes = rowBytes ?? width * 4;
}
public int width;
public int height;
public int format;
public int rowBytes;
}
Image_dispose(_ptr);
Image_dispose(ptr);
}
public int width => Image_width(_ptr);

public Promise<byte[]> toByteData(
public Future<byte[]> toByteData(
var completer = new Promise<byte[]>(true);
GCHandle completerHandle = GCHandle.Alloc(completer);
return ui_._futurize(
(_Callback<byte[]> callback) => {
GCHandle callbackHandle = GCHandle.Alloc(callback);
IntPtr error =
Image_toByteData(_ptr, (int) format, _toByteDataCallback,
(IntPtr) completerHandle);
if (error != null) {
completerHandle.Free();
throw new Exception(Marshal.PtrToStringAnsi(error));
}
IntPtr error = Image_toByteData(_ptr,
(int) format, _toByteDataCallback, (IntPtr) callbackHandle);
if (error != IntPtr.Zero) {
callbackHandle.Free();
return Marshal.PtrToStringAnsi(error);
}
return completer;
return null;
});
GCHandle completerHandle = (GCHandle) callbackHandle;
var completer = (Promise<byte[]>) completerHandle.Target;
completerHandle.Free();
GCHandle handle = (GCHandle) callbackHandle;
var callback = (_Callback<byte[]>) handle.Target;
handle.Free();
if (!Isolate.checkExists()) {
return;
}
completer.Resolve(new byte[0]);
callback(new byte[0]);
completer.Resolve(bytes);
callback(bytes);
}
}
catch (Exception ex) {

/*
* TODO: FrameInfo, Codec
*/
public delegate void ImageDecoderCallback(Image result);
public class FrameInfo : NativeWrapper {
internal FrameInfo(IntPtr ptr) : base(ptr) {
}
protected override void DisposePtr(IntPtr ptr) {
FrameInfo_dispose(ptr);
}
public TimeSpan duration => TimeSpan.FromMilliseconds(_durationMillis);
int _durationMillis => FrameInfo_durationMillis(_ptr);
public Image image => new Image(FrameInfo_image(_ptr));
[DllImport(NativeBindings.dllName)]
static extern void FrameInfo_dispose(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern int FrameInfo_durationMillis(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern IntPtr FrameInfo_image(IntPtr ptr);
}
public class Codec : NativeWrapperDisposable {
internal Codec(IntPtr ptr) : base(ptr) {
}
protected override void DisposePtr(IntPtr ptr) {
Codec_dispose(ptr);
}
public int frameCount => Codec_frameCount(_ptr);
public int repetitionCount => Codec_repetitionCount(_ptr);
public Future<FrameInfo> getNextFrame() {
return ui_._futurize<FrameInfo>(_getNextFrame);
}
string _getNextFrame(_Callback<FrameInfo> callback) {
GCHandle callbackHandle = GCHandle.Alloc(callback);
IntPtr error = Codec_getNextFrame(_ptr, _getNextFrameCallback, (IntPtr) callbackHandle);
if (error != IntPtr.Zero) {
callbackHandle.Free();
return Marshal.PtrToStringAnsi(error);
}
return null;
}
[MonoPInvokeCallback(typeof(Codec_getNextFrameCallback))]
static void _getNextFrameCallback(IntPtr callbackHandle, IntPtr ptr) {
GCHandle handle = (GCHandle) callbackHandle;
var callback = (_Callback<FrameInfo>) handle.Target;
handle.Free();
if (!Isolate.checkExists()) {
return;
}
try {
callback(ptr == IntPtr.Zero ? null : new FrameInfo(ptr));
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
internal static unsafe string _instantiateImageCodec(byte[] list, _Callback<Codec> callback,
_ImageInfo? imageInfo, int targetWidth, int targetHeight) {
GCHandle callbackHandle = GCHandle.Alloc(callback);
fixed (byte* bytes = list) {
IntPtr error = Codec_instantiateImageCodec(bytes, list?.Length ?? 0,
_instantiateImageCodecCallback, (IntPtr) callbackHandle,
imageInfo ?? default, imageInfo.HasValue, targetWidth, targetHeight);
if (error != IntPtr.Zero) {
callbackHandle.Free();
return Marshal.PtrToStringAnsi(error);
}
}
return null;
}
[MonoPInvokeCallback(typeof(Codec_instantiateImageCodecCallback))]
static void _instantiateImageCodecCallback(IntPtr callbackHandle, IntPtr ptr) {
GCHandle handle = (GCHandle) callbackHandle;
var callback = (_Callback<Codec>) handle.Target;
handle.Free();
try {
D.assert(ptr != IntPtr.Zero);
callback(new Codec(ptr));
}
catch (Exception ex) {
Debug.LogException(ex);
}
}
[DllImport(NativeBindings.dllName)]
static extern void Codec_dispose(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern int Codec_frameCount(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern int Codec_repetitionCount(IntPtr ptr);
delegate void Codec_getNextFrameCallback(IntPtr callbackHandle, IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern IntPtr Codec_getNextFrame(IntPtr ptr, Codec_getNextFrameCallback callback, IntPtr callbackHandle);
delegate void Codec_instantiateImageCodecCallback(IntPtr callbackHandle, IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern unsafe IntPtr Codec_instantiateImageCodec(byte* list, int listLength,
Codec_instantiateImageCodecCallback callback,
IntPtr callbackHandle, _ImageInfo imageInfo, bool hasImageInfo, int targetWidth, int targetHeight);
}
public static partial class ui_ {
public static Future<Codec> instantiateImageCodec(byte[] list, int? targetWidth = null,
int? targetHeight = null) {
return _futurize(
(_Callback<Codec> callback) => Codec._instantiateImageCodec(list, callback, null,
targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension)
);
}
public static void decodeImageFromList(byte[] list, ImageDecoderCallback callback) {
_decodeImageFromListAsync(list, callback);
}
static Future _decodeImageFromListAsync(byte[] list, ImageDecoderCallback callback) {
return instantiateImageCodec(list).then_(codec => {
return codec.getNextFrame().then_(frameInfo => { callback(frameInfo.image); });
});
}
public static void decodeImageFromPixels(
byte[] pixels,
int width,
int height,
PixelFormat format,
ImageDecoderCallback callback,
int? rowBytes = null, int? targetWidth = null, int? targetHeight = null
) {
_ImageInfo imageInfo = new _ImageInfo(width, height, (int) format, rowBytes);
Future<Codec> codecFuture = _futurize(
(_Callback<Codec> callback1) => Codec._instantiateImageCodec(pixels, callback1, imageInfo,
targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension)
);
codecFuture.then_<FrameInfo>(codec => codec.getNextFrame())
.then_(frameInfo => callback(frameInfo.image));
}
}
public enum PathFillType {
nonZero,
evenOdd,

}
protected override void DisposePtr(IntPtr ptr) {
Layer_dispose(ptr);
EngineLayer_dispose(ptr);
static extern void Layer_dispose(IntPtr ptr);
static extern void EngineLayer_dispose(IntPtr ptr);
}
public class Path : NativeWrapper {

}
cullRect = cullRect ?? Rect.largest;
_ptr = Canvas_constructor(recorder._ptr, cullRect.left, cullRect.top,
_setPtr(Canvas_constructor(recorder._ptr, cullRect.left, cullRect.top,
cullRect.bottom);
cullRect.bottom));
}
protected override void DisposePtr(IntPtr ptr) {

}
[DllImport(NativeBindings.dllName)]
public static extern IntPtr Canvas_constructor(IntPtr recorder,
static extern IntPtr Canvas_constructor(IntPtr recorder,
float left,
float top,
float right,

public static extern void Canvas_dispose(IntPtr ptr);
static extern void Canvas_dispose(IntPtr ptr);
public static extern void Canvas_save(IntPtr ptr);
static extern void Canvas_save(IntPtr ptr);
public static extern unsafe void
static extern unsafe void
public static extern unsafe void Canvas_saveLayer(IntPtr ptr,
static extern unsafe void Canvas_saveLayer(IntPtr ptr,
public static extern void Canvas_restore(IntPtr ptr);
static extern void Canvas_restore(IntPtr ptr);
public static extern int Canvas_getSaveCount(IntPtr ptr);
static extern int Canvas_getSaveCount(IntPtr ptr);
public static extern void Canvas_translate(IntPtr ptr,
static extern void Canvas_translate(IntPtr ptr,
public static extern void Canvas_scale(IntPtr ptr,
static extern void Canvas_scale(IntPtr ptr,
public static extern void Canvas_rotate(IntPtr ptr,
static extern void Canvas_rotate(IntPtr ptr,
public static extern void Canvas_skew(IntPtr ptr,
static extern void Canvas_skew(IntPtr ptr,
public static extern unsafe void Canvas_transform(IntPtr ptr,
static extern unsafe void Canvas_transform(IntPtr ptr,
public static extern void Canvas_clipRect(IntPtr ptr,
static extern void Canvas_clipRect(IntPtr ptr,
public static extern unsafe void Canvas_clipRRect(IntPtr ptr,
static extern unsafe void Canvas_clipRRect(IntPtr ptr,
public static extern void Canvas_clipPath(IntPtr ptr,
static extern void Canvas_clipPath(IntPtr ptr,
public static extern void Canvas_drawColor(IntPtr ptr,
static extern void Canvas_drawColor(IntPtr ptr,
public static extern unsafe void Canvas_drawLine(IntPtr ptr,
static extern unsafe void Canvas_drawLine(IntPtr ptr,
public static extern unsafe void Canvas_drawPaint(IntPtr ptr,
static extern unsafe void Canvas_drawPaint(IntPtr ptr,
public static extern unsafe void Canvas_drawRect(IntPtr ptr,
static extern unsafe void Canvas_drawRect(IntPtr ptr,
public static extern unsafe void Canvas_drawRRect(IntPtr ptr,
static extern unsafe void Canvas_drawRRect(IntPtr ptr,
public static extern unsafe void Canvas_drawDRRect(IntPtr ptr,
static extern unsafe void Canvas_drawDRRect(IntPtr ptr,
public static extern unsafe void Canvas_drawOval(IntPtr ptr,
static extern unsafe void Canvas_drawOval(IntPtr ptr,
public static extern unsafe void Canvas_drawCircle(IntPtr ptr,
static extern unsafe void Canvas_drawCircle(IntPtr ptr,
public static extern unsafe void Canvas_drawArc(IntPtr ptr,
static extern unsafe void Canvas_drawArc(IntPtr ptr,
public static extern unsafe void Canvas_drawPath(IntPtr ptr,
static extern unsafe void Canvas_drawPath(IntPtr ptr,
public static extern unsafe void Canvas_drawImage(IntPtr ptr,
static extern unsafe void Canvas_drawImage(IntPtr ptr,
public static extern unsafe void Canvas_drawImageRect(IntPtr ptr,
static extern unsafe void Canvas_drawImageRect(IntPtr ptr,
public static extern unsafe void Canvas_drawImageNine(IntPtr ptr,
static extern unsafe void Canvas_drawImageNine(IntPtr ptr,
public static extern void Canvas_drawPicture(IntPtr ptr, IntPtr picture);
static extern void Canvas_drawPicture(IntPtr ptr, IntPtr picture);
public static extern unsafe void Canvas_drawPoints(IntPtr ptr,
static extern unsafe void Canvas_drawPoints(IntPtr ptr,
public static extern unsafe void Canvas_drawVertices(IntPtr ptr, IntPtr vertices, int blendMode,
static extern unsafe void Canvas_drawVertices(IntPtr ptr, IntPtr vertices, int blendMode,
public static extern unsafe void Canvas_drawAtlas(IntPtr ptr, IntPtr* paintObjects, byte* paintData,
static extern unsafe void Canvas_drawAtlas(IntPtr ptr, IntPtr* paintObjects, byte* paintData,
public static extern void Canvas_drawShadow(IntPtr ptr, IntPtr path, uint color, float elevation,
static extern void Canvas_drawShadow(IntPtr ptr, IntPtr path, uint color, float elevation,
bool transparentOccluder);
}

Picture_dispose(ptr);
}
public Future toImage(int width, int height) {
public Future<Image> toImage(int width, int height) {
if (width <= 0 || height <= 0) {
throw new ArgumentException("Invalid image dimensions.");
}

GCHandle handle = (GCHandle) callbackHandle;
var callback = (_Callback<Image>) handle.Target;
handle.Free();
if (!Isolate.checkExists()) {
return;
}
try {
callback(result == IntPtr.Zero ? null : new Image(result));

delegate string _Callbacker<T>(_Callback<T> callback);
public static partial class ui_ {
internal static Future _futurize<T>(_Callbacker<T> callbacker) {
internal static Future<T> _futurize<T>(_Callbacker<T> callbacker) {
Completer completer = Completer.sync();
string error = callbacker(t => {
if (t == null) {

});
if (error != null)
throw new Exception(error);
return completer.future;
return completer.future.to<T>();
}
}
}

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


var callback = (PlatformMessageResponseCallback) handle.Target;
handle.Free();
if (!Isolate.checkExists()) {
return;
}
byte[] bytes = null;
if (data != null && dataLength != 0) {
bytes = new byte[dataLength];

8
engine/Build.bee.cs


"src/lib/ui/painting/canvas.cc",
"src/lib/ui/painting/canvas.h",
"src/lib/ui/painting/codec.cc",
"src/lib/ui/painting/codec.h",
"src/lib/ui/painting/frame_info.cc",
"src/lib/ui/painting/frame_info.h",
"src/lib/ui/painting/gradient.cc",
"src/lib/ui/painting/gradient.h",
"src/lib/ui/painting/image.cc",

"src/lib/ui/painting/image_shader.h",
"src/lib/ui/painting/matrix.cc",
"src/lib/ui/painting/matrix.h",
"src/lib/ui/painting/multi_frame_codec.cc",
"src/lib/ui/painting/multi_frame_codec.h",
"src/lib/ui/painting/path.cc",
"src/lib/ui/painting/path.h",
"src/lib/ui/painting/paint.cc",

"src/lib/ui/painting/rrect.h",
"src/lib/ui/painting/shader.cc",
"src/lib/ui/painting/shader.h",
"src/lib/ui/painting/single_frame_codec.cc",
"src/lib/ui/painting/single_frame_codec.h",
"src/lib/ui/painting/vertices.cc",
"src/lib/ui/painting/vertices.h",

14
engine/src/flow/skia_gpu_object.cc


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

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

skia_object->unref();
}
if (performDeferredCleanup) {
if (context_ && skia_objects.size() > 0) {
context_->performDeferredCleanup(std::chrono::milliseconds(0));
}
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(bool performDeferredCleanup = true);
void Drain();
private:
const fml::RefPtr<fml::TaskRunner> task_runner_;

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


UIWIDGETS_API(void) SceneBuilder_dispose(SceneBuilder* ptr) { ptr->Release(); }
UIWIDGETS_API(void)
UIWIDGETS_API(EngineLayer*)
ptr->pushTransform(matrix4);
const auto layer = ptr->pushTransform(matrix4);
layer->AddRef();
return layer.get();
UIWIDGETS_API(void)
UIWIDGETS_API(EngineLayer*)
ptr->pushOffset(dx, dy);
const auto layer = ptr->pushOffset(dx, dy);
layer->AddRef();
return layer.get();
}
UIWIDGETS_API(void)

6
engine/src/lib/ui/painting/engine_layer.cc


#include "engine_layer.h"
#include "runtime/mono_api.h"
namespace uiwidgets {
EngineLayer::EngineLayer(std::shared_ptr<ContainerLayer> layer)

size_t EngineLayer::GetAllocationSize() { return 3000; };
size_t EngineLayer::GetAllocationSize() { return 3000; }
UIWIDGETS_API(void) EngineLayer_dispose(EngineLayer* ptr) { ptr->Release(); }
} // namespace uiwidgets

15
engine/src/lib/ui/painting/image.cc


CanvasImage::~CanvasImage() = default;
const char* CanvasImage::toByteData(int format, EncodeImageCallback callback,
const char* CanvasImage::toByteData(int format, RawEncodeImageCallback callback,
Mono_Handle callback_handle) {
return EncodeImage(this, format, callback, callback_handle);
}

} else {
return sizeof(CanvasImage);
}
}
UIWIDGETS_API(void) Image_dispose(CanvasImage* ptr) { ptr->Release(); }
UIWIDGETS_API(int) Image_width(CanvasImage* ptr) { return ptr->width(); }
UIWIDGETS_API(int) Image_height(CanvasImage* ptr) { return ptr->height(); }
UIWIDGETS_API(const char*)
Image_toByteData(CanvasImage* ptr, int format,
RawEncodeImageCallback encode_image_callback,
Mono_Handle callback_handle) {
return ptr->toByteData(format, encode_image_callback, callback_handle);
}
} // namespace uiwidgets

2
engine/src/lib/ui/painting/image.h


int height() { return image_.get()->height(); }
const char* toByteData(int format, EncodeImageCallback callback,
const char* toByteData(int format, RawEncodeImageCallback callback,
Mono_Handle callback_handle);
void dispose();

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


#include "src/codec/SkCodecImageGenerator.h"
namespace uiwidgets {
namespace {
constexpr double kAspectRatioChangedThreshold = 0.01;
} // namespace
fml::WeakPtr<IOManager> io_manager) {}
fml::WeakPtr<IOManager> io_manager)
: runners_(std::move(runners)),
concurrent_task_runner_(std::move(concurrent_task_runner)),
io_manager_(std::move(io_manager)),
weak_factory_(this) {
FML_DCHECK(runners_.IsValid());
FML_DCHECK(runners_.GetUITaskRunner()->RunsTasksOnCurrentThread())
<< "The image decoder must be created & collected on the UI thread.";
}
ImageDecoder::~ImageDecoder() = default;
static double AspectRatio(const SkISize& size) {
return static_cast<double>(size.width()) / size.height();
}
// Get the updated dimensions of the image. If both dimensions are specified,
// use them. If one of them is specified, respect the one that is and use the
// aspect ratio to calculate the other. If neither dimension is specified, use
// intrinsic dimensions of the image.
static SkISize GetResizedDimensions(SkISize current_size,
std::optional<uint32_t> target_width,
std::optional<uint32_t> target_height) {
if (current_size.isEmpty()) {
return SkISize::MakeEmpty();
}
if (target_width && target_height) {
return SkISize::Make(target_width.value(), target_height.value());
}
const auto aspect_ratio = AspectRatio(current_size);
if (target_width) {
return SkISize::Make(target_width.value(),
target_width.value() / aspect_ratio);
}
if (target_height) {
return SkISize::Make(target_height.value() * aspect_ratio,
target_height.value());
}
return current_size;
}
static sk_sp<SkImage> ResizeRasterImage(sk_sp<SkImage> image,
const SkISize& resized_dimensions,
const fml::tracing::TraceFlow& flow) {
FML_DCHECK(!image->isTextureBacked());
TRACE_EVENT0("uiwidgets", __FUNCTION__);
flow.Step(__FUNCTION__);
if (resized_dimensions.isEmpty()) {
FML_LOG(ERROR) << "Could not resize to empty dimensions.";
return nullptr;
}
if (image->dimensions() == resized_dimensions) {
return image->makeRasterImage();
}
if (resized_dimensions.width() > image->dimensions().width() ||
resized_dimensions.height() > image->dimensions().height()) {
FML_LOG(WARNING) << "Image is being upsized from "
<< image->dimensions().width() << "x"
<< image->dimensions().height() << " to "
<< resized_dimensions.width() << "x"
<< resized_dimensions.height()
<< ". Are cache(Height|Width) used correctly?";
// TOOD(48885): consider exiting here, there's no good reason to support
// upsampling in a "caching"-optimization context..
}
const bool aspect_ratio_changed =
std::abs(AspectRatio(resized_dimensions) -
AspectRatio(image->dimensions())) > kAspectRatioChangedThreshold;
if (aspect_ratio_changed) {
// This is probably a bug. If a user passes dimensions that change the
// aspect ratio in a "caching" context that's probably not working as
// intended and rather a signal that the API is hard to use.
FML_LOG(WARNING)
<< "Aspect ratio changes. Are cache(Height|Width) used correctly?";
}
const auto scaled_image_info =
image->imageInfo().makeDimensions(resized_dimensions);
SkBitmap scaled_bitmap;
if (!scaled_bitmap.tryAllocPixels(scaled_image_info)) {
FML_LOG(ERROR) << "Failed to allocate memory for bitmap of size "
<< scaled_image_info.computeMinByteSize() << "B";
return nullptr;
}
if (!image->scalePixels(scaled_bitmap.pixmap(), kLow_SkFilterQuality,
SkImage::kDisallow_CachingHint)) {
FML_LOG(ERROR) << "Could not scale pixels";
return nullptr;
}
// Marking this as immutable makes the MakeFromBitmap call share the pixels
// instead of copying.
scaled_bitmap.setImmutable();
auto scaled_image = SkImage::MakeFromBitmap(scaled_bitmap);
if (!scaled_image) {
FML_LOG(ERROR) << "Could not create a scaled image from a scaled bitmap.";
return nullptr;
}
return scaled_image;
}
static sk_sp<SkImage> ImageFromDecompressedData(
sk_sp<SkData> data, ImageDecoder::ImageInfo info,
std::optional<uint32_t> target_width, std::optional<uint32_t> target_height,
const fml::tracing::TraceFlow& flow) {
TRACE_EVENT0("uiwidgets", __FUNCTION__);
flow.Step(__FUNCTION__);
auto image = SkImage::MakeRasterData(info.sk_info, data, info.row_bytes);
if (!image) {
FML_LOG(ERROR) << "Could not create image from decompressed bytes.";
return nullptr;
}
if (!target_width && !target_height) {
// No resizing requested. Just rasterize the image.
return image->makeRasterImage();
}
auto resized_dimensions =
GetResizedDimensions(image->dimensions(), target_width, target_height);
return ResizeRasterImage(std::move(image), resized_dimensions, flow);
}
sk_sp<SkImage> ImageFromCompressedData(sk_sp<SkData> data,
std::optional<uint32_t> target_width,
std::optional<uint32_t> target_height,
const fml::tracing::TraceFlow& flow) {
TRACE_EVENT0("uiwidgets", __FUNCTION__);
flow.Step(__FUNCTION__);
if (!target_width && !target_height) {
// No resizing requested. Just decode & rasterize the image.
return SkImage::MakeFromEncoded(data)->makeRasterImage();
}
auto codec = SkCodec::MakeFromData(data);
if (codec == nullptr) {
return nullptr;
}
const auto* codec_ptr = codec.get();
// Note that we cannot read the dimensions from the codec since they don't
// respect image orientation provided e.g. in EXIF data.
auto image_generator = SkCodecImageGenerator::MakeFromCodec(std::move(codec));
const auto& source_dimensions = image_generator->getInfo().dimensions();
auto resized_dimensions =
GetResizedDimensions(source_dimensions, target_width, target_height);
// No resize needed.
if (resized_dimensions == source_dimensions) {
return SkImage::MakeFromEncoded(data)->makeRasterImage();
}
auto decode_dimensions = codec_ptr->getScaledDimensions(
std::max(static_cast<double>(resized_dimensions.width()) /
source_dimensions.width(),
static_cast<double>(resized_dimensions.height()) /
source_dimensions.height()));
// If the codec supports efficient sub-pixel decoding, decoded at a resolution
// close to the target resolution before resizing.
if (decode_dimensions != codec_ptr->dimensions()) {
if (source_dimensions != codec_ptr->dimensions()) {
decode_dimensions =
SkISize::Make(decode_dimensions.height(), decode_dimensions.width());
}
auto scaled_image_info =
image_generator->getInfo().makeDimensions(decode_dimensions);
SkBitmap scaled_bitmap;
if (!scaled_bitmap.tryAllocPixels(scaled_image_info)) {
FML_LOG(ERROR) << "Failed to allocate memory for bitmap of size "
<< scaled_image_info.computeMinByteSize() << "B";
return nullptr;
}
const auto& pixmap = scaled_bitmap.pixmap();
if (image_generator->getPixels(pixmap.info(), pixmap.writable_addr(),
pixmap.rowBytes())) {
// Marking this as immutable makes the MakeFromBitmap call share
// the pixels instead of copying.
scaled_bitmap.setImmutable();
auto decoded_image = SkImage::MakeFromBitmap(scaled_bitmap);
FML_DCHECK(decoded_image);
if (!decoded_image) {
FML_LOG(ERROR)
<< "Could not create a scaled image from a scaled bitmap.";
return nullptr;
}
return ResizeRasterImage(std::move(decoded_image), resized_dimensions,
flow);
}
}
auto image = SkImage::MakeFromEncoded(data);
if (!image) {
return nullptr;
}
return ResizeRasterImage(std::move(image), resized_dimensions, flow);
}
static SkiaGPUObject<SkImage> UploadRasterImage(
sk_sp<SkImage> image, fml::WeakPtr<IOManager> io_manager,
const fml::tracing::TraceFlow& flow) {
TRACE_EVENT0("uiwidgets", __FUNCTION__);
flow.Step(__FUNCTION__);
// Should not already be a texture image because that is the entire point of
// the this method.
FML_DCHECK(!image->isTextureBacked());
if (!io_manager->GetResourceContext() || !io_manager->GetSkiaUnrefQueue()) {
FML_LOG(ERROR)
<< "Could not acquire context of release queue for texture upload.";
return {};
}
SkPixmap pixmap;
if (!image->peekPixels(&pixmap)) {
FML_LOG(ERROR) << "Could not peek pixels of image for texture upload.";
return {};
}
SkiaGPUObject<SkImage> result;
io_manager->GetIsGpuDisabledSyncSwitch()->Execute(
fml::SyncSwitch::Handlers()
.SetIfTrue([&result, &pixmap, &image] {
SkSafeRef(image.get());
sk_sp<SkImage> texture_image = SkImage::MakeFromRaster(
pixmap,
[](const void* pixels, SkImage::ReleaseContext context) {
SkSafeUnref(static_cast<SkImage*>(context));
},
image.get());
result = {texture_image, nullptr};
})
.SetIfFalse([&result, context = io_manager->GetResourceContext(),
&pixmap, queue = io_manager->GetSkiaUnrefQueue()] {
TRACE_EVENT0("uiwidgets", "MakeCrossContextImageFromPixmap");
sk_sp<SkImage> texture_image = SkImage::MakeCrossContextFromPixmap(
context.get(), // context
pixmap, // pixmap
true, // buildMips,
true // limitToMaxTextureSize
);
if (!texture_image) {
FML_LOG(ERROR) << "Could not make x-context image.";
result = {};
} else {
result = {texture_image, queue};
}
}));
return result;
}
void ImageDecoder::Decode(ImageDescriptor descriptor,
const ImageResult& callback) {
TRACE_EVENT0("uiwidgets", __FUNCTION__);
fml::tracing::TraceFlow flow(__FUNCTION__);
FML_DCHECK(callback);
FML_DCHECK(runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
// Always service the callback on the UI thread.
auto result = [callback, ui_runner = runners_.GetUITaskRunner()](
SkiaGPUObject<SkImage> image,
fml::tracing::TraceFlow flow) {
ui_runner->PostTask(fml::MakeCopyable(
[callback, image = std::move(image), flow = std::move(flow)]() mutable {
// We are going to terminate the trace flow here. Flows cannot
// terminate without a base trace. Add one explicitly.
TRACE_EVENT0("uiwidgets", "ImageDecodeCallback");
flow.End();
callback(std::move(image));
}));
};
if (!descriptor.data || descriptor.data->size() == 0) {
result({}, std::move(flow));
return;
}
concurrent_task_runner_->PostTask(
fml::MakeCopyable([descriptor, //
io_manager = io_manager_, //
io_runner = runners_.GetIOTaskRunner(), //
result, //
flow = std::move(flow) //
]() mutable {
// Step 1: Decompress the image.
// On Worker.
auto decompressed =
descriptor.decompressed_image_info
? ImageFromDecompressedData(
std::move(descriptor.data), //
descriptor.decompressed_image_info.value(), //
descriptor.target_width, //
descriptor.target_height, //
flow //
)
: ImageFromCompressedData(std::move(descriptor.data), //
descriptor.target_width, //
descriptor.target_height, //
flow);
if (!decompressed) {
FML_LOG(ERROR) << "Could not decompress image.";
result({}, std::move(flow));
return;
}
// Step 2: Update the image to the GPU.
// On IO Thread.
io_runner->PostTask(fml::MakeCopyable([io_manager, decompressed, result,
flow =
std::move(flow)]() mutable {
if (!io_manager) {
FML_LOG(ERROR) << "Could not acquire IO manager.";
return result({}, std::move(flow));
}
// If the IO manager does not have a resource context, the caller
// might not have set one or a software backend could be in use.
// Either way, just return the image as-is.
if (!io_manager->GetResourceContext()) {
result({std::move(decompressed), io_manager->GetSkiaUnrefQueue()},
std::move(flow));
return;
}
auto uploaded =
UploadRasterImage(std::move(decompressed), io_manager, flow);
if (!uploaded.get()) {
FML_LOG(ERROR) << "Could not upload image to the GPU.";
result({}, std::move(flow));
return;
}
// Finally, all done.
result(std::move(uploaded), std::move(flow));
}));
}));
}
return fml::WeakPtr<ImageDecoder>();
return weak_factory_.GetWeakPtr();
}
} // namespace uiwidgets

55
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 <memory>
#include <optional>
#include "flow/skia_gpu_object.h"
#include "flutter/fml/concurrent_message_loop.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "flutter/fml/trace_event.h"
#include "include/core/SkData.h"
#include "include/core/SkImage.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSize.h"
// An object that coordinates image decompression and texture upload across
// multiple threads/components in the shell. This object must be created,
// accessed and collected on the UI thread (typically the engine or its runtime
// controller). None of the expensive operations performed by this component
// occur in a frame pipeline.
class ImageDecoder {
public:
ImageDecoder(

~ImageDecoder();
struct ImageInfo {
SkImageInfo sk_info = {};
size_t row_bytes = 0;
};
struct ImageDescriptor {
sk_sp<SkData> data;
std::optional<ImageInfo> decompressed_image_info;
std::optional<uint32_t> target_width;
std::optional<uint32_t> target_height;
};
using ImageResult = std::function<void(SkiaGPUObject<SkImage>)>;
// Takes an image descriptor and returns a handle to a texture resident on the
// GPU. All image decompression and resizes are done on a worker thread
// concurrently. Texture upload is done on the IO thread and the result
// returned back on the UI thread. On error, the texture is null but the
// callback is guaranteed to return on the UI thread.
void Decode(ImageDescriptor descriptor, const ImageResult& result);
private:
TaskRunners runners_;
std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner_;
fml::WeakPtr<IOManager> io_manager_;
fml::WeakPtrFactory<ImageDecoder> weak_factory_;
FML_DISALLOW_COPY_AND_ASSIGN(ImageDecoder);
sk_sp<SkImage> ImageFromCompressedData(sk_sp<SkData> data,
std::optional<uint32_t> target_width,
std::optional<uint32_t> target_height,
const fml::tracing::TraceFlow& flow);
} // namespace uiwidgets

42
engine/src/lib/ui/painting/image_encoding.cc


namespace uiwidgets {
namespace {
void InvokeDataCallback(std::unique_ptr<EncodeImageCallback> callback,
sk_sp<SkData> buffer) {
std::shared_ptr<MonoState> mono_state = callback->mono_state.lock();
if (!mono_state) {
callback->callback(callback->callback_handle, nullptr, 0);
return;
}
MonoState::Scope scope(mono_state);
if (!buffer) {
callback->callback(callback->callback_handle, nullptr, 0);
} else {
callback->callback(callback->callback_handle, buffer->bytes(),
buffer->size());
}
}
// This must be kept in sync with the enum in painting.dart
enum ImageByteFormat {
kRawRGBA,

if (png_image == nullptr) {
FML_LOG(ERROR) << "Could not convert raster image to PNG.";
return nullptr;
};
}
return png_image;
} break;
case kRawRGBA: {

}
void EncodeImageAndInvokeDataCallback(
sk_sp<SkImage> image, EncodeImageCallback callback,
Mono_Handle callback_handle, ImageByteFormat format,
fml::RefPtr<fml::TaskRunner> ui_task_runner,
sk_sp<SkImage> image, std::unique_ptr<EncodeImageCallback> callback,
ImageByteFormat format, fml::RefPtr<fml::TaskRunner> ui_task_runner,
[callback, callback_handle](sk_sp<SkData> encoded) mutable {
callback(callback_handle, encoded->bytes(), encoded->size());
[callback = std::move(callback)](sk_sp<SkData> encoded) mutable {
InvokeDataCallback(std::move(callback), std::move(encoded));
ui_task_runner](sk_sp<SkImage> raster_image) {
ui_task_runner](sk_sp<SkImage> raster_image) mutable {
sk_sp<SkData> encoded = EncodeImage(std::move(raster_image), format);
ui_task_runner->PostTask(
[callback_task = std::move(callback_task),

} // namespace
const char* EncodeImage(CanvasImage* canvas_image, int format,
EncodeImageCallback callback,
RawEncodeImageCallback raw_callback,
if (!callback || !callback_handle) return "Callback must be a function.";
if (!raw_callback || !callback_handle) return "Callback must be a function.";
auto callback = std::make_unique<EncodeImageCallback>(EncodeImageCallback{
MonoState::Current()->GetWeakPtr(), raw_callback, callback_handle});
[callback, callback_handle, image = canvas_image->image(), image_format,
ui_task_runner = task_runners.GetUITaskRunner(),
[callback = std::move(callback), image = canvas_image->image(),
image_format, ui_task_runner = task_runners.GetUITaskRunner(),
raster_task_runner = task_runners.GetRasterTaskRunner(),
io_task_runner = task_runners.GetIOTaskRunner(),
io_manager = UIMonoState::Current()->GetIOManager(),

std::move(image), callback, callback_handle, image_format,
std::move(image), std::move(callback), image_format,
std::move(ui_task_runner), std::move(raster_task_runner),
std::move(io_task_runner), io_manager->GetResourceContext().get(),
std::move(snapshot_delegate));

14
engine/src/lib/ui/painting/image_encoding.h


#pragma once
#include "runtime/mono_api.h"
#include "runtime/mono_state.h"
typedef void (*EncodeImageCallback)(Mono_Handle callback_handle,
const uint8_t* data, size_t length);
typedef void (*RawEncodeImageCallback)(Mono_Handle callback_handle,
const uint8_t* data, size_t length);
struct EncodeImageCallback {
std::weak_ptr<MonoState> mono_state;
RawEncodeImageCallback callback;
Mono_Handle callback_handle;
};
EncodeImageCallback callback,
Mono_Handle callback_handle);
RawEncodeImageCallback callback, Mono_Handle callback_handle);
} // namespace uiwidgets

3
engine/src/lib/ui/painting/picture.cc


auto mono_state = mono_state_weak.lock();
if (!mono_state) {
// The root isolate could have died in the meantime.
raw_image_callback(callback_handle, nullptr);
MonoState::Scope scope(mono_state);
if (!raster_image) {

auto mono_image = CanvasImage::Create();
mono_image->set_image({std::move(raster_image), std::move(unref_queue)});
mono_image->AddRef();
auto* raw_mono_image = mono_image.get();
// All done!

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


[mono_state_weak = mono_state_weak_, callback = callback_,
handle = handle_, data = std::move(data)]() {
const std::shared_ptr<MonoState> mono_state = mono_state_weak.lock();
if (!mono_state) return;
if (!mono_state) {
callback(handle, nullptr, 0);
return;
}
callback(handle, data->GetMapping(), static_cast<int>(data->GetSize()));
}));
}

ui_task_runner_->PostTask([mono_state_weak = mono_state_weak_,
callback = callback_, handle = handle_]() {
const std::shared_ptr<MonoState> mono_state = mono_state_weak.lock();
if (!mono_state) return;
if (!mono_state) {
callback(handle, nullptr, 0);
return;
}
callback(handle, nullptr, 0);
});
}

46
engine/src/render_api_d3d11.cc


#include "platform_base.h"
#include "render_api.h"
#include "shell/platform/unity/uiwidgets_system.h"
// Direct3D 11 implementation of RenderAPI.

#include <vector>
#include "TestLoadICU.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/third_party/txt/src/txt/font_collection.h"
#include "flutter/third_party/txt/src/txt/font_collection.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTextBlob.h"

#include "src/gpu/gl/GrGLDefines.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
#include "third_party/icu/SkLoadICU.h"
#include "TestLoadICU.h"
void Dart_TimelineEvent(const char* label, int64_t timestamp0,
int64_t timestamp1_or_async_id,
Dart_Timeline_Event_Type type, intptr_t argument_count,
const char** argument_names,
const char** argument_values) {}
class RenderAPI_D3D11 : public RenderAPI {
public:

txt::ParagraphStyle style;
txt::FontCollection tf;
txt::TextStyle ts;
//style.
// style.
std::unique_ptr<txt::ParagraphBuilder> pb = txt::ParagraphBuilder::CreateTxtBuilder(style, _fontCollection);
std::unique_ptr<txt::ParagraphBuilder> pb =
txt::ParagraphBuilder::CreateTxtBuilder(style, _fontCollection);
pb->PushStyle(ts);
std::u16string s16 = u"Hello, some text.你好!";
pb->AddText(s16);

// canvas->drawColor(SK_ColorWHITE);
testParagraph->Paint(canvas, 10, 200);
// canvas->drawColor(SK_ColorWHITE);
testParagraph->Paint(canvas, 10, 200);
}
void draw1(SkCanvas* canvas) {

}
double t = 0;
/* canvas->clear(SK_ColorWHITE);

animation_->seekFrameTime(t);
animation_->render(canvas);*/
//SkRect rect = SkRect::MakeLTRB(100, 100, 200, 200);
//canvas->drawImageRect(image_, rect, nullptr);
// SkRect rect = SkRect::MakeLTRB(100, 100, 200, 200);
// canvas->drawImageRect(image_, rect, nullptr);
// mutex_skia->ReleaseSync(0);
canvas->flush();

using namespace txt;
std::shared_ptr<txt::FontCollection> GetTestFontCollection() {
std::shared_ptr<txt::FontCollection> collection =
std::make_shared<txt::FontCollection>();
collection->SetupDefaultFontManager();
return collection;
std::shared_ptr<txt::FontCollection> collection =
std::make_shared<txt::FontCollection>();
collection->SetupDefaultFontManager();
return collection;
}
#endif // #if SUPPORT_D3D11

60
engine/src/runtime/mono_api.cc


#include "mono_isolate.h"
#include "mono_state.h"
#include "shell/platform/unity/uiwidgets_system.h"
namespace uiwidgets {

const Mono_Isolate current = *ptr;
FML_DCHECK(current != nullptr);
Mono_Shutdown(current);
*ptr = nullptr;
delete current;

static Mono_ThrowExceptionCallback Mono_ThrowExceptionCallback_;
typedef void (*Mono_ShutdownCallback)(Mono_Isolate isolate);
static Mono_ShutdownCallback Mono_ShutdownCallback_;
void Mono_Shutdown(Mono_Isolate isolate) { Mono_ShutdownCallback_(isolate); }
int64_t Mono_TimelineGetMicros() {
return fml::TimePoint::Now().ToEpochDelta().ToMicroseconds();

UIWIDGETS_API(void)
Mono_hook(Mono_ThrowExceptionCallback throwException) {
Mono_hook(Mono_ThrowExceptionCallback throwException,
Mono_ShutdownCallback shutdown) {
Mono_ShutdownCallback_ = shutdown;
}
UIWIDGETS_API(Mono_Isolate)

extern "C" int64_t Dart_TimelineGetMicros() {
return uiwidgets::Mono_TimelineGetMicros();
}
inline const char* TimelineEventToString(Dart_Timeline_Event_Type type) {
switch (type) {
case Dart_Timeline_Event_Begin:
return "Begin";
case Dart_Timeline_Event_End:
return "End";
case Dart_Timeline_Event_Instant:
return "Instant";
case Dart_Timeline_Event_Async_Begin:
return "AsyncBegin";
case Dart_Timeline_Event_Async_End:
return "AsyncEnd";
case Dart_Timeline_Event_Async_Instant:
return "AsyncInstant";
case Dart_Timeline_Event_Counter:
return "Counter";
case Dart_Timeline_Event_Flow_Begin:
return "FlowBegin";
case Dart_Timeline_Event_Flow_Step:
return "FlowStep";
case Dart_Timeline_Event_Flow_End:
return "FlowEnd";
default:
return "";
}
}
extern "C" void Dart_TimelineEvent(const char* label, int64_t timestamp0,
int64_t timestamp1_or_async_id,
Dart_Timeline_Event_Type type,
intptr_t argument_count,
const char** argument_names,
const char** argument_values) {
static int64_t timestamp_begin = timestamp0;
if (timestamp1_or_async_id) {
uiwidgets::UIWidgetsSystem::GetInstancePtr()->printf_console(
"uiwidgets Timeline [Thread:%d] [%lld ms] [%lld] [%s]: %s\n",
GetCurrentThreadId(), (timestamp0 - timestamp_begin) / 1000,
timestamp1_or_async_id, TimelineEventToString(type), label);
} else {
uiwidgets::UIWidgetsSystem::GetInstancePtr()->printf_console(
"uiwidgets Timeline [Thread:%d] [%d ms] [%s]: %s\n",
GetCurrentThreadId(), (timestamp0 - timestamp_begin) / 1000,
TimelineEventToString(type), label);
}
}

1
engine/src/runtime/mono_api.h


void* Mono_CurrentIsolateData();
void Mono_ThrowException(const char* exception);
void Mono_Shutdown(Mono_Isolate isolate);
int64_t Mono_TimelineGetMicros();
void Mono_NotifyIdle(int64_t deadline);

2
engine/src/runtime/mono_isolate.cc


FML_DCHECK(Mono_CurrentIsolate() == nullptr);
}
return true;
return true;
}
MonoIsolate::AutoFireClosure::AutoFireClosure(const fml::closure& closure)

36
engine/src/shell/common/shell.cc


//#include "shell/common/skia_event_tracer_impl.h"
//#include "shell/common/switches.h"
#include "shell/common/vsync_waiter.h"
#include "shell/platform/embedder/embedder_task_runner.h"
namespace uiwidgets {

fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetUITaskRunner(),
fml::MakeCopyable([engine = std::move(engine_), &ui_latch]() mutable {
engine.reset();
ui_latch.Signal();
}));
fml::MakeCopyable(
[engine = std::move(engine_), &ui_latch,
task_runner = task_runners_.GetUITaskRunner()]() mutable {
engine.reset();
ui_latch.Signal();
// assume it's always EmbedderTaskRunner
static_cast<EmbedderTaskRunner*>(task_runner.get())->Terminate();
}));
fml::MakeCopyable([rasterizer = std::move(rasterizer_),
weak_factory_gpu = std::move(weak_factory_gpu_),
&gpu_latch]() mutable {
rasterizer.reset();
weak_factory_gpu.reset();
gpu_latch.Signal();
}));
fml::MakeCopyable(
[rasterizer = std::move(rasterizer_),
weak_factory_gpu = std::move(weak_factory_gpu_), &gpu_latch,
task_runner = task_runners_.GetRasterTaskRunner()]() mutable {
rasterizer.reset();
weak_factory_gpu.reset();
gpu_latch.Signal();
// assume it's always EmbedderTaskRunner
static_cast<EmbedderTaskRunner*>(task_runner.get())->Terminate();
}));
gpu_latch.Wait();
fml::TaskRunner::RunNowOrPostTask(

if (rasterizer) {
rasterizer->Teardown();
}
// Step 2: Next, tell the IO thread to complete its remaining work.
fml::TaskRunner::RunNowOrPostTask(io_task_runner, io_task);
};

task_runners_.GetPlatformTaskRunner();
auto ui_task = [engine = engine_->GetWeakPtr(),
ui_task_runner = task_runners_.GetUITaskRunner(),
// Step 1: Next, tell the raster thread that its rasterizer should suspend
// access to the underlying surface.
if (should_post_raster_task) {

// surface is about to go away.
fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task);
latch.Wait();
if (!should_post_raster_task) {
// See comment on should_post_raster_task, in this case the raster_task
// wasn't executed, and we just run it here as the platform thread

16
engine/src/shell/platform/embedder/embedder_task_runner.cc


{
// Release the lock before the jump via the dispatch table.
std::scoped_lock lock(tasks_mutex_);
if (terminated_) {
return;
}
baton = ++last_baton_;
pending_tasks_[baton] = task;
}

FML_DCHECK(task);
task();
return true;
}
void EmbedderTaskRunner::Terminate() {
FML_DCHECK(RunsTasksOnCurrentThread());
std::unordered_map<uint64_t, fml::closure> local_tasks;
{
std::scoped_lock lock(tasks_mutex_);
terminated_ = true;
pending_tasks_.swap(local_tasks);
}
}
// |fml::TaskRunner|

3
engine/src/shell/platform/embedder/embedder_task_runner.h


bool PostTask(uint64_t baton);
void Terminate();
private:
const size_t embedder_identifier_;
DispatchTable dispatch_table_;

fml::TaskQueueId placeholder_id_;
bool terminated_ = false;
void PostTask(const fml::closure& task) override;

7
engine/src/shell/platform/unity/uiwidgets_system.h


#include <flutter/fml/closure.h>
#include <chrono>
#include <cstdarg>
#include <set>
#include <unordered_map>

void UnregisterPanel(UIWidgetsPanel* panel);
void PostTaskToGfxWorker(const fml::closure& task);
void printf_console(const char* log, ...) {
va_list vl;
va_start(vl, log);
unity_uiwidgets_->printf_consolev(log, vl);
va_end(vl);
}
void BindUnityInterfaces(IUnityInterfaces* unity_interfaces);
void UnBindUnityInterfaces();

3
engine/third_party/Unity/IUnityUIWidgets.h


#pragma once
#include "IUnityInterface.h"
#include "IUnityInterface.h"
namespace UnityUIWidgets {
typedef void (*VoidCallback)();

virtual void SetWakeUpCallback(VoidCallback callback) = 0;
virtual void IssuePluginEventAndData(UnityRenderingEventAndData callback,
int eventId, void* data) = 0;
virtual void printf_consolev(const char* log, va_list alist) = 0;
};
} // namespace UnityUIWidgets

正在加载...
取消
保存