浏览代码

draft

/siyaoH-1.17-PlatformMessage
Kevin Gu 4 年前
当前提交
b1009c12
共有 87 个文件被更改,包括 8146 次插入424 次删除
  1. 2
      com.unity.uiwidgets/.editorconfig
  2. 56
      com.unity.uiwidgets/Runtime/ui/geometry.cs
  3. 8
      com.unity.uiwidgets/Runtime/ui/painting/painting.cs
  4. 56
      engine/Build.bee.cs
  5. 2
      engine/src/common/settings.h
  6. 2
      engine/src/flow/embedded_views.h
  7. 433
      engine/src/lib/ui/painting/canvas.cc
  8. 83
      engine/src/lib/ui/painting/canvas.h
  9. 2
      engine/src/lib/ui/painting/image_encoding.cc
  10. 49
      engine/src/lib/ui/painting/picture.cc
  11. 8
      engine/src/lib/ui/painting/picture.h
  12. 19
      engine/src/lib/ui/painting/picture_recorder.cc
  13. 13
      engine/src/lib/ui/window/platform_message.cc
  14. 3
      engine/src/lib/ui/window/platform_message.h
  15. 415
      engine/src/lib/ui/window/window.cc
  16. 72
      engine/src/lib/ui/window/window.h
  17. 2
      engine/src/render_api_d3d11.cc
  18. 25
      engine/src/runtime/mono_api.cc
  19. 8
      engine/src/runtime/mono_api.h
  20. 8
      engine/src/runtime/mono_isolate.cc
  21. 2
      engine/src/runtime/mono_isolate.h
  22. 42
      engine/src/shell/common/animator.cc
  23. 6
      engine/src/shell/common/animator.h
  24. 194
      com.unity.uiwidgets/Runtime/ui/painting/native_bindings.cs
  25. 3
      com.unity.uiwidgets/Runtime/ui/painting/native_bindings.cs.meta
  26. 277
      com.unity.uiwidgets/Runtime/ui2/compositing.cs
  27. 3
      com.unity.uiwidgets/Runtime/ui2/compositing.cs.meta
  28. 154
      com.unity.uiwidgets/Runtime/ui2/hooks.cs
  29. 3
      com.unity.uiwidgets/Runtime/ui2/hooks.cs.meta
  30. 62
      com.unity.uiwidgets/Runtime/ui2/isolate.cs
  31. 64
      com.unity.uiwidgets/Runtime/ui2/native_bindings.cs
  32. 1001
      com.unity.uiwidgets/Runtime/ui2/painting.cs
  33. 310
      com.unity.uiwidgets/Runtime/ui2/window.cs
  34. 3
      com.unity.uiwidgets/Runtime/ui2/window.cs.meta
  35. 39
      engine/src/lib/ui/painting/color_filter.cc
  36. 30
      engine/src/lib/ui/painting/color_filter.h
  37. 12
      engine/src/lib/ui/painting/engine_layer.cc
  38. 27
      engine/src/lib/ui/painting/engine_layer.h
  39. 109
      engine/src/lib/ui/painting/gradient.cc
  40. 45
      engine/src/lib/ui/painting/gradient.h
  41. 37
      engine/src/lib/ui/painting/image_filter.cc
  42. 29
      engine/src/lib/ui/painting/image_filter.h
  43. 26
      engine/src/lib/ui/painting/image_shader.cc
  44. 26
      engine/src/lib/ui/painting/image_shader.h
  45. 27
      engine/src/lib/ui/painting/matrix.cc
  46. 9
      engine/src/lib/ui/painting/matrix.h
  47. 150
      engine/src/lib/ui/painting/paint.cc
  48. 20
      engine/src/lib/ui/painting/paint.h
  49. 353
      engine/src/lib/ui/painting/path.cc
  50. 71
      engine/src/lib/ui/painting/path.h
  51. 21
      engine/src/lib/ui/painting/rrect.cc
  52. 14
      engine/src/lib/ui/painting/rrect.h
  53. 9
      engine/src/lib/ui/painting/shader.cc
  54. 28
      engine/src/lib/ui/painting/shader.h
  55. 89
      engine/src/lib/ui/painting/vertices.cc
  56. 30
      engine/src/lib/ui/painting/vertices.h
  57. 12
      engine/src/lib/ui/window/pointer_data.cc
  58. 83
      engine/src/lib/ui/window/pointer_data.h
  59. 19
      engine/src/lib/ui/window/pointer_data_packet.cc
  60. 27
      engine/src/lib/ui/window/pointer_data_packet.h
  61. 281
      engine/src/lib/ui/window/pointer_data_packet_converter.cc
  62. 50
      engine/src/lib/ui/window/pointer_data_packet_converter.h
  63. 68
      engine/src/lib/ui/window/viewport_metrics.cc
  64. 79
      engine/src/lib/ui/window/viewport_metrics.h
  65. 270
      engine/src/runtime/runtime_controller.cc
  66. 123
      engine/src/runtime/runtime_controller.h
  67. 7
      engine/src/runtime/runtime_delegate.cc
  68. 30
      engine/src/runtime/runtime_delegate.h
  69. 8
      engine/src/runtime/window_data.cc
  70. 27
      engine/src/runtime/window_data.h
  71. 502
      engine/src/shell/common/engine.cc
  72. 149
      engine/src/shell/common/engine.h
  73. 119
      engine/src/shell/common/platform_view.cc
  74. 80
      engine/src/shell/common/platform_view.h
  75. 57
      engine/src/shell/common/pointer_data_dispatcher.cc
  76. 72
      engine/src/shell/common/pointer_data_dispatcher.h
  77. 1001
      engine/src/shell/common/shell.cc
  78. 525
      engine/src/shell/common/shell.h
  79. 64
      engine/src/lib/ui/compositing/scene.cc
  80. 39
      engine/src/lib/ui/compositing/scene.h
  81. 202
      engine/src/lib/ui/compositing/scene_builder.cc
  82. 85
      engine/src/lib/ui/compositing/scene_builder.h
  83. 0
      /com.unity.uiwidgets/Runtime/ui2/isolate.cs.meta
  84. 0
      /com.unity.uiwidgets/Runtime/ui2/native_bindings.cs.meta
  85. 0
      /com.unity.uiwidgets/Runtime/ui2/painting.cs.meta

2
com.unity.uiwidgets/.editorconfig


# use this.{} for all instance members
csharp_instance_members_qualify_members=all
csharp_instance_members_qualify_members=none
# all braces start at the end of a line

56
com.unity.uiwidgets/Runtime/ui/geometry.cs


);
}
internal float[] _value32 => new[] {left, top, right, bottom};
public readonly float left;
public readonly float top;
public readonly float right;

topLeft, topRight, bottomRight, bottomLeft);
}
internal float[] _value32 => new[] {
left,
top,
right,
bottom,
tlRadiusX,
tlRadiusY,
trRadiusX,
trRadiusY,
brRadiusX,
brRadiusY,
blRadiusX,
blRadiusY,
};
public readonly float left;
public readonly float top;
public readonly float right;

public float longestSide {
get { return Mathf.Max(this.width.abs(), this.height.abs()); }
}
public bool hasNaN => left.isNaN() || top.isNaN() || right.isNaN() || bottom.isNaN() ||
trRadiusX.isNaN() || trRadiusY.isNaN() || tlRadiusX.isNaN() || tlRadiusY.isNaN() ||
brRadiusX.isNaN() || brRadiusY.isNaN() || blRadiusX.isNaN() || blRadiusY.isNaN();
public Offset center {
get { return new Offset(this.left + this.width / 2.0f, this.top + this.height / 2.0f); }

$"bottomLeft: {this.blRadius}" +
")";
}
}
public class RSTransform {
RSTransform(float scos, float ssin, float tx, float ty) {
_value[0] = scos;
_value[1] = ssin;
_value[2] = tx;
_value[3] = ty;
}
public static RSTransform fromComponents(
float rotation,
float scale,
float anchorX,
float anchorY,
float translateX,
float translateY
) {
float scos = Mathf.Cos(rotation) * scale;
float ssin = Mathf.Sin(rotation) * scale;
float tx = translateX + -scos * anchorX + ssin * anchorY;
float ty = translateY + -ssin * anchorX - scos * anchorY;
return new RSTransform(scos, ssin, tx, ty);
}
float[] _value = new float[4];
public float scos => _value[0];
public float ssin => _value[1];
public float tx => _value[2];
public float ty => _value[3];
}
}

8
com.unity.uiwidgets/Runtime/ui/painting/painting.cs


using System;
using System.Linq;
using Unity.UIWidgets.foundation;
using UnityEngine;

internal static Color _scaleAlpha(Color a, float factor) {
return a.withAlpha((a.alpha * factor).round().clamp(0, 255));
}
internal static bool _matrix4IsValid(float[] matrix4) {
D.assert(matrix4 != null, () => "Matrix4 argument was null.");
D.assert(matrix4.Length == 16, () => "Matrix4 must have 16 entries.");
D.assert(matrix4.All((float value) => value.isFinite()), () => "Matrix4 entries must be finite.");
return true;
}
}

56
engine/Build.bee.cs


"src/flow/texture.cc",
"src/flow/texture.h",
"src/lib/ui/compositing/scene.cc",
"src/lib/ui/compositing/scene.h",
"src/lib/ui/compositing/scene_builder.cc",
"src/lib/ui/compositing/scene_builder.h",
"src/lib/ui/painting/color_filter.cc",
"src/lib/ui/painting/color_filter.h",
"src/lib/ui/painting/engine_layer.cc",
"src/lib/ui/painting/engine_layer.h",
"src/lib/ui/painting/gradient.cc",
"src/lib/ui/painting/gradient.h",
"src/lib/ui/painting/image.cc",
"src/lib/ui/painting/image.h",
"src/lib/ui/painting/image_decoder.cc",

"src/lib/ui/painting/image_filter.cc",
"src/lib/ui/painting/image_filter.h",
"src/lib/ui/painting/image_shader.cc",
"src/lib/ui/painting/image_shader.h",
"src/lib/ui/painting/matrix.cc",
"src/lib/ui/painting/matrix.h",
"src/lib/ui/painting/path.cc",
"src/lib/ui/painting/path.h",
"src/lib/ui/painting/paint.cc",
"src/lib/ui/painting/paint.h",
"src/lib/ui/painting/rrect.cc",
"src/lib/ui/painting/rrect.h",
"src/lib/ui/painting/shader.cc",
"src/lib/ui/painting/shader.h",
"src/lib/ui/painting/vertices.cc",
"src/lib/ui/painting/vertices.h",
"src/lib/ui/window/platform_message.cc",
"src/lib/ui/window/platform_message.h",
"src/lib/ui/window/platform_message_response.cc",
"src/lib/ui/window/platform_message_response.h",
"src/lib/ui/window/pointer_data.cc",
"src/lib/ui/window/pointer_data.h",
"src/lib/ui/window/pointer_data_packet.cc",
"src/lib/ui/window/pointer_data_packet.h",
"src/lib/ui/window/pointer_data_packet_converter.cc",
"src/lib/ui/window/pointer_data_packet_converter.h",
"src/lib/ui/window/viewport_metrics.cc",
"src/lib/ui/window/viewport_metrics.h",
"src/lib/ui/window/window.cc",
"src/lib/ui/window/window.h",
"src/lib/ui/io_manager.h",
"src/lib/ui/snapshot_delegate.h",

"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_delegate.cc",
"src/runtime/runtime_delegate.h",
"src/runtime/window_data.cc",
"src/runtime/window_data.h",
//"src/shell/common/engine.cc",
//"src/shell/common/engine.h",
"src/shell/common/platform_view.cc",
"src/shell/common/platform_view.h",
"src/shell/common/pointer_data_dispatcher.cc",
"src/shell/common/pointer_data_dispatcher.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",

2
engine/src/common/settings.h


bool enable_software_rendering = false;
bool skia_deterministic_rendering_on_cpu = false;
bool verbose_logging = false;
std::string log_tag = "flutter";
std::string log_tag = "uiwidgets";
// The icu_initialization_required setting does not have a corresponding
// switch because it is intended to be decided during build time, not runtime.

2
engine/src/flow/embedded_views.h


const SkPath& GetPath() const { return *path_; }
const SkMatrix& GetMatrix() const { return matrix_; }
const int& GetAlpha() const { return alpha_; }
float GetAlphaFloat() const { return (alpha_ / 255.0); }
float GetAlphaFloat() const { return (alpha_ / 255.0f); }
bool operator==(const Mutator& other) const {
if (type_ != other.type_) {

433
engine/src/lib/ui/painting/canvas.cc


#include <math.h>
#include "flow/layers/physical_shape_layer.h"
#include "image.h"
#include "lib/ui/painting/image.h"
#include "lib/ui/ui_mono_state.h"
#include "matrix.h"
fml::RefPtr<Canvas> Canvas::Create(PictureRecorder* recorder, double left,
double top, double right, double bottom) {
fml::RefPtr<Canvas> Canvas::Create(PictureRecorder* recorder, float left,
float top, float right, float bottom) {
FML_DCHECK(!recorder->isRecording()); // verified by Dart code
FML_DCHECK(!recorder->isRecording());
fml::RefPtr<Canvas> canvas = fml::MakeRefCounted<Canvas>(
recorder->BeginRecording(SkRect::MakeLTRB(left, top, right, bottom)));
recorder->set_canvas(canvas);

Canvas::Canvas(SkCanvas* canvas) : canvas_(canvas) {}
Canvas::~Canvas() {}
void Canvas::save() {
if (!canvas_) return;
canvas_->save();
}
void Canvas::saveLayerWithoutBounds(const Paint& paint) {
if (!canvas_) return;
canvas_->saveLayer(nullptr, paint.paint());
}
void Canvas::saveLayer(float left, float top, float right, float bottom,
const Paint& paint) {
if (!canvas_) return;
SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
canvas_->saveLayer(&bounds, paint.paint());
}
void Canvas::restore() {
if (!canvas_) return;
canvas_->restore();
}
int Canvas::getSaveCount() {
if (!canvas_) return 0;
return canvas_->getSaveCount();
}
void Canvas::translate(float dx, float dy) {
if (!canvas_) return;
canvas_->translate(dx, dy);
}
void Canvas::scale(float sx, float sy) {
if (!canvas_) return;
canvas_->scale(sx, sy);
}
void Canvas::rotate(float radians) {
if (!canvas_) return;
canvas_->rotate(radians * 180.0 / M_PI);
}
void Canvas::skew(float sx, float sy) {
if (!canvas_) return;
canvas_->skew(sx, sy);
}
void Canvas::transform(float* matrix4) {
if (!canvas_) return;
canvas_->concat(ToSkMatrix(matrix4));
}
void Canvas::clipRect(float left, float top, float right, float bottom,
SkClipOp clipOp, bool doAntiAlias) {
if (!canvas_) return;
canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp,
doAntiAlias);
}
void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) {
if (!canvas_) return;
canvas_->clipRRect(rrect.sk_rrect, doAntiAlias);
}
void Canvas::clipPath(const CanvasPath* path, bool doAntiAlias) {
if (!canvas_) return;
if (!path)
Mono_ThrowException("Canvas.clipPath called with non-genuine Path.");
canvas_->clipPath(path->path(), doAntiAlias);
}
void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) {
if (!canvas_) return;
canvas_->drawColor(color, blend_mode);
}
void Canvas::drawLine(float x1, float y1, float x2, float y2,
const Paint& paint) {
if (!canvas_) return;
canvas_->drawLine(x1, y1, x2, y2, *paint.paint());
}
void Canvas::drawPaint(const Paint& paint) {
if (!canvas_) return;
canvas_->drawPaint(*paint.paint());
}
void Canvas::drawRect(float left, float top, float right, float bottom,
const Paint& paint) {
if (!canvas_) return;
canvas_->drawRect(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
}
void Canvas::drawRRect(const RRect& rrect, const Paint& paint) {
if (!canvas_) return;
canvas_->drawRRect(rrect.sk_rrect, *paint.paint());
}
void Canvas::drawDRRect(const RRect& outer, const RRect& inner,
const Paint& paint) {
if (!canvas_) return;
canvas_->drawDRRect(outer.sk_rrect, inner.sk_rrect, *paint.paint());
}
void Canvas::drawOval(float left, float top, float right, float bottom,
const Paint& paint) {
if (!canvas_) return;
canvas_->drawOval(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
}
void Canvas::drawCircle(float x, float y, float radius, const Paint& paint) {
if (!canvas_) return;
canvas_->drawCircle(x, y, radius, *paint.paint());
}
void Canvas::drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter,
const Paint& paint) {
if (!canvas_) return;
canvas_->drawArc(SkRect::MakeLTRB(left, top, right, bottom),
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
useCenter, *paint.paint());
}
void Canvas::drawPath(const CanvasPath* path, const Paint& paint) {
if (!canvas_) return;
if (!path)
Mono_ThrowException("Canvas.drawPath called with non-genuine Path.");
canvas_->drawPath(path->path(), *paint.paint());
}
void Canvas::drawImage(const CanvasImage* image, float x, float y,
const Paint& paint) {
if (!canvas_) return;
if (!image)
Mono_ThrowException("Canvas.drawImage called with non-genuine Image.");
canvas_->drawImage(image->image(), x, y, paint.paint());
}
void Canvas::drawImageRect(const CanvasImage* image, float src_left,
float src_top, float src_right, float src_bottom,
float dst_left, float dst_top, float dst_right,
float dst_bottom, const Paint& paint) {
if (!canvas_) return;
if (!image)
Mono_ThrowException("Canvas.drawImageRect called with non-genuine Image.");
SkRect src = SkRect::MakeLTRB(src_left, src_top, src_right, src_bottom);
SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
canvas_->drawImageRect(image->image(), src, dst, paint.paint(),
SkCanvas::kFast_SrcRectConstraint);
}
void Canvas::drawImageNine(const CanvasImage* image, float center_left,
float center_top, float center_right,
float center_bottom, float dst_left, float dst_top,
float dst_right, float dst_bottom,
const Paint& paint) {
if (!canvas_) return;
if (!image)
Mono_ThrowException("Canvas.drawImageNine called with non-genuine Image.");
SkRect center =
SkRect::MakeLTRB(center_left, center_top, center_right, center_bottom);
SkIRect icenter;
center.round(&icenter);
SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
canvas_->drawImageNine(image->image(), icenter, dst, paint.paint());
}
void Canvas::drawPicture(Picture* picture) {
if (!canvas_) return;
if (!picture)
Mono_ThrowException("Canvas.drawPicture called with non-genuine Picture.");
canvas_->drawPicture(picture->picture().get());
}
void Canvas::drawPoints(const Paint& paint, SkCanvas::PointMode point_mode,
float* points, int points_length) {
if (!canvas_) return;
static_assert(sizeof(SkPoint) == sizeof(float) * 2,
"SkPoint doesn't use floats.");
canvas_->drawPoints(point_mode,
points_length / 2, // SkPoints have two floats.
reinterpret_cast<const SkPoint*>(points), *paint.paint());
}
void Canvas::drawVertices(const Vertices* vertices, SkBlendMode blend_mode,
const Paint& paint) {
if (!canvas_) return;
if (!vertices)
Mono_ThrowException(
"Canvas.drawVertices called with non-genuine Vertices.");
canvas_->drawVertices(vertices->vertices(), blend_mode, *paint.paint());
}
void Canvas::drawAtlas(const Paint& paint, CanvasImage* atlas,
float* transforms, int transforms_length, float* rects,
int rects_length, int32_t* colors, int colors_length,
SkBlendMode blend_mode, float* cull_rect) {
if (!canvas_) return;
if (!atlas)
Mono_ThrowException(
"Canvas.drawAtlas or Canvas.drawRawAtlas called with "
"non-genuine Image.");
sk_sp<SkImage> skImage = atlas->image();
static_assert(sizeof(SkRSXform) == sizeof(float) * 4,
"SkRSXform doesn't use floats.");
static_assert(sizeof(SkRect) == sizeof(float) * 4,
"SkRect doesn't use floats.");
canvas_->drawAtlas(
skImage.get(), reinterpret_cast<const SkRSXform*>(transforms),
reinterpret_cast<const SkRect*>(rects),
reinterpret_cast<const SkColor*>(colors),
rects_length / 4, // SkRect have four floats.
blend_mode, reinterpret_cast<const SkRect*>(cull_rect), paint.paint());
}
void Canvas::drawShadow(const CanvasPath* path, SkColor color, float elevation,
bool transparentOccluder) {
if (!path)
Mono_ThrowException("Canvas.drawShader called with non-genuine Path.");
SkScalar dpr = 1.f;
// TODO:
// UIMonoState::Current()->window()->viewport_metrics().device_pixel_ratio;
PhysicalShapeLayer::DrawShadow(canvas_, path->path(), color, elevation,
transparentOccluder, dpr);
}
void Canvas::Clear() { canvas_ = nullptr; }
bool Canvas::IsRecording() const { return !!canvas_; }
UIWIDGETS_API(Canvas*)
Canvas_constructor(PictureRecorder* recorder, float left, float top,
float right, float bottom) {
const auto canvas = Canvas::Create(recorder, left, top, right, bottom);
canvas->AddRef();
return canvas.get();
}
UIWIDGETS_API(void) Canvas_dispose(Canvas* ptr) { ptr->Release(); }
UIWIDGETS_API(void) Canvas_save(Canvas* ptr) { ptr->save(); }
UIWIDGETS_API(void)
Canvas_saveLayerWithoutBounds(Canvas* ptr, void** paint_objects,
uint8_t* paint_data) {
const Paint paint(paint_objects, paint_data);
ptr->saveLayerWithoutBounds(paint);
}
UIWIDGETS_API(void)
Canvas_saveLayer(Canvas* ptr, float left, float top, float right, float bottom,
void** paint_objects, uint8_t* paint_data) {
ptr->saveLayer(left, top, right, bottom, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void) Canvas_restore(Canvas* ptr) { ptr->restore(); }
UIWIDGETS_API(int) Canvas_getSaveCount(Canvas* ptr) {
return ptr->getSaveCount();
}
UIWIDGETS_API(void) Canvas_translate(Canvas* ptr, float x, float y) {
ptr->translate(x, y);
}
UIWIDGETS_API(void)
Canvas_scale(Canvas* ptr, float sx, float sy) { ptr->scale(sx, sy); }
UIWIDGETS_API(void)
Canvas_rotate(Canvas* ptr, float radians) { ptr->rotate(radians); }
UIWIDGETS_API(void)
Canvas_skew(Canvas* ptr, float sx, float sy) { ptr->skew(sx, sy); }
UIWIDGETS_API(void)
Canvas_transform(Canvas* ptr, float* matrix4) { ptr->transform(matrix4); }
UIWIDGETS_API(void)
Canvas_clipRect(Canvas* ptr, float left, float top, float right, float bottom,
SkClipOp clipOp, bool doAntiAlias) {
ptr->clipRect(left, top, right, bottom, clipOp, doAntiAlias);
}
UIWIDGETS_API(void)
Canvas_clipRRect(Canvas* ptr, float* rrect, bool doAntiAlias) {
ptr->clipRRect(RRect(rrect), doAntiAlias);
}
UIWIDGETS_API(void)
Canvas_clipPath(Canvas* ptr, CanvasPath* path, bool doAntiAlias) {
ptr->clipPath(path, doAntiAlias);
}
UIWIDGETS_API(void)
Canvas_drawColor(Canvas* ptr, SkColor color, SkBlendMode blendMode) {
ptr->drawColor(color, blendMode);
}
UIWIDGETS_API(void)
Canvas_drawLine(Canvas* ptr, float x1, float y1, float x2, float y2,
void** paint_objects, uint8_t* paint_data) {
ptr->drawLine(x1, y1, x2, y2, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawPaint(Canvas* ptr, void** paint_objects, uint8_t* paint_data) {
ptr->drawPaint(Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawRect(Canvas* ptr, float left, float top, float right, float bottom,
void** paint_objects, uint8_t* paint_data) {
ptr->drawRect(left, top, right, bottom, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawRRect(Canvas* ptr, float* rrect, void** paint_objects,
uint8_t* paint_data) {
ptr->drawRRect(RRect(rrect), Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawDRRect(Canvas* ptr, float* outer, float* inner, void** paint_objects,
uint8_t* paint_data) {
ptr->drawDRRect(RRect(outer), RRect(inner), Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawOval(Canvas* ptr, float left, float top, float right, float bottom,
void** paint_objects, uint8_t* paint_data) {
ptr->drawOval(left, top, right, bottom, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawCircle(Canvas* ptr, float x, float y, float radius,
void** paint_objects, uint8_t* paint_data) {
ptr->drawCircle(x, y, radius, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawArc(Canvas* ptr, float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter,
void** paint_objects, uint8_t* paint_data) {
ptr->drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter,
Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawPath(Canvas* ptr, CanvasPath* path, void** paint_objects,
uint8_t* paint_data) {
ptr->drawPath(path, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawImage(Canvas* ptr, CanvasImage* image, float x, float y,
void** paint_objects, uint8_t* paint_data) {
ptr->drawImage(image, x, y, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawImageRect(Canvas* ptr, CanvasImage* image, float srcLeft,
float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight,
float dstBottom, void** paint_objects,
uint8_t* paint_data) {
ptr->drawImageRect(image, srcLeft, srcTop, srcRight, srcBottom, dstLeft,
dstTop, dstRight, dstBottom,
Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawImageNine(Canvas* ptr, CanvasImage* image, float centerLeft,
float centerTop, float centerRight, float centerBottom,
float dstLeft, float dstTop, float dstRight,
float dstBottom, void** paint_objects,
uint8_t* paint_data) {
ptr->drawImageNine(image, centerLeft, centerTop, centerRight, centerBottom,
dstLeft, dstTop, dstRight, dstBottom,
Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawPicture(Canvas* ptr, Picture* picture) { ptr->drawPicture(picture); }
UIWIDGETS_API(void)
Canvas_drawPoints(Canvas* ptr, void** paint_objects, uint8_t* paint_data,
SkCanvas::PointMode pointMode, float* points,
int pointsLength) {
ptr->drawPoints(Paint(paint_objects, paint_data), pointMode, points,
pointsLength);
}
UIWIDGETS_API(void)
Canvas_drawVertices(Canvas* ptr, Vertices* vertices, SkBlendMode blendMode,
void** paint_objects, uint8_t* paint_data) {
ptr->drawVertices(vertices, blendMode, Paint(paint_objects, paint_data));
}
UIWIDGETS_API(void)
Canvas_drawAtlas(Canvas* ptr, void** paint_objects, uint8_t* paint_data,
CanvasImage* atlas, float* rstTransforms,
int rstTransformsLength, float* rects, int rectsLength,
int32_t* colors, int colorsLength, SkBlendMode blendMode,
float* cullRect) {
ptr->drawAtlas(Paint(paint_objects, paint_data), atlas, rstTransforms,
rstTransformsLength, rects, rectsLength, colors, colorsLength,
blendMode, cullRect);
}
UIWIDGETS_API(void)
Canvas_drawShadow(Canvas* ptr, CanvasPath* path, SkColor color, float elevation,
bool transparentOccluder) {
ptr->drawShadow(path, color, elevation, transparentOccluder);
}
} // namespace uiwidgets

83
engine/src/lib/ui/painting/canvas.h


#include <flutter/fml/memory/ref_ptr.h>
#include "include/core/SkCanvas.h"
#include "lib/ui/painting/picture.h"
#include "lib/ui/painting/picture_recorder.h"
#include "picture.h"
#include "picture_recorder.h"
#include "paint.h"
#include "path.h"
#include "picture.h"
#include "picture_recorder.h"
#include "rrect.h"
#include "vertices.h"
class PictureRecorder;
class CanvasImage;
static fml::RefPtr<Canvas> Create(PictureRecorder* recorder, double left,
double top, double right, double bottom);
static fml::RefPtr<Canvas> Create(PictureRecorder* recorder, float left,
float top, float right, float bottom);
void save();
void saveLayerWithoutBounds(const Paint& paint);
void saveLayer(float left, float top, float right, float bottom,
const Paint& paint);
void restore();
int getSaveCount();
void translate(float dx, float dy);
void scale(float sx, float sy);
void rotate(float radians);
void skew(float sx, float sy);
void transform(float* matrix4);
void clipRect(float left, float top, float right, float bottom,
SkClipOp clipOp, bool doAntiAlias = true);
void clipRRect(const RRect& rrect, bool doAntiAlias = true);
void clipPath(const CanvasPath* path, bool doAntiAlias = true);
void drawColor(SkColor color, SkBlendMode blend_mode);
void drawLine(float x1, float y1, float x2, float y2, const Paint& paint);
void drawPaint(const Paint& paint);
void drawRect(float left, float top, float right, float bottom,
const Paint& paint);
void drawRRect(const RRect& rrect, const Paint& paint);
void drawDRRect(const RRect& outer, const RRect& inner, const Paint& paint);
void drawOval(float left, float top, float right, float bottom,
const Paint& paint);
void drawCircle(float x, float y, float radius, const Paint& paint);
void drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter,
const Paint& paint);
void drawPath(const CanvasPath* path, const Paint& paint);
void drawImage(const CanvasImage* image, float x, float y,
const Paint& paint);
void drawImageRect(const CanvasImage* image, float src_left, float src_top,
float src_right, float src_bottom, float dst_left,
float dst_top, float dst_right, float dst_bottom,
const Paint& paint);
void drawImageNine(const CanvasImage* image, float center_left,
float center_top, float center_right,
float center_bottom, float dst_left, float dst_top,
float dst_right, float dst_bottom, const Paint& paint);
void drawPicture(Picture* picture);
// The paint argument is first for the following functions because Paint
// unwraps a number of C++ objects. Once we create a view unto a
// Float32List, we cannot re-enter the VM to unwrap objects. That means we
// either need to process the paint argument first.
void drawPoints(const Paint& paint, SkCanvas::PointMode point_mode,
float* points, int points_length);
void drawVertices(const Vertices* vertices, SkBlendMode blend_mode,
const Paint& paint);
void drawAtlas(const Paint& paint, CanvasImage* atlas, float* transforms,
int transforms_length, float* rects, int rects_length,
int32_t* colors, int colors_length, SkBlendMode blend_mode,
float* cull_rect);
void drawShadow(const CanvasPath* path, SkColor color, float elevation,
bool transparentOccluder);
SkCanvas* canvas() const { return canvas_; }
void Clear();
bool IsRecording() const;
private:
explicit Canvas(SkCanvas* canvas);

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


}
sk_sp<SkData> EncodeImage(sk_sp<SkImage> raster_image, ImageByteFormat format) {
TRACE_EVENT0("flutter", __FUNCTION__);
TRACE_EVENT0("uiwidgets", __FUNCTION__);
if (!raster_image) {
return nullptr;

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


void Picture::dispose() {}
size_t Picture::GetAllocationSize() {
if (auto picture = picture_.get()) {
return picture->approximateBytesUsed();
} else {
return sizeof(Picture);
}
}
const char* Picture::RasterizeToImage(sk_sp<SkPicture> picture, uint32_t width,
uint32_t height,
RawImageCallback raw_image_callback,

return "Image dimensions for scene were invalid.";
}
auto* dart_state = UIMonoState::Current();
auto dart_state_weak = dart_state->GetWeakPtr();
auto* mono_state = UIMonoState::Current();
auto mono_state_weak = mono_state->GetWeakPtr();
auto unref_queue = dart_state->GetSkiaUnrefQueue();
auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner();
auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner();
auto snapshot_delegate = dart_state->GetSnapshotDelegate();
auto unref_queue = mono_state->GetSkiaUnrefQueue();
auto ui_task_runner = mono_state->GetTaskRunners().GetUITaskRunner();
auto raster_task_runner = mono_state->GetTaskRunners().GetRasterTaskRunner();
auto snapshot_delegate = mono_state->GetSnapshotDelegate();
// We can't create an image on this task runner because we don't have a
// graphics context. Even if we did, it would be slow anyway. Also, this

auto picture_bounds = SkISize::Make(width, height);
auto ui_task = fml::MakeCopyable([dart_state_weak, raw_image_callback,
auto ui_task = fml::MakeCopyable([mono_state_weak, raw_image_callback,
auto dart_state = dart_state_weak.lock();
if (!dart_state) {
auto mono_state = mono_state_weak.lock();
if (!mono_state) {
MonoState::Scope scope(dart_state);
MonoState::Scope scope(mono_state);
if (!raster_image) {
raw_image_callback(callback_handle, nullptr);

auto dart_image = CanvasImage::Create();
dart_image->set_image({std::move(raster_image), std::move(unref_queue)});
auto* raw_dart_image = dart_image.get();
auto mono_image = CanvasImage::Create();
mono_image->set_image({std::move(raster_image), std::move(unref_queue)});
auto* raw_mono_image = mono_image.get();
raw_image_callback(callback_handle, raw_dart_image);
raw_image_callback(callback_handle, raw_mono_image);
});
// Kick things off on the raster rask runner.

});
return nullptr;
}
UIWIDGETS_API(void) Picture_dispose(Picture* ptr) { ptr->Release(); }
UIWIDGETS_API(bool) Picture_GetAllocationSize(Picture* ptr) {
return ptr->GetAllocationSize();
}
UIWIDGETS_API(const char*)
Picture_toImage(Picture* ptr, uint32_t width, uint32_t height,
Picture::RawImageCallback raw_image_callback,
Mono_Handle callback_handle) {
return ptr->toImage(width, height, raw_image_callback, callback_handle);
}
} // namespace uiwidgets

8
engine/src/lib/ui/painting/picture.h


void dispose();
size_t GetAllocationSize();
uint32_t height,
RawImageCallback raw_image_callback,
Mono_Handle callback_handle);
uint32_t height,
RawImageCallback raw_image_callback,
Mono_Handle callback_handle);
private:
explicit Picture(SkiaGPUObject<SkPicture> picture);

19
engine/src/lib/ui/painting/picture_recorder.cc


#include "picture_recorder.h"
#include <Unity/IUnityInterface.h>
#include "lib/ui/painting/canvas.h"
#include "lib/ui/painting/picture.h"
#include "lib/ui/ui_mono_state.h"

PictureRecorder::~PictureRecorder() {}
bool PictureRecorder::isRecording() {
//return canvas_ && canvas_->IsRecording();
return true;
return canvas_ && canvas_->IsRecording();
}
SkCanvas* PictureRecorder::BeginRecording(SkRect bounds) {

fml::RefPtr<Picture> picture = Picture::Create(UIMonoState::CreateGPUObject(
picture_recorder_.finishRecordingAsPicture()));
//canvas_->Clear();
canvas_->Clear();
extern "C" UNITY_INTERFACE_EXPORT PictureRecorder* UNITY_INTERFACE_API
PictureRecorder_constructor() {
UIWIDGETS_API(PictureRecorder*) PictureRecorder_constructor() {
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API
PictureRecorder_dispose(PictureRecorder* ptr) {
UIWIDGETS_API(void) PictureRecorder_dispose(PictureRecorder* ptr) {
extern "C" UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API
PictureRecorder_isRecording(PictureRecorder* ptr) {
UIWIDGETS_API(bool) PictureRecorder_isRecording(PictureRecorder* ptr) {
extern "C" UNITY_INTERFACE_EXPORT void* UNITY_INTERFACE_API
PictureRecorder_endRecording(PictureRecorder* ptr) {
UIWIDGETS_API(Picture*) PictureRecorder_endRecording(PictureRecorder* ptr) {
const auto picture = ptr->endRecording();
picture->AddRef();
return picture.get();

13
engine/src/lib/ui/window/platform_message.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/lib/ui/window/platform_message.h"
#include "platform_message.h"
namespace flutter {
namespace uiwidgets {
PlatformMessage::PlatformMessage(std::string channel,
std::vector<uint8_t> data,
PlatformMessage::PlatformMessage(std::string channel, std::vector<uint8_t> data,
fml::RefPtr<PlatformMessageResponse> response)
: channel_(std::move(channel)),
data_(std::move(data)),

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

3
engine/src/lib/ui/window/platform_message.h


}
private:
PlatformMessage(std::string channel,
std::vector<uint8_t> data,
PlatformMessage(std::string channel, std::vector<uint8_t> data,
fml::RefPtr<PlatformMessageResponse> response);
PlatformMessage(std::string channel,
fml::RefPtr<PlatformMessageResponse> response);

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


#include "window.h"
#include "lib/ui/compositing/scene.h"
#include "lib/ui/ui_dart_state.h"
#include "lib/ui/window/platform_message_response_dart.h"
#include "lib/ui/ui_mono_state.h"
void DefaultRouteName(Dart_NativeArguments args) {
std::string routeName =
UIDartState::Current()->window()->client()->DefaultRouteName();
Dart_SetReturnValue(args, tonic::StdStringToDart(routeName));
}
void ScheduleFrame(Dart_NativeArguments args) {
UIDartState::Current()->window()->client()->ScheduleFrame();
}
typedef Mono_Handle (*Window_constructorCallback)(Window* window);
void Render(Dart_NativeArguments args) {
Dart_Handle exception = nullptr;
Scene* scene =
tonic::DartConverter<Scene*>::FromArguments(args, 1, exception);
if (exception) {
Dart_ThrowException(exception);
return;
}
UIDartState::Current()->window()->client()->Render(scene);
}
static Window_constructorCallback Window_constructor_;
void UpdateSemantics(Dart_NativeArguments args) {
Dart_Handle exception = nullptr;
SemanticsUpdate* update =
tonic::DartConverter<SemanticsUpdate*>::FromArguments(args, 1, exception);
if (exception) {
Dart_ThrowException(exception);
return;
}
UIDartState::Current()->window()->client()->UpdateSemantics(update);
}
typedef void (*Window_disposeCallback)(Mono_Handle handle);
void SetIsolateDebugName(Dart_NativeArguments args) {
Dart_Handle exception = nullptr;
const std::string name =
tonic::DartConverter<std::string>::FromArguments(args, 1, exception);
if (exception) {
Dart_ThrowException(exception);
return;
}
UIDartState::Current()->SetDebugName(name);
}
static Window_disposeCallback Window_dispose_;
void SetNeedsReportTimings(Dart_NativeArguments args) {
Dart_Handle exception = nullptr;
bool value = tonic::DartConverter<bool>::FromArguments(args, 1, exception);
UIDartState::Current()->window()->client()->SetNeedsReportTimings(value);
}
typedef void (*Window_updateWindowMetricsCallback)(
float devicePixelRatio, float width, float height, float depth,
float viewPaddingTop, float viewPaddingRight, float viewPaddingBottom,
float viewPaddingLeft, float viewInsetTop, float viewInsetRight,
float viewInsetBottom, float viewInsetLeft, float systemGestureInsetTop,
float systemGestureInsetRight, float systemGestureInsetBottom,
float systemGestureInsetLeft);
void ReportUnhandledException(Dart_NativeArguments args) {
Dart_Handle exception = nullptr;
static Window_updateWindowMetricsCallback Window_updateWindowMetrics_;
auto error_name =
tonic::DartConverter<std::string>::FromArguments(args, 0, exception);
if (exception) {
Dart_ThrowException(exception);
return;
}
typedef void (*Window_beginFrameCallback)(long microseconds);
static Window_beginFrameCallback Window_beginFrame_;
auto stack_trace =
tonic::DartConverter<std::string>::FromArguments(args, 1, exception);
if (exception) {
Dart_ThrowException(exception);
return;
}
typedef void (*Window_drawFrameCallback)();
static Window_drawFrameCallback Window_drawFrame_;
UIDartState::Current()->ReportUnhandledException(std::move(error_name),
std::move(stack_trace));
UIWIDGETS_API(void)
Window_hook(Window_constructorCallback Window_constructor,
Window_disposeCallback Window_dispose,
Window_updateWindowMetricsCallback Window_updateWindowMetrics,
Window_beginFrameCallback Window_beginFrame,
Window_drawFrameCallback Window_drawFrame) {
Window_constructor_ = Window_constructor;
Window_dispose_ = Window_dispose;
Window_updateWindowMetrics_ = Window_updateWindowMetrics;
Window_beginFrame_ = Window_beginFrame;
Window_drawFrame_ = Window_drawFrame;
Dart_Handle SendPlatformMessage(Dart_Handle window,
const std::string& name,
Dart_Handle callback,
Dart_Handle data_handle) {
UIDartState* dart_state = UIDartState::Current();
if (!dart_state->window()) {
return tonic::ToDart(
"Platform messages can only be sent from the main isolate");
}
fml::RefPtr<PlatformMessageResponse> response;
if (!Dart_IsNull(callback)) {
response = fml::MakeRefCounted<PlatformMessageResponseDart>(
tonic::DartPersistentValue(dart_state, callback),
dart_state->GetTaskRunners().GetUITaskRunner());
}
if (Dart_IsNull(data_handle)) {
dart_state->window()->client()->HandlePlatformMessage(
fml::MakeRefCounted<PlatformMessage>(name, response));
} else {
tonic::DartByteData data(data_handle);
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
dart_state->window()->client()->HandlePlatformMessage(
fml::MakeRefCounted<PlatformMessage>(
name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),
response));
}
return Dart_Null();
UIWIDGETS_API(Mono_Handle) Window_instance() {
return UIMonoState::Current()->window()->mono_window();
void _SendPlatformMessage(Dart_NativeArguments args) {
tonic::DartCallStatic(&SendPlatformMessage, args);
UIWIDGETS_API(void) Window_setNeedsReportTimings(Window* ptr, bool value) {
ptr->client()->SetNeedsReportTimings(value);
void RespondToPlatformMessage(Dart_Handle window,
int response_id,
const tonic::DartByteData& data) {
if (Dart_IsNull(data.dart_handle())) {
UIDartState::Current()->window()->CompletePlatformMessageEmptyResponse(
response_id);
} else {
// TODO(engine): Avoid this copy.
const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
UIDartState::Current()->window()->CompletePlatformMessageResponse(
response_id,
std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()));
}
UIWIDGETS_API(char*) Window_defaultRouteName(Window* ptr) {
const std::string routeName = ptr->client()->DefaultRouteName();
size_t size = routeName.length() + 1;
char* result = static_cast<char*>(malloc(size));
routeName.copy(result, size);
return result;
void _RespondToPlatformMessage(Dart_NativeArguments args) {
tonic::DartCallStatic(&RespondToPlatformMessage, args);
UIWIDGETS_API(void) Window_freeDefaultRouteName(char* routeName) {
free(routeName);
void GetPersistentIsolateData(Dart_NativeArguments args) {
auto persistent_isolate_data =
UIDartState::Current()->window()->client()->GetPersistentIsolateData();
if (!persistent_isolate_data) {
Dart_SetReturnValue(args, Dart_Null());
return;
}
UIWIDGETS_API(void) Window_scheduleFrame(Window* ptr) {
ptr->client()->ScheduleFrame();
}
Dart_SetReturnValue(
args, tonic::DartByteData::Create(persistent_isolate_data->GetMapping(),
persistent_isolate_data->GetSize()));
UIWIDGETS_API(void) Window_render(Window* ptr, Scene* scene) {
ptr->client()->Render(scene);
Dart_Handle ToByteData(const std::vector<uint8_t>& buffer) {
Dart_Handle data_handle =
Dart_NewTypedData(Dart_TypedData_kByteData, buffer.size());
if (Dart_IsError(data_handle))
return data_handle;
Dart_TypedData_Type type;
void* data = nullptr;
intptr_t num_bytes = 0;
FML_CHECK(!Dart_IsError(
Dart_TypedDataAcquireData(data_handle, &type, &data, &num_bytes)));
memcpy(data, buffer.data(), num_bytes);
Dart_TypedDataReleaseData(data_handle);
return data_handle;
}
Window::Window(WindowClient* client) : client_(client) {}
Window::Window(WindowClient* client)
: client_(client), mono_window_(Window_constructor_(this)) {}
Window::~Window() {}
Window::~Window() { Window_dispose_(mono_window_); }
library_.Set(tonic::DartState::Current(),
Dart_LookupLibrary(tonic::ToDart("dart:ui")));
mono_state_ = MonoState::Current()->GetWeakPtr();
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
tonic::LogIfError(tonic::DartInvokeField(
library_.value(), "_updateWindowMetrics",
{
tonic::ToDart(metrics.device_pixel_ratio),
tonic::ToDart(metrics.physical_width),
tonic::ToDart(metrics.physical_height),
tonic::ToDart(metrics.physical_depth),
tonic::ToDart(metrics.physical_padding_top),
tonic::ToDart(metrics.physical_padding_right),
tonic::ToDart(metrics.physical_padding_bottom),
tonic::ToDart(metrics.physical_padding_left),
tonic::ToDart(metrics.physical_view_inset_top),
tonic::ToDart(metrics.physical_view_inset_right),
tonic::ToDart(metrics.physical_view_inset_bottom),
tonic::ToDart(metrics.physical_view_inset_left),
tonic::ToDart(metrics.physical_system_gesture_inset_top),
tonic::ToDart(metrics.physical_system_gesture_inset_right),
tonic::ToDart(metrics.physical_system_gesture_inset_bottom),
tonic::ToDart(metrics.physical_system_gesture_inset_left),
}));
std::shared_ptr<MonoState> mono_state = mono_state_.lock();
if (!mono_state) return;
MonoState::Scope scope(mono_state);
Window_updateWindowMetrics_(
metrics.device_pixel_ratio, metrics.physical_width,
metrics.physical_height, metrics.physical_depth,
metrics.physical_padding_top, metrics.physical_padding_right,
metrics.physical_padding_bottom, metrics.physical_padding_left,
metrics.physical_view_inset_top, metrics.physical_view_inset_right,
metrics.physical_view_inset_bottom, metrics.physical_view_inset_left,
metrics.physical_system_gesture_inset_top,
metrics.physical_system_gesture_inset_right,
metrics.physical_system_gesture_inset_bottom,
metrics.physical_system_gesture_inset_left);
void Window::UpdateLocales(const std::vector<std::string>& locales) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
tonic::LogIfError(tonic::DartInvokeField(
library_.value(), "_updateLocales",
{
tonic::ToDart<std::vector<std::string>>(locales),
}));
}
void Window::UpdateUserSettingsData(const std::string& data) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
tonic::LogIfError(tonic::DartInvokeField(library_.value(),
"_updateUserSettingsData",
{
tonic::StdStringToDart(data),
}));
}
void Window::UpdateLifecycleState(const std::string& data) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
tonic::LogIfError(tonic::DartInvokeField(library_.value(),
"_updateLifecycleState",
{
tonic::StdStringToDart(data),
}));
}
void Window::UpdateLocales(const std::vector<std::string>& locales) {}
void Window::UpdateSemanticsEnabled(bool enabled) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
tonic::LogIfError(tonic::DartInvokeField(
library_.value(), "_updateSemanticsEnabled", {tonic::ToDart(enabled)}));
}
void Window::UpdateUserSettingsData(const std::string& data) {}
void Window::UpdateAccessibilityFeatures(int32_t values) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
void Window::UpdateLifecycleState(const std::string& data) {}
tonic::LogIfError(tonic::DartInvokeField(library_.value(),
"_updateAccessibilityFeatures",
{tonic::ToDart(values)}));
}
void Window::UpdateAccessibilityFeatures(int32_t values) {}
void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state) {
FML_DLOG(WARNING)
<< "Dropping platform message for lack of DartState on channel: "
<< message->channel();
return;
}
tonic::DartState::Scope scope(dart_state);
Dart_Handle data_handle =
(message->hasData()) ? ToByteData(message->data()) : Dart_Null();
if (Dart_IsError(data_handle)) {
FML_DLOG(WARNING)
<< "Dropping platform message because of a Dart error on channel: "
<< message->channel();
return;
}
void Window::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {}
int response_id = 0;
if (auto response = message->response()) {
response_id = next_response_id_++;
pending_responses_[response_id] = response;
}
tonic::LogIfError(
tonic::DartInvokeField(library_.value(), "_dispatchPlatformMessage",
{tonic::ToDart(message->channel()), data_handle,
tonic::ToDart(response_id)}));
}
void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
Dart_Handle data_handle = ToByteData(packet.data());
if (Dart_IsError(data_handle))
return;
tonic::LogIfError(tonic::DartInvokeField(
library_.value(), "_dispatchPointerDataPacket", {data_handle}));
}
void Window::DispatchSemanticsAction(int32_t id,
SemanticsAction action,
std::vector<uint8_t> args) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
Dart_Handle args_handle = (args.empty()) ? Dart_Null() : ToByteData(args);
if (Dart_IsError(args_handle))
return;
tonic::LogIfError(tonic::DartInvokeField(
library_.value(), "_dispatchSemanticsAction",
{tonic::ToDart(id), tonic::ToDart(static_cast<int32_t>(action)),
args_handle}));
}
void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) {}
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
std::shared_ptr<MonoState> mono_state = mono_state_.lock();
if (!mono_state) return;
MonoState::Scope scope(mono_state);
Window_beginFrame_(microseconds);
tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame",
{
Dart_NewInteger(microseconds),
}));
UIMonoState::Current()->FlushMicrotasksNow();
UIDartState::Current()->FlushMicrotasksNow();
tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {}));
Window_drawFrame_();
void Window::ReportTimings(std::vector<int64_t> timings) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
Dart_Handle data_handle =
Dart_NewTypedData(Dart_TypedData_kInt64, timings.size());
Dart_TypedData_Type type;
void* data = nullptr;
intptr_t num_acquired = 0;
FML_CHECK(!Dart_IsError(
Dart_TypedDataAcquireData(data_handle, &type, &data, &num_acquired)));
FML_DCHECK(num_acquired == static_cast<int>(timings.size()));
memcpy(data, timings.data(), sizeof(int64_t) * timings.size());
FML_CHECK(Dart_TypedDataReleaseData(data_handle));
tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_reportTimings",
{
data_handle,
}));
}
void Window::ReportTimings(std::vector<int64_t> timings) {}
if (!response_id)
return;
if (!response_id) return;
if (it == pending_responses_.end())
return;
if (it == pending_responses_.end()) return;
auto response = std::move(it->second);
pending_responses_.erase(it);
response->CompleteEmpty();

std::vector<uint8_t> data) {
if (!response_id)
return;
if (!response_id) return;
if (it == pending_responses_.end())
return;
if (it == pending_responses_.end()) return;
}
void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({
{"Window_defaultRouteName", DefaultRouteName, 1, true},
{"Window_scheduleFrame", ScheduleFrame, 1, true},
{"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
{"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
{"Window_render", Render, 2, true},
{"Window_reportUnhandledException", ReportUnhandledException, 2, true},
{"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true},
{"Window_getPersistentIsolateData", GetPersistentIsolateData, 1, true},
});
}
} // namespace uiwidgets

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


#pragma once
#include <string>
#include <unordered_map>
#include <vector>
#include "flutter/fml/time/time_point.h"
#include "include/gpu/GrContext.h"
#include "lib/ui/window/platform_message.h"
#include "lib/ui/window/pointer_data_packet.h"
#include "lib/ui/window/viewport_metrics.h"
#include "runtime/mono_api.h"
#include "runtime/mono_state.h"
class FontCollection;
class Scene;
enum class AccessibilityFeatureFlag : int32_t {
kAccessibleNavigation = 1 << 0,
kInvertColors = 1 << 1,
kDisableAnimations = 1 << 2,
kBoldText = 1 << 3,
kReduceMotion = 1 << 4,
kHighContrast = 1 << 5,
};
class WindowClient {
public:
virtual std::string DefaultRouteName() = 0;
virtual void ScheduleFrame() = 0;
virtual void Render(Scene* scene) = 0;
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
virtual FontCollection& GetFontCollection() = 0;
virtual void SetNeedsReportTimings(bool value) = 0;
protected:
virtual ~WindowClient();
};
public:
explicit Window(WindowClient* client);
~Window();
WindowClient* client() const { return client_; }
const ViewportMetrics& viewport_metrics() { return viewport_metrics_; }
Mono_Handle mono_window() const { return mono_window_; }
void DidCreateIsolate();
void UpdateWindowMetrics(const ViewportMetrics& metrics);
void UpdateLocales(const std::vector<std::string>& locales);
void UpdateUserSettingsData(const std::string& data);
void UpdateLifecycleState(const std::string& data);
void UpdateAccessibilityFeatures(int32_t flags);
void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
void DispatchPointerDataPacket(const PointerDataPacket& packet);
void BeginFrame(fml::TimePoint frameTime);
void ReportTimings(std::vector<int64_t> timings);
void CompletePlatformMessageResponse(int response_id,
std::vector<uint8_t> data);
void CompletePlatformMessageEmptyResponse(int response_id);
private:
WindowClient* client_;
ViewportMetrics viewport_metrics_;
Mono_Handle mono_window_;
std::weak_ptr<MonoState> mono_state_;
// We use id 0 to mean that no response is expected.
int next_response_id_ = 1;
std::unordered_map<int, fml::RefPtr<PlatformMessageResponse>>
pending_responses_;
};
} // namespace uiwidgets

2
engine/src/render_api_d3d11.cc


const char** argument_names,
const char** argument_values) {}
int64_t Dart_TimelineGetMicros() { return 0; }
class RenderAPI_D3D11 : public RenderAPI {
public:
RenderAPI_D3D11();

25
engine/src/runtime/mono_api.cc


return Mono_IsolateData(Mono_CurrentIsolate());
}
void Mono_ThrowException(const char* exception) {}
typedef void (*Mono_ThrowExceptionCallback)(const char* exception);
static Mono_ThrowExceptionCallback Mono_ThrowExceptionCallback_;
void Mono_ThrowException(const char* exception) {
Mono_ThrowExceptionCallback_(exception);
}
typedef int64_t (*Mono_TimelineGetMicrosCallback)();
static Mono_TimelineGetMicrosCallback Mono_TimelineGetMicrosCallback_;
int64_t Mono_TimelineGetMicros() { return Mono_TimelineGetMicrosCallback_(); }
} // namespace uiwidgets
UIWIDGETS_API(void)
Mono_hook(Mono_ThrowExceptionCallback throwException,
Mono_TimelineGetMicrosCallback timelineGetMicros) {
Mono_ThrowExceptionCallback_ = throwException;
Mono_TimelineGetMicrosCallback_ = timelineGetMicros;
}
} // namespace uiwidgets
extern "C" int64_t Dart_TimelineGetMicros() { return uiwidgets::Mono_TimelineGetMicros(); }

8
engine/src/runtime/mono_api.h


#pragma once
#include <Unity/IUnityInterface.h>
#define UIWIDGETS_API(RETURN) \
extern "C" UNITY_INTERFACE_EXPORT RETURN UNITY_INTERFACE_API
namespace uiwidgets {

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

8
engine/src/runtime/mono_isolate.cc


shutdown_callbacks_.emplace_back(std::make_unique<AutoFireClosure>(closure));
}
void MonoIsolate::Shutdown() {
TRACE_EVENT0("uiwidgets", "DartIsolate::Shutdown");
bool MonoIsolate::Shutdown() {
TRACE_EVENT0("uiwidgets", "MonoIsolate::Shutdown");
// We need to enter the isolate because Dart_ShutdownIsolate does not take
// We need to enter the isolate because Mono_ShutdownIsolate does not take
// the isolate to shutdown as a parameter.
FML_DCHECK(Mono_CurrentIsolate() == nullptr);
Mono_EnterIsolate(mono_isolate);

return true;
}
MonoIsolate::AutoFireClosure::AutoFireClosure(const fml::closure& closure)

2
engine/src/runtime/mono_isolate.h


~MonoIsolate() override;
void Shutdown();
bool Shutdown();
void AddIsolateShutdownCallback(const fml::closure& closure);

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


#include "animator.h"
#include "flutter/fml/trace_event.h"
#include "runtime/mono_api.h"
namespace uiwidgets {

waiter_(std::move(waiter)),
last_frame_begin_time_(),
last_frame_target_time_(),
dart_frame_deadline_(0),
mono_frame_deadline_(0),
layer_tree_pipeline_(fml::MakeRefCounted<LayerTreePipeline>(
task_runners.GetPlatformTaskRunner() ==
task_runners.GetRasterTaskRunner()

return (frame_number_ % 2) ? "even" : "odd";
}
static int64_t FxlToDartOrEarlier(fml::TimePoint time) {
int64_t dart_now = Dart_TimelineGetMicros();
static int64_t FxlToMonoOrEarlier(fml::TimePoint time) {
int64_t mono_now = Mono_TimelineGetMicros();
return (time - fxl_now).ToMicroseconds() + dart_now;
return (time - fxl_now).ToMicroseconds() + mono_now;
TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_number_++);
TRACE_EVENT_ASYNC_END0("uiwidgets", "Frame Request Pending", frame_number_++);
TRACE_EVENT0("flutter", "Animator::BeginFrame");
TRACE_EVENT0("uiwidgets", "Animator::BeginFrame");
TRACE_FLOW_END("flutter", "PointerEvent", trace_flow_id);
TRACE_FLOW_END("uiwidgets", "PointerEvent", trace_flow_id);
trace_flow_ids_.pop_front();
}

last_frame_begin_time_ = frame_start_time;
last_frame_target_time_ = frame_target_time;
dart_frame_deadline_ = FxlToDartOrEarlier(frame_target_time);
mono_frame_deadline_ = FxlToMonoOrEarlier(frame_target_time);
TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame",
TRACE_EVENT2("uiwidgets", "Framework Workload", "mode", "basic", "frame",
FrameParity());
delegate_.OnAnimatorBeginFrame(frame_target_time);
}

// assume that we are idle, and notify the engine of this.
if (notify_idle_task_id == self->notify_idle_task_id_ &&
!self->frame_scheduled_) {
TRACE_EVENT0("flutter", "BeginFrame idle callback");
self->delegate_.OnAnimatorNotifyIdle(Dart_TimelineGetMicros() +
TRACE_EVENT0("uiwidgets", "BeginFrame idle callback");
self->delegate_.OnAnimatorNotifyIdle(Mono_TimelineGetMicros() +
100000);
}
},

// started an expensive operation right after posting this message however.
// To support that, we need edge triggered wakes on VSync.
task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(),
frame_number = frame_number_]() {
if (!self.get()) {
return;
}
TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number);
self->AwaitVSync();
});
task_runners_.GetUITaskRunner()->PostTask(
[self = weak_factory_.GetWeakPtr(), frame_number = frame_number_]() {
if (!self.get()) {
return;
}
TRACE_EVENT_ASYNC_BEGIN0("uiwidgets", "Frame Request Pending",
frame_number);
self->AwaitVSync();
});
frame_scheduled_ = true;
}

}
});
delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
delegate_.OnAnimatorNotifyIdle(mono_frame_deadline_);
}
void Animator::ScheduleSecondaryVsyncCallback(const fml::closure& callback) {

6
engine/src/shell/common/animator.h


namespace uiwidgets {
/// Executor of animations.
///
/// In conjunction with the |VsyncWaiter| it allows callers (typically Dart
/// code) to schedule work that ends up generating a |LayerTree|.
class Animator final {
public:
class Delegate {

fml::TimePoint last_frame_begin_time_;
fml::TimePoint last_frame_target_time_;
int64_t dart_frame_deadline_;
int64_t mono_frame_deadline_;
fml::RefPtr<LayerTreePipeline> layer_tree_pipeline_;
fml::Semaphore pending_frame_semaphore_;
LayerTreePipeline::ProducerContinuation producer_continuation_;

194
com.unity.uiwidgets/Runtime/ui/painting/native_bindings.cs


using System;
using System.Runtime.InteropServices;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.ui {
class NativeBindings {
#if (UNITY_IOS || UNITY_TVOS || UNITY_WEBGL) && !UNITY_EDITOR
const string dllName = "__Internal";
#else
const string dllName = "libUIWidgets_d";
#endif
[DllImport(dllName)]
public static extern IntPtr ImageShader_constructor();
[DllImport(dllName)]
public static extern void ImageShader_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern unsafe void ImageShader_initWithImage(IntPtr ptr,
IntPtr image, int tmx, int tmy, float* matrix4);
[DllImport(dllName)]
public static extern IntPtr Gradient_constructor();
[DllImport(dllName)]
public static extern void Gradient_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern unsafe void Gradient_initLinear(IntPtr ptr,
float* endPoints, int endPointsLength,
uint* colors, int colorsLength,
float* colorStops, int colorStopsLength,
int tileMode, float* matrix4);
[DllImport(dllName)]
public static extern unsafe void Gradient_initRadial(IntPtr ptr,
float centerX, float centerY, float radius,
uint* colors, int colorsLength,
float* colorStops, int colorStopsLength,
int tileMode, float* matrix4);
[DllImport(dllName)]
public static extern unsafe void Gradient_initConical(IntPtr ptr,
float startX, float startY, float startRadius,
float endX, float endY, float endRadius,
uint* colors, int colorsLength,
float* colorStops, int colorStopsLength,
int tileMode, float* matrix4);
[DllImport(dllName)]
public static extern unsafe void Gradient_initSweep(IntPtr ptr,
float centerX, float centerY,
uint* colors, int colorsLength,
float* colorStops, int colorStopsLength,
int tileMode, float startAngle, float endAngle, float* matrix4);
[DllImport(dllName)]
public static extern IntPtr ColorFilter_constructor();
[DllImport(dllName)]
public static extern void ColorFilter_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern void ColorFilter_initMode(IntPtr ptr, uint color, int blendMode);
[DllImport(dllName)]
public static extern unsafe void ColorFilter_initMatrix(IntPtr ptr, float* matrix4);
[DllImport(dllName)]
public static extern unsafe void ColorFilter_initLinearToSrgbGamma(IntPtr ptr);
[DllImport(dllName)]
public static extern unsafe void ColorFilter_initSrgbToLinearGamma(IntPtr ptr);
[DllImport(dllName)]
public static extern IntPtr ImageFilter_constructor();
[DllImport(dllName)]
public static extern void ImageFilter_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern void ImageFilter_initBlur(IntPtr ptr, float sigmaX, float sigmaY);
[DllImport(dllName)]
public static extern unsafe void ImageFilter_initMatrix(IntPtr ptr, float* matrix4, int filterQuality);
[DllImport(dllName)]
public static extern IntPtr Canvas_constructor(IntPtr recorder,
double left,
double top,
double right,
double bottom);
[DllImport(dllName)]
public static extern void Canvas_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern void Canvas_save(IntPtr ptr);
[DllImport(dllName)]
public static extern void Canvas_restore(IntPtr ptr);
[DllImport(dllName)]
public static extern void Image_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern int Image_width(IntPtr ptr);
[DllImport(dllName)]
public static extern int Image_height(IntPtr ptr);
public delegate void Image_toByteDataCallback(IntPtr callbackHandle, IntPtr data, int length);
[DllImport(dllName)]
public static extern string Image_toByteData(IntPtr ptr, int format, Image_toByteDataCallback callback,
IntPtr callbackHandle);
[DllImport(dllName)]
public static extern void Picture_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern int Picture_GetAllocationSize(IntPtr ptr);
public delegate void Picture_toImageCallback(IntPtr callbackHandle, IntPtr result);
[DllImport(dllName)]
public static extern string Picture_toImage(IntPtr ptr, int width, int height, Picture_toImageCallback callback,
IntPtr callbackHandle);
[DllImport(dllName)]
public static extern IntPtr PictureRecorder_constructor();
[DllImport(dllName)]
public static extern void PictureRecorder_dispose(IntPtr ptr);
[DllImport(dllName)]
public static extern bool PictureRecorder_isRecording(IntPtr ptr);
[DllImport(dllName)]
public static extern IntPtr PictureRecorder_endRecording(IntPtr ptr);
}
public abstract class NativeWrapper {
protected internal IntPtr _ptr { get; protected set; }
protected NativeWrapper() {
}
protected NativeWrapper(IntPtr ptr) {
D.assert(this._ptr != IntPtr.Zero);
this._ptr = ptr;
}
~NativeWrapper() {
if (this._ptr != IntPtr.Zero) {
this.DisposePtr(this._ptr);
this._ptr = IntPtr.Zero;
}
}
protected abstract void DisposePtr(IntPtr ptr);
}
public abstract class NativeWrapperDisposable : IDisposable {
protected internal IntPtr _ptr { get; protected set; }
protected NativeWrapperDisposable() {
}
protected NativeWrapperDisposable(IntPtr ptr) {
D.assert(this._ptr != IntPtr.Zero);
this._ptr = ptr;
}
~NativeWrapperDisposable() {
if (this._ptr != IntPtr.Zero) {
this.DisposePtr(this._ptr);
this._ptr = IntPtr.Zero;
}
}
protected abstract void DisposePtr(IntPtr ptr);
public void Dispose() {
if (this._ptr != IntPtr.Zero) {
this.DisposePtr(this._ptr);
this._ptr = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
}
}

3
com.unity.uiwidgets/Runtime/ui/painting/native_bindings.cs.meta


fileFormatVersion: 2
guid: 334fd474090a463f811ef61d03d38e9e
timeCreated: 1595569910

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


using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using AOT;
using RSG;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.ui2 {
public class Scene : NativeWrapperDisposable {
internal Scene(IntPtr ptr) : base(ptr) {
}
protected override void DisposePtr(IntPtr ptr) {
Scene_dispose(ptr);
}
public Promise<Image> toImage(int width, int height) {
if (width <= 0 || height <= 0) {
throw new Exception("Invalid image dimensions.");
}
var completer = new Promise<Image>(true);
GCHandle completerHandle = GCHandle.Alloc(completer);
IntPtr error =
Scene_toImage(_ptr, width, height, _toImageCallback,
(IntPtr) completerHandle);
if (error != null) {
completerHandle.Free();
throw new Exception(Marshal.PtrToStringAnsi(error));
}
return completer;
}
[MonoPInvokeCallback(typeof(Scene_toImageCallback))]
static void _toImageCallback(IntPtr callbackHandle, IntPtr result) {
GCHandle completerHandle = (GCHandle) callbackHandle;
var completer = (Promise<Image>) completerHandle.Target;
completerHandle.Free();
if (result == IntPtr.Zero) {
completer.Reject(new Exception("operation failed"));
}
else {
var image = new Image(result);
completer.Resolve(image);
}
}
[DllImport(NativeBindings.dllName)]
static extern void Scene_dispose(IntPtr ptr);
delegate void Scene_toImageCallback(IntPtr callbackHandle, IntPtr result);
[DllImport(NativeBindings.dllName)]
static extern IntPtr Scene_toImage(IntPtr ptr, int width, int height, Scene_toImageCallback callback,
IntPtr callbackHandle);
}
public abstract class _EngineLayerWrapper : EngineLayer {
protected _EngineLayerWrapper(IntPtr ptr) : base(ptr) {
}
internal List<_EngineLayerWrapper> _debugChildren;
internal bool _debugWasUsedAsOldLayer = false;
internal bool _debugCheckNotUsedAsOldLayer() {
D.assert(
!_debugWasUsedAsOldLayer,
() => "Layer $runtimeType was previously used as oldLayer.\n" +
"Once a layer is used as oldLayer, it may not be used again. Instead, " +
"after calling one of the SceneBuilder.push* methods and passing an oldLayer " +
"to it, use the layer returned by the method as oldLayer in subsequent " +
"frames.");
return true;
}
}
public class TransformEngineLayer : _EngineLayerWrapper {
internal TransformEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class OffsetEngineLayer : _EngineLayerWrapper {
internal OffsetEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class ClipRectEngineLayer : _EngineLayerWrapper {
internal ClipRectEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class ClipRRectEngineLayer : _EngineLayerWrapper {
internal ClipRRectEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class ClipPathEngineLayer : _EngineLayerWrapper {
internal ClipPathEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class OpacityEngineLayer : _EngineLayerWrapper {
internal OpacityEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class ColorFilterEngineLayer : _EngineLayerWrapper {
internal ColorFilterEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class ImageFilterEngineLayer : _EngineLayerWrapper {
internal ImageFilterEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class BackdropFilterEngineLayer : _EngineLayerWrapper {
internal BackdropFilterEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class ShaderMaskEngineLayer : _EngineLayerWrapper {
internal ShaderMaskEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class PhysicalShapeEngineLayer : _EngineLayerWrapper {
internal PhysicalShapeEngineLayer(IntPtr ptr) : base(ptr) {
}
}
public class SceneBuilder : NativeWrapper {
public SceneBuilder() : base(SceneBuilder_constructor()) {
}
protected override void DisposePtr(IntPtr ptr) {
SceneBuilder_dispose(ptr);
}
readonly Dictionary<EngineLayer, string> _usedLayers = new Dictionary<EngineLayer, string>();
bool _debugCheckUsedOnce(EngineLayer layer, string usage) {
D.assert(() => {
if (layer == null) {
return true;
}
D.assert(
!_usedLayers.ContainsKey(layer),
() => $"Layer {layer.GetType()} already used.\n" +
$"The layer is already being used as {_usedLayers[layer]} in this scene.\n" +
"A layer may only be used once in a given scene.");
_usedLayers[layer] = usage;
return true;
});
return true;
}
bool _debugCheckCanBeUsedAsOldLayer(_EngineLayerWrapper layer, String methodName) {
D.assert(() => {
if (layer == null) {
return true;
}
layer._debugCheckNotUsedAsOldLayer();
D.assert(_debugCheckUsedOnce(layer, $"oldLayer in {methodName}"));
layer._debugWasUsedAsOldLayer = true;
return true;
});
return true;
}
readonly List<_EngineLayerWrapper> _layerStack = new List<_EngineLayerWrapper>();
bool _debugPushLayer(_EngineLayerWrapper newLayer) {
D.assert(() => {
if (_layerStack.isNotEmpty()) {
_EngineLayerWrapper currentLayer = _layerStack.last();
currentLayer._debugChildren ??= new List<_EngineLayerWrapper>();
currentLayer._debugChildren.Add(newLayer);
}
_layerStack.Add(newLayer);
return true;
});
return true;
}
public unsafe TransformEngineLayer pushTransform(
float[] matrix4,
TransformEngineLayer oldLayer = null
) {
D.assert(PaintingUtils._matrix4IsValid(matrix4));
D.assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, "pushTransform"));
fixed (float* matrix4Ptr = matrix4) {
TransformEngineLayer layer = new TransformEngineLayer(SceneBuilder_pushTransform(_ptr, matrix4Ptr));
D.assert(_debugPushLayer(layer));
return layer;
}
}
public OffsetEngineLayer pushOffset(
float dx,
float dy,
OffsetEngineLayer oldLayer = null
) {
D.assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, "pushOffset"));
OffsetEngineLayer layer = new OffsetEngineLayer(SceneBuilder_pushOffset(_ptr, dx, dy));
D.assert(_debugPushLayer(layer));
return layer;
}
public void pop() {
if (_layerStack.isNotEmpty()) {
_layerStack.removeLast();
}
SceneBuilder_pop(_ptr);
}
public Scene build() {
return new Scene(SceneBuilder_build(_ptr));
}
public void addRetained(EngineLayer retainedLayer) {
D.assert(retainedLayer is _EngineLayerWrapper);
D.assert(() => {
_EngineLayerWrapper layer = retainedLayer as _EngineLayerWrapper;
void recursivelyCheckChildrenUsedOnce(_EngineLayerWrapper parentLayer) {
_debugCheckUsedOnce(parentLayer, "retained layer");
parentLayer._debugCheckNotUsedAsOldLayer();
if (parentLayer._debugChildren == null || parentLayer._debugChildren.isEmpty()) {
return;
}
parentLayer._debugChildren.ForEach(recursivelyCheckChildrenUsedOnce);
}
recursivelyCheckChildrenUsedOnce(layer);
return true;
});
_EngineLayerWrapper wrapper = retainedLayer as _EngineLayerWrapper;
SceneBuilder_addRetained(_ptr, wrapper._ptr);
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_constructor();
[DllImport(NativeBindings.dllName)]
static extern void SceneBuilder_dispose(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern unsafe IntPtr SceneBuilder_pushTransform(IntPtr ptr, float* matrix4);
[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_pushOffset(IntPtr ptr, float dx, float dy);
[DllImport(NativeBindings.dllName)]
static extern void SceneBuilder_pop(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_build(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern void SceneBuilder_addRetained(IntPtr ptr, IntPtr retainedLayer);
}
}

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


fileFormatVersion: 2
guid: 28c3db1a7c1746ca8d7725c27f41cb30
timeCreated: 1597124223

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


using System;
using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.ui;
using UnityEngine;
namespace Unity.UIWidgets.ui2 {
public static class Hooks {
public static void hook() {
Mono_hook(
Mono_throwException,
Mono_timelineGetMicros);
Window_hook(
Window_constructor,
Window_dispose,
Window_updateWindowMetrics,
Window_beginFrame,
Window_drawFrame);
}
delegate void Mono_ThrowExceptionCallback(IntPtr exception);
[MonoPInvokeCallback(typeof(Mono_ThrowExceptionCallback))]
static void Mono_throwException(IntPtr exception) {
throw new Exception(Marshal.PtrToStringAnsi(exception));
}
delegate long Mono_TimelineGetMicrosCallback();
[MonoPInvokeCallback(typeof(Mono_TimelineGetMicrosCallback))]
static long Mono_timelineGetMicros() {
return Environment.TickCount * 1000L;
}
[DllImport(NativeBindings.dllName)]
static extern void Mono_hook(Mono_ThrowExceptionCallback throwException,
Mono_TimelineGetMicrosCallback timelineGetMicros);
delegate IntPtr Window_constructorCallback(IntPtr ptr);
[MonoPInvokeCallback(typeof(Window_constructorCallback))]
static IntPtr Window_constructor(IntPtr ptr) {
Window window = new Window();
window._ptr = ptr;
return (IntPtr) GCHandle.Alloc(window);
}
delegate void Window_disposeCallback(IntPtr handle);
[MonoPInvokeCallback(typeof(Window_disposeCallback))]
static void Window_dispose(IntPtr handle) {
GCHandle gcHandle = (GCHandle) handle;
Window window = (Window) gcHandle.Target;
window._ptr = IntPtr.Zero;
gcHandle.Free();
}
delegate void Window_updateWindowMetricsCallback(
float devicePixelRatio,
float width,
float height,
float depth,
float viewPaddingTop,
float viewPaddingRight,
float viewPaddingBottom,
float viewPaddingLeft,
float viewInsetTop,
float viewInsetRight,
float viewInsetBottom,
float viewInsetLeft,
float systemGestureInsetTop,
float systemGestureInsetRight,
float systemGestureInsetBottom,
float systemGestureInsetLeft
);
[MonoPInvokeCallback(typeof(Window_updateWindowMetricsCallback))]
static void Window_updateWindowMetrics(
float devicePixelRatio,
float width,
float height,
float depth,
float viewPaddingTop,
float viewPaddingRight,
float viewPaddingBottom,
float viewPaddingLeft,
float viewInsetTop,
float viewInsetRight,
float viewInsetBottom,
float viewInsetLeft,
float systemGestureInsetTop,
float systemGestureInsetRight,
float systemGestureInsetBottom,
float systemGestureInsetLeft
) {
var window = Window.instance;
window.devicePixelRatio = devicePixelRatio;
window.physicalSize = new Size(width, height);
window.physicalDepth = depth;
window.viewPadding = new WindowPadding(
top: viewPaddingTop,
right: viewPaddingRight,
bottom: viewPaddingBottom,
left: viewPaddingLeft);
window.viewInsets = new WindowPadding(
top: viewInsetTop,
right: viewInsetRight,
bottom: viewInsetBottom,
left: viewInsetLeft);
window.padding = new WindowPadding(
top: Mathf.Max(0.0f, viewPaddingTop - viewInsetTop),
right: Mathf.Max(0.0f, viewPaddingRight - viewInsetRight),
bottom: Mathf.Max(0.0f, viewPaddingBottom - viewInsetBottom),
left: Mathf.Max(0.0f, viewPaddingLeft - viewInsetLeft));
window.systemGestureInsets = new WindowPadding(
top: Mathf.Max(0.0f, systemGestureInsetTop),
right: Mathf.Max(0.0f, systemGestureInsetRight),
bottom: Mathf.Max(0.0f, systemGestureInsetBottom),
left: Mathf.Max(0.0f, systemGestureInsetLeft));
window.onMetricsChanged?.Invoke();
}
delegate void Window_beginFrameCallback(long microseconds);
[MonoPInvokeCallback(typeof(Window_beginFrameCallback))]
static void Window_beginFrame(long microseconds) {
Window.instance.onBeginFrame?.Invoke(TimeSpan.FromMilliseconds(microseconds / 1000.0));
}
delegate void Window_drawFrameCallback();
[MonoPInvokeCallback(typeof(Window_drawFrameCallback))]
static void Window_drawFrame() {
Window.instance.onDrawFrame?.Invoke();
}
[DllImport(NativeBindings.dllName)]
static extern void Window_hook(
Window_constructorCallback Window_constructor,
Window_disposeCallback Window_dispose,
Window_updateWindowMetricsCallback Window_updateWindowMetrics,
Window_beginFrameCallback Window_beginFrame,
Window_drawFrameCallback Window_drawFrame);
}
}

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


fileFormatVersion: 2
guid: 9757fe323057485caf33e70f71ca8bb0
timeCreated: 1597045454

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


using System;
using System.Runtime.InteropServices;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.ui2 {
public static class Isolate {
public static IntPtr current {
get => Isolate_current();
}
public static IDisposable getScope(IntPtr isolate) {
return new _IsolateDisposable(isolate);
}
class _IsolateDisposable : IDisposable {
IntPtr _isolate;
IntPtr _previous;
public _IsolateDisposable(IntPtr isolate) {
_isolate = isolate;
_previous = Isolate_current();
if (_previous == _isolate) {
return;
}
if (_previous != IntPtr.Zero) {
Isolate_exit();
}
Isolate_enter(_isolate);
}
public void Dispose() {
var current = Isolate_current();
D.assert(current == IntPtr.Zero || current == _isolate);
if (_previous == _isolate) {
return;
}
if (current != IntPtr.Zero) {
Isolate_exit();
}
if (_previous != IntPtr.Zero) {
Isolate_enter(_previous);
}
}
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr Isolate_current();
[DllImport(NativeBindings.dllName)]
static extern void Isolate_enter(IntPtr isolate);
[DllImport(NativeBindings.dllName)]
static extern void Isolate_exit();
}
}

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


using System;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.ui2 {
public class NativeBindings {
#if (UNITY_IOS || UNITY_TVOS || UNITY_WEBGL) && !UNITY_EDITOR
internal const string dllName = "__Internal";
#else
internal const string dllName = "libUIWidgets_d";
#endif
}
public abstract class NativeWrapper {
protected internal IntPtr _ptr { get; protected set; }
protected NativeWrapper() {
}
protected NativeWrapper(IntPtr ptr) {
D.assert(ptr != IntPtr.Zero);
_ptr = ptr;
}
~NativeWrapper() {
if (_ptr != IntPtr.Zero) {
DisposePtr(_ptr);
_ptr = IntPtr.Zero;
}
}
protected abstract void DisposePtr(IntPtr ptr);
}
public abstract class NativeWrapperDisposable : IDisposable {
protected internal IntPtr _ptr { get; protected set; }
protected NativeWrapperDisposable() {
}
protected NativeWrapperDisposable(IntPtr ptr) {
D.assert(_ptr != IntPtr.Zero);
_ptr = ptr;
}
~NativeWrapperDisposable() {
if (_ptr != IntPtr.Zero) {
DisposePtr(_ptr);
_ptr = IntPtr.Zero;
}
}
protected abstract void DisposePtr(IntPtr ptr);
public void Dispose() {
if (_ptr != IntPtr.Zero) {
DisposePtr(_ptr);
_ptr = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
}
}

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

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


using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.ui2 {
public delegate void VoidCallback();
public delegate void FrameCallback(TimeSpan duration);
public delegate void TimingsCallback(List<FrameTiming> timings);
public delegate void PointerDataPacketCallback(PointerDataPacket packet);
public unsafe delegate void PlatformMessageResponseCallback(byte* data, int dataLength);
public unsafe delegate void PlatformMessageCallback(
[MarshalAs(UnmanagedType.LPStr)] string name, byte* data, int dataLength,
PlatformMessageResponseCallback callback);
delegate void _SetNeedsReportTimingsFunc(IntPtr ptr, bool value);
public enum FramePhase {
buildStart,
buildFinish,
rasterStart,
rasterFinish,
}
public class FrameTiming {
public FrameTiming(List<long> timestamps) {
D.assert(timestamps.Count == Enum.GetNames(typeof(FramePhase)).Length);
_timestamps = timestamps;
}
public long timestampInMicroseconds(FramePhase phase) => _timestamps[(int) phase];
TimeSpan _rawDuration(FramePhase phase) => TimeSpan.FromMilliseconds(_timestamps[(int) phase] / 1000.0);
public TimeSpan buildDuration => _rawDuration(FramePhase.buildFinish) - _rawDuration(FramePhase.buildStart);
public TimeSpan rasterDuration => _rawDuration(FramePhase.rasterFinish) - _rawDuration(FramePhase.rasterStart);
public TimeSpan totalSpan => _rawDuration(FramePhase.rasterFinish) - _rawDuration(FramePhase.buildStart);
List<long> _timestamps; // in microseconds
string _formatMS(TimeSpan duration) => $"{duration.Milliseconds}ms";
public override string ToString() {
return
$"{GetType()}(buildDuration: {_formatMS(buildDuration)}, rasterDuration: {_formatMS(rasterDuration)}, totalSpan: {_formatMS(totalSpan)})";
}
}
public enum AppLifecycleState {
resumed,
inactive,
paused,
detached,
}
public class WindowPadding {
internal WindowPadding(float left, float top, float right, float bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public readonly float left;
public readonly float top;
public readonly float right;
public readonly float bottom;
public static readonly WindowPadding zero = new WindowPadding(left: 0.0f, top: 0.0f, right: 0.0f, bottom: 0.0f);
public override string ToString() {
return $"{GetType()}(left: {left}, top: {top}, right: {right}, bottom: {bottom})";
}
}
public class Window {
internal IntPtr _ptr;
internal Window() {
_setNeedsReportTimings = Window_setNeedsReportTimings;
}
public static Window instance {
get {
GCHandle gcHandle = (GCHandle) Window_instance();
return (Window) gcHandle.Target;
}
}
public float devicePixelRatio { get; internal set; } = 1.0f;
public Size physicalSize { get; internal set; } = Size.zero;
public float physicalDepth { get; internal set; } = float.MaxValue;
public WindowPadding viewInsets { get; internal set; } = WindowPadding.zero;
public WindowPadding viewPadding { get; internal set; } = WindowPadding.zero;
public WindowPadding systemGestureInsets { get; internal set; } = WindowPadding.zero;
public WindowPadding padding { get; internal set; } = WindowPadding.zero;
public VoidCallback onMetricsChanged { get; set; }
public string initialLifecycleState {
get {
_initialLifecycleStateAccessed = true;
return _initialLifecycleState;
}
}
string _initialLifecycleState;
bool _initialLifecycleStateAccessed = false;
public float textScaleFactor { get; internal set; } = 1.0f;
public VoidCallback onTextScaleFactorChanged { get; set; }
public bool alwaysUse24HourFormat { get; internal set; } = false;
public Brightness platformBrightness { get; internal set; } = Brightness.light;
public VoidCallback onPlatformBrightnessChanged { get; set; }
public FrameCallback onBeginFrame { get; set; }
public VoidCallback onDrawFrame { get; set; }
TimingsCallback _onReportTimings;
_SetNeedsReportTimingsFunc _setNeedsReportTimings;
public TimingsCallback onReportTimings {
get { return _onReportTimings; }
set {
if ((value == null) != (_onReportTimings == null)) {
_setNeedsReportTimings(_ptr, value != null);
}
_onReportTimings = value;
}
}
public PointerDataPacketCallback onPointerDataPacket { get; set; }
public string defaultRouteName {
get {
IntPtr routeNamePtr = Window_defaultRouteName(_ptr);
string routeName = Marshal.PtrToStringAnsi(routeNamePtr);
Window_freeDefaultRouteName(routeNamePtr);
return routeName;
}
}
public void scheduleFrame() {
Window_scheduleFrame(_ptr);
}
public void render(Scene scene) {
Window_render(_ptr, scene._ptr);
}
public AccessibilityFeatures accessibilityFeatures { get; internal set; } = AccessibilityFeatures.zero;
public VoidCallback onAccessibilityFeaturesChanged { get; set; }
public unsafe void sendPlatformMessage(string name,
byte* data, int dataLength,
PlatformMessageResponseCallback callback) {
IntPtr errorPtr =
Window_sendPlatformMessage(_ptr, name, callback, data, dataLength);
if (errorPtr != IntPtr.Zero)
throw new Exception(Marshal.PtrToStringAnsi(errorPtr));
}
public PlatformMessageCallback onPlatformMessage { get; set; }
unsafe void _respondToPlatformMessage(int responseId, byte* data, int dataLength) {
Window_respondToPlatformMessage(_ptr, responseId, data, dataLength);
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr Window_instance();
[DllImport(NativeBindings.dllName)]
static extern void Window_setNeedsReportTimings(IntPtr ptr, bool value);
[DllImport(NativeBindings.dllName)]
static extern IntPtr Window_defaultRouteName(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern void Window_freeDefaultRouteName(IntPtr routeNamePtr);
[DllImport(NativeBindings.dllName)]
static extern void Window_scheduleFrame(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern void Window_render(IntPtr ptr, IntPtr scene);
[DllImport(NativeBindings.dllName)]
static extern unsafe IntPtr Window_sendPlatformMessage(IntPtr ptr, string name,
PlatformMessageResponseCallback callback,
byte* data, int dataLength);
[DllImport(NativeBindings.dllName)]
static extern unsafe void Window_respondToPlatformMessage(IntPtr ptr, int responseId,
byte* data, int dataLength);
}
public class AccessibilityFeatures : IEquatable<AccessibilityFeatures> {
internal AccessibilityFeatures(int index) {
_index = index;
}
const int _kAccessibleNavigation = 1 << 0;
const int _kInvertColorsIndex = 1 << 1;
const int _kDisableAnimationsIndex = 1 << 2;
const int _kBoldTextIndex = 1 << 3;
const int _kReduceMotionIndex = 1 << 4;
const int _kHighContrastIndex = 1 << 5;
readonly int _index;
public static readonly AccessibilityFeatures zero = new AccessibilityFeatures(0);
public bool accessibleNavigation => (_kAccessibleNavigation & _index) != 0;
public bool invertColors => (_kInvertColorsIndex & _index) != 0;
public bool disableAnimations => (_kDisableAnimationsIndex & _index) != 0;
public bool boldText => (_kBoldTextIndex & _index) != 0;
public bool reduceMotion => (_kReduceMotionIndex & _index) != 0;
public bool highContrast => (_kHighContrastIndex & _index) != 0;
public override string ToString() {
List<String> features = new List<String>();
if (accessibleNavigation)
features.Add("accessibleNavigation");
if (invertColors)
features.Add("invertColors");
if (disableAnimations)
features.Add("disableAnimations");
if (boldText)
features.Add("boldText");
if (reduceMotion)
features.Add("reduceMotion");
if (highContrast)
features.Add("highContrast");
return $"AccessibilityFeatures{features}";
}
public bool Equals(AccessibilityFeatures other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return _index == other._index;
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != GetType()) {
return false;
}
return Equals((AccessibilityFeatures) obj);
}
public override int GetHashCode() {
return _index;
}
public static bool operator ==(AccessibilityFeatures left, AccessibilityFeatures right) {
return Equals(left, right);
}
public static bool operator !=(AccessibilityFeatures left, AccessibilityFeatures right) {
return !Equals(left, right);
}
}
public enum Brightness {
dark,
light,
}
}

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


fileFormatVersion: 2
guid: 65763a38b5ea40a2af2abe0a2458105a
timeCreated: 1597046337

39
engine/src/lib/ui/painting/color_filter.cc


#include "color_filter.h"
namespace uiwidgets {
fml::RefPtr<ColorFilter> ColorFilter::Create() {
return fml::MakeRefCounted<ColorFilter>();
}
void ColorFilter::initMode(int color, int blend_mode) {
filter_ = SkColorFilters::Blend(static_cast<SkColor>(color),
static_cast<SkBlendMode>(blend_mode));
}
sk_sp<SkColorFilter> ColorFilter::MakeColorMatrixFilter255(
const float array[20]) {
float tmp[20];
memcpy(tmp, array, sizeof(tmp));
tmp[4] *= 1.0f / 255;
tmp[9] *= 1.0f / 255;
tmp[14] *= 1.0f / 255;
tmp[19] *= 1.0f / 255;
return SkColorFilters::Matrix(tmp);
}
void ColorFilter::initMatrix(const float* color_matrix) {
filter_ = MakeColorMatrixFilter255(color_matrix);
}
void ColorFilter::initLinearToSrgbGamma() {
filter_ = SkColorFilters::LinearToSRGBGamma();
}
void ColorFilter::initSrgbToLinearGamma() {
filter_ = SkColorFilters::SRGBToLinearGamma();
}
ColorFilter::~ColorFilter() = default;
} // namespace uiwidgets

30
engine/src/lib/ui/painting/color_filter.h


#pragma once
#include <flutter/fml/memory/ref_counted.h>
#include "include/core/SkColorFilter.h"
namespace uiwidgets {
class ColorFilter : public fml::RefCountedThreadSafe<ColorFilter> {
FML_FRIEND_MAKE_REF_COUNTED(ColorFilter);
public:
static fml::RefPtr<ColorFilter> Create();
static sk_sp<SkColorFilter> MakeColorMatrixFilter255(const float array[20]);
void initMode(int color, int blend_mode);
void initMatrix(const float* color_matrix);
void initSrgbToLinearGamma();
void initLinearToSrgbGamma();
~ColorFilter();
sk_sp<SkColorFilter> filter() const { return filter_; }
private:
sk_sp<SkColorFilter> filter_;
};
} // namespace uiwidgets

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


#include "engine_layer.h"
namespace uiwidgets {
EngineLayer::EngineLayer(std::shared_ptr<ContainerLayer> layer)
: layer_(layer) {}
EngineLayer::~EngineLayer() = default;
size_t EngineLayer::GetAllocationSize() { return 3000; };
} // namespace uiwidgets

27
engine/src/lib/ui/painting/engine_layer.h


#pragma once
#include "flow/layers/container_layer.h"
namespace uiwidgets {
class EngineLayer : public fml::RefCountedThreadSafe<EngineLayer> {
public:
~EngineLayer();
size_t GetAllocationSize();
static fml::RefPtr<EngineLayer> MakeRetained(
std::shared_ptr<ContainerLayer> layer) {
return fml::MakeRefCounted<EngineLayer>(layer);
}
std::shared_ptr<ContainerLayer> Layer() const { return layer_; }
private:
explicit EngineLayer(std::shared_ptr<ContainerLayer> layer);
std::shared_ptr<ContainerLayer> layer_;
FML_FRIEND_MAKE_REF_COUNTED(EngineLayer);
};
} // namespace uiwidgets

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


#define _USE_MATH_DEFINES
#include "gradient.h"
namespace uiwidgets {
typedef CanvasGradient Gradient;
fml::RefPtr<CanvasGradient> CanvasGradient::Create() {
return fml::MakeRefCounted<CanvasGradient>();
}
void CanvasGradient::initLinear(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) {
FML_DCHECK(end_points_length == 4);
FML_DCHECK(colors_length == color_stops_length || color_stops == nullptr);
static_assert(sizeof(SkPoint) == sizeof(float) * 2,
"SkPoint doesn't use floats.");
static_assert(sizeof(SkColor) == sizeof(int32_t),
"SkColor doesn't use int32_t.");
SkMatrix sk_matrix;
bool has_matrix = matrix4 != nullptr;
if (has_matrix) {
sk_matrix = ToSkMatrix(matrix4);
}
set_shader(UIMonoState::CreateGPUObject(SkGradientShader::MakeLinear(
reinterpret_cast<const SkPoint*>(end_points),
reinterpret_cast<const SkColor*>(colors), color_stops, colors_length,
tile_mode, 0, has_matrix ? &sk_matrix : nullptr)));
}
void CanvasGradient::initRadial(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) {
FML_DCHECK(colors_length == color_stops_length || color_stops == nullptr);
static_assert(sizeof(SkColor) == sizeof(int32_t),
"SkColor doesn't use int32_t.");
SkMatrix sk_matrix;
bool has_matrix = matrix4 != nullptr;
if (has_matrix) {
sk_matrix = ToSkMatrix(matrix4);
}
set_shader(UIMonoState::CreateGPUObject(SkGradientShader::MakeRadial(
SkPoint::Make(center_x, center_y), radius,
reinterpret_cast<const SkColor*>(colors), color_stops, colors_length,
tile_mode, 0, has_matrix ? &sk_matrix : nullptr)));
}
void CanvasGradient::initSweep(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) {
FML_DCHECK(colors_length == color_stops_length || color_stops == nullptr);
static_assert(sizeof(SkColor) == sizeof(int32_t),
"SkColor doesn't use int32_t.");
SkMatrix sk_matrix;
bool has_matrix = matrix4 != nullptr;
if (has_matrix) {
sk_matrix = ToSkMatrix(matrix4);
}
set_shader(UIMonoState::CreateGPUObject(SkGradientShader::MakeSweep(
center_x, center_y, reinterpret_cast<const SkColor*>(colors), color_stops,
colors_length, tile_mode, start_angle * 180.0 / M_PI,
end_angle * 180.0 / M_PI, 0, has_matrix ? &sk_matrix : nullptr)));
}
void CanvasGradient::initTwoPointConical(
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) {
FML_DCHECK(colors_length == color_stops_length || color_stops == nullptr);
static_assert(sizeof(SkColor) == sizeof(int32_t),
"SkColor doesn't use int32_t.");
SkMatrix sk_matrix;
bool has_matrix = matrix4 != nullptr;
if (has_matrix) {
sk_matrix = ToSkMatrix(matrix4);
}
set_shader(UIMonoState::CreateGPUObject(SkGradientShader::MakeTwoPointConical(
SkPoint::Make(start_x, start_y), start_radius,
SkPoint::Make(end_x, end_y), end_radius,
reinterpret_cast<const SkColor*>(colors), color_stops, colors_length,
tile_mode, 0, has_matrix ? &sk_matrix : nullptr)));
}
CanvasGradient::CanvasGradient() = default;
CanvasGradient::~CanvasGradient() = default;
} // namespace uiwidgets

45
engine/src/lib/ui/painting/gradient.h


#pragma
#include "include/effects/SkGradientShader.h"
#include "lib/ui/painting/matrix.h"
#include "lib/ui/painting/shader.h"
namespace uiwidgets {
// TODO: update this if/when Skia adds Decal mode skbug.com/7638
static_assert(kSkTileModeCount >= 3, "Need to update tile mode enum");
class CanvasGradient : public Shader {
FML_FRIEND_MAKE_REF_COUNTED(CanvasGradient);
public:
~CanvasGradient() override;
static fml::RefPtr<CanvasGradient> Create();
void initLinear(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);
void initRadial(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);
void initSweep(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);
void initTwoPointConical(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);
private:
CanvasGradient();
};
} // namespace uiwidgets

37
engine/src/lib/ui/painting/image_filter.cc


#include "image_filter.h"
#include "include/effects/SkBlurImageFilter.h"
#include "include/effects/SkImageSource.h"
#include "include/effects/SkPictureImageFilter.h"
#include "matrix.h"
namespace uiwidgets {
fml::RefPtr<ImageFilter> ImageFilter::Create() {
return fml::MakeRefCounted<ImageFilter>();
}
ImageFilter::ImageFilter() = default;
ImageFilter::~ImageFilter() = default;
void ImageFilter::initImage(CanvasImage* image) {
filter_ = SkImageSource::Make(image->image());
}
void ImageFilter::initPicture(Picture* picture) {
filter_ = SkPictureImageFilter::Make(picture->picture());
}
void ImageFilter::initBlur(double sigma_x, double sigma_y) {
filter_ = SkBlurImageFilter::Make(sigma_x, sigma_y, nullptr, nullptr,
SkBlurImageFilter::kClamp_TileMode);
}
void ImageFilter::initMatrix(const float* matrix4, int filterQuality) {
filter_ = SkImageFilter::MakeMatrixFilter(
ToSkMatrix(matrix4), static_cast<SkFilterQuality>(filterQuality),
nullptr);
}
} // namespace uiwidgets

29
engine/src/lib/ui/painting/image_filter.h


#pragma once
#include "image.h"
#include "include/core/SkImageFilter.h"
#include "picture.h"
namespace uiwidgets {
class ImageFilter : public fml::RefCountedThreadSafe<ImageFilter> {
FML_FRIEND_MAKE_REF_COUNTED(ImageFilter);
public:
~ImageFilter();
static fml::RefPtr<ImageFilter> Create();
void initImage(CanvasImage* image);
void initPicture(Picture*);
void initBlur(double sigma_x, double sigma_y);
void initMatrix(const float* matrix4, int filter_quality);
const sk_sp<SkImageFilter>& filter() const { return filter_; }
private:
ImageFilter();
sk_sp<SkImageFilter> filter_;
};
} // namespace uiwidgets

26
engine/src/lib/ui/painting/image_shader.cc


#include "image_shader.h"
#include "lib/ui/ui_mono_state.h"
namespace uiwidgets {
fml::RefPtr<ImageShader> ImageShader::Create() {
return fml::MakeRefCounted<ImageShader>();
}
void ImageShader::initWithImage(CanvasImage* image, SkTileMode tmx,
SkTileMode tmy, const float* matrix4) {
if (!image) {
Mono_ThrowException(
"ImageShader constructor called with non-genuine Image.");
}
SkMatrix sk_matrix = ToSkMatrix(matrix4);
set_shader(UIMonoState::CreateGPUObject(
image->image()->makeShader(tmx, tmy, &sk_matrix)));
}
ImageShader::ImageShader() = default;
ImageShader::~ImageShader() = default;
} // namespace uiwidgets

26
engine/src/lib/ui/painting/image_shader.h


#pragma once
#include "gradient.h"
#include "image.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkShader.h"
#include "matrix.h"
#include "shader.h"
namespace uiwidgets {
class ImageShader : public Shader {
FML_FRIEND_MAKE_REF_COUNTED(ImageShader);
public:
~ImageShader() override;
static fml::RefPtr<ImageShader> Create();
void initWithImage(CanvasImage* image, SkTileMode tmx, SkTileMode tmy,
const float* matrix4);
private:
ImageShader();
};
} // namespace uiwidgets

27
engine/src/lib/ui/painting/matrix.cc


#include "matrix.h"
#include "flutter/fml/logging.h"
namespace uiwidgets {
// Mappings from SkMatrix-index to input-index.
static const int kSkMatrixIndexToMatrix4Index[] = {
// clang-format off
0, 4, 12,
1, 5, 13,
3, 7, 15,
// clang-format on
};
SkMatrix ToSkMatrix(const float* matrix4) {
FML_DCHECK(matrix4);
SkMatrix sk_matrix;
for (int i = 0; i < 9; ++i) {
const int matrix4_index = kSkMatrixIndexToMatrix4Index[i];
sk_matrix[i] = matrix4[matrix4_index];
}
return sk_matrix;
}
} // namespace uiwidgets

9
engine/src/lib/ui/painting/matrix.h


#pragma once
#include "include/core/SkMatrix.h"
namespace uiwidgets {
SkMatrix ToSkMatrix(const float* matrix4);
} // namespace uiwidgets

150
engine/src/lib/ui/painting/paint.cc


#include "paint.h"
#include "color_filter.h"
#include "flutter/fml/logging.h"
#include "image_filter.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkImageFilter.h"
#include "include/core/SkMaskFilter.h"
#include "include/core/SkShader.h"
#include "include/core/SkString.h"
#include "shader.h"
namespace uiwidgets {
// Indices for 32bit values.
constexpr int kIsAntiAliasIndex = 0;
constexpr int kColorIndex = 1;
constexpr int kBlendModeIndex = 2;
constexpr int kStyleIndex = 3;
constexpr int kStrokeWidthIndex = 4;
constexpr int kStrokeCapIndex = 5;
constexpr int kStrokeJoinIndex = 6;
constexpr int kStrokeMiterLimitIndex = 7;
constexpr int kFilterQualityIndex = 8;
constexpr int kMaskFilterIndex = 9;
constexpr int kMaskFilterBlurStyleIndex = 10;
constexpr int kMaskFilterSigmaIndex = 11;
constexpr int kInvertColorIndex = 12;
constexpr int kDitherIndex = 13;
constexpr size_t kDataByteCount = 56; // 4 * (last index + 1)
// Indices for objects.
constexpr int kShaderIndex = 0;
constexpr int kColorFilterIndex = 1;
constexpr int kImageFilterIndex = 2;
constexpr int kObjectCount = 3; // One larger than largest object index.
// Must be kept in sync with the default in painting.cs.
constexpr uint32_t kColorDefault = 0xFF000000;
// Must be kept in sync with the default in painting.cs.
constexpr uint32_t kBlendModeDefault =
static_cast<uint32_t>(SkBlendMode::kSrcOver);
// Must be kept in sync with the default in painting.cs, and also with the
// default SkPaintDefaults_MiterLimit in Skia (which is not in a public header).
constexpr double kStrokeMiterLimitDefault = 4.0;
// A color matrix which inverts colors.
// clang-format off
constexpr float invert_colors[20] = {
-1.0, 0, 0, 1.0, 0,
0, -1.0, 0, 1.0, 0,
0, 0, -1.0, 1.0, 0,
1.0, 1.0, 1.0, 1.0, 0
};
// clang-format on
// Must be kept in sync with the MaskFilter private constants in painting.cs.
enum MaskFilterType { Null, Blur };
Paint::Paint(void** paint_objects, uint8_t* paint_data) {
is_null_ = paint_data == nullptr;
if (is_null_) return;
Mono_Handle values[kObjectCount];
if (paint_objects != nullptr) {
auto shader = static_cast<Shader*>(paint_objects[kShaderIndex]);
if (shader) {
paint_.setShader(shader->shader());
}
auto color_filter =
static_cast<ColorFilter*>(paint_objects[kColorFilterIndex]);
if (color_filter) {
paint_.setColorFilter(color_filter->filter());
}
auto image_filter =
static_cast<ImageFilter*>(paint_objects[kImageFilterIndex]);
if (image_filter) {
paint_.setImageFilter(image_filter->filter());
}
}
const uint32_t* uint_data = reinterpret_cast<const uint32_t*>(paint_data);
const float* float_data = reinterpret_cast<const float*>(paint_data);
paint_.setAntiAlias(uint_data[kIsAntiAliasIndex] == 0);
uint32_t encoded_color = uint_data[kColorIndex];
if (encoded_color) {
SkColor color = encoded_color ^ kColorDefault;
paint_.setColor(color);
}
uint32_t encoded_blend_mode = uint_data[kBlendModeIndex];
if (encoded_blend_mode) {
uint32_t blend_mode = encoded_blend_mode ^ kBlendModeDefault;
paint_.setBlendMode(static_cast<SkBlendMode>(blend_mode));
}
uint32_t style = uint_data[kStyleIndex];
if (style) paint_.setStyle(static_cast<SkPaint::Style>(style));
float stroke_width = float_data[kStrokeWidthIndex];
if (stroke_width != 0.0) paint_.setStrokeWidth(stroke_width);
uint32_t stroke_cap = uint_data[kStrokeCapIndex];
if (stroke_cap) paint_.setStrokeCap(static_cast<SkPaint::Cap>(stroke_cap));
uint32_t stroke_join = uint_data[kStrokeJoinIndex];
if (stroke_join)
paint_.setStrokeJoin(static_cast<SkPaint::Join>(stroke_join));
float stroke_miter_limit = float_data[kStrokeMiterLimitIndex];
if (stroke_miter_limit != 0.0)
paint_.setStrokeMiter(stroke_miter_limit + kStrokeMiterLimitDefault);
uint32_t filter_quality = uint_data[kFilterQualityIndex];
if (filter_quality)
paint_.setFilterQuality(static_cast<SkFilterQuality>(filter_quality));
if (uint_data[kInvertColorIndex]) {
sk_sp<SkColorFilter> invert_filter =
ColorFilter::MakeColorMatrixFilter255(invert_colors);
sk_sp<SkColorFilter> current_filter = paint_.refColorFilter();
if (current_filter) {
invert_filter = invert_filter->makeComposed(current_filter);
}
paint_.setColorFilter(invert_filter);
}
if (uint_data[kDitherIndex]) {
paint_.setDither(true);
}
switch (uint_data[kMaskFilterIndex]) {
case Null:
break;
case Blur:
SkBlurStyle blur_style =
static_cast<SkBlurStyle>(uint_data[kMaskFilterBlurStyleIndex]);
double sigma = float_data[kMaskFilterSigmaIndex];
paint_.setMaskFilter(SkMaskFilter::MakeBlur(blur_style, sigma));
break;
}
}
} // namespace uiwidgets

20
engine/src/lib/ui/painting/paint.h


#pragma once
#include "include/core/SkPaint.h"
#include "runtime/mono_api.h"
namespace uiwidgets {
class Paint {
public:
Paint() = default;
Paint(void** paint_objects, uint8_t* paint_data);
const SkPaint* paint() const { return is_null_ ? nullptr : &paint_; }
private:
SkPaint paint_;
bool is_null_ = true;
};
} // namespace uiwidgets

353
engine/src/lib/ui/painting/path.cc


#include "path.h"
#define _USE_MATH_DEFINES
#include <math.h>
#include "matrix.h"
#include "runtime/mono_state.h"
namespace uiwidgets {
typedef CanvasPath Path;
CanvasPath::CanvasPath() {}
CanvasPath::~CanvasPath() {}
int CanvasPath::getFillType() { return static_cast<int>(path_.getFillType()); }
void CanvasPath::setFillType(int fill_type) {
path_.setFillType(static_cast<SkPathFillType>(fill_type));
}
void CanvasPath::moveTo(float x, float y) { path_.moveTo(x, y); }
void CanvasPath::relativeMoveTo(float x, float y) { path_.rMoveTo(x, y); }
void CanvasPath::lineTo(float x, float y) { path_.lineTo(x, y); }
void CanvasPath::relativeLineTo(float x, float y) { path_.rLineTo(x, y); }
void CanvasPath::quadraticBezierTo(float x1, float y1, float x2, float y2) {
path_.quadTo(x1, y1, x2, y2);
}
void CanvasPath::relativeQuadraticBezierTo(float x1, float y1, float x2,
float y2) {
path_.rQuadTo(x1, y1, x2, y2);
}
void CanvasPath::cubicTo(float x1, float y1, float x2, float y2, float x3,
float y3) {
path_.cubicTo(x1, y1, x2, y2, x3, y3);
}
void CanvasPath::relativeCubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
path_.rCubicTo(x1, y1, x2, y2, x3, y3);
}
void CanvasPath::conicTo(float x1, float y1, float x2, float y2, float w) {
path_.conicTo(x1, y1, x2, y2, w);
}
void CanvasPath::relativeConicTo(float x1, float y1, float x2, float y2,
float w) {
path_.rConicTo(x1, y1, x2, y2, w);
}
void CanvasPath::arcTo(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool forceMoveTo) {
path_.arcTo(SkRect::MakeLTRB(left, top, right, bottom),
startAngle * 180.0f / M_PI, sweepAngle * 180.0f / M_PI,
forceMoveTo);
}
void CanvasPath::arcToPoint(float arcEndX, float arcEndY, float radiusX,
float radiusY, float xAxisRotation, bool isLargeArc,
bool isClockwiseDirection) {
const auto arcSize = isLargeArc ? SkPath::ArcSize::kLarge_ArcSize
: SkPath::ArcSize::kSmall_ArcSize;
const auto direction =
isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
path_.arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, arcEndX,
arcEndY);
}
void CanvasPath::relativeArcToPoint(float arcEndDeltaX, float arcEndDeltaY,
float radiusX, float radiusY,
float xAxisRotation, bool isLargeArc,
bool isClockwiseDirection) {
const auto arcSize = isLargeArc ? SkPath::ArcSize::kLarge_ArcSize
: SkPath::ArcSize::kSmall_ArcSize;
const auto direction =
isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
path_.rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
arcEndDeltaX, arcEndDeltaY);
}
void CanvasPath::addRect(float left, float top, float right, float bottom) {
path_.addRect(SkRect::MakeLTRB(left, top, right, bottom));
}
void CanvasPath::addOval(float left, float top, float right, float bottom) {
path_.addOval(SkRect::MakeLTRB(left, top, right, bottom));
}
void CanvasPath::addArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle) {
path_.addArc(SkRect::MakeLTRB(left, top, right, bottom),
startAngle * 180.0f / M_PI, sweepAngle * 180.0 / M_PI);
}
void CanvasPath::addPolygon(float* points, int points_length, bool close) {
path_.addPoly(reinterpret_cast<const SkPoint*>(points), points_length / 2,
close);
}
void CanvasPath::addRRect(const RRect& rrect) {
path_.addRRect(rrect.sk_rrect);
}
void CanvasPath::addPath(CanvasPath* path, float dx, float dy) {
if (!path) Mono_ThrowException("Path.addPath called with non-genuine Path.");
path_.addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode);
}
void CanvasPath::addPathWithMatrix(CanvasPath* path, float dx, float dy,
float* matrix4) {
if (!path) {
Mono_ThrowException("Path.addPathWithMatrix called with non-genuine Path.");
}
SkMatrix matrix = ToSkMatrix(matrix4);
matrix.setTranslateX(matrix.getTranslateX() + dx);
matrix.setTranslateY(matrix.getTranslateY() + dy);
path_.addPath(path->path(), matrix, SkPath::kAppend_AddPathMode);
}
void CanvasPath::extendWithPath(CanvasPath* path, float dx, float dy) {
if (!path)
Mono_ThrowException("Path.extendWithPath called with non-genuine Path.");
path_.addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode);
}
void CanvasPath::extendWithPathAndMatrix(CanvasPath* path, float dx, float dy,
float* matrix4) {
if (!path) {
Mono_ThrowException("Path.addPathWithMatrix called with non-genuine Path.");
}
SkMatrix matrix = ToSkMatrix(matrix4);
matrix.setTranslateX(matrix.getTranslateX() + dx);
matrix.setTranslateY(matrix.getTranslateY() + dy);
path_.addPath(path->path(), matrix, SkPath::kExtend_AddPathMode);
}
void CanvasPath::close() { path_.close(); }
void CanvasPath::reset() { path_.reset(); }
bool CanvasPath::contains(float x, float y) { return path_.contains(x, y); }
fml::RefPtr<CanvasPath> CanvasPath::shift(float dx, float dy) {
fml::RefPtr<CanvasPath> path = CanvasPath::CreateNew();
path_.offset(dx, dy, &path->path_);
return path;
}
fml::RefPtr<CanvasPath> CanvasPath::transform(float* matrix4) {
fml::RefPtr<CanvasPath> path = CanvasPath::CreateNew();
path_.transform(ToSkMatrix(matrix4), &path->path_);
return path;
}
void CanvasPath::getBounds(float* rect) {
const SkRect& bounds = path_.getBounds();
rect[0] = bounds.left();
rect[1] = bounds.top();
rect[2] = bounds.right();
rect[3] = bounds.bottom();
}
bool CanvasPath::op(CanvasPath* path1, CanvasPath* path2, int operation) {
return Op(path1->path(), path2->path(), (SkPathOp)operation, &path_);
}
fml::RefPtr<CanvasPath> CanvasPath::clone() {
fml::RefPtr<CanvasPath> path = CanvasPath::CreateNew();
// per Skia docs, this will create a fast copy
// data is shared until the source path or dest path are mutated
path->path_ = path_;
return path;
}
UIWIDGETS_API(Path*) Path_constructor() {
const auto path = Path::CreateNew();
path->AddRef();
return path.get();
}
UIWIDGETS_API(void) Path_dispose(Path* ptr) { ptr->Release(); }
UIWIDGETS_API(Path*) Path_clone(Path* ptr) {
const auto path = ptr->clone();
path->AddRef();
return path.get();
}
UIWIDGETS_API(int) Path_getFillType(Path* ptr) { return ptr->getFillType(); }
UIWIDGETS_API(void) Path_setFillType(Path* ptr, int fillType) {
ptr->setFillType(fillType);
}
UIWIDGETS_API(void) Path_moveTo(Path* ptr, float x, float y) {
ptr->moveTo(x, y);
}
UIWIDGETS_API(void) Path_relativeMoveTo(Path* ptr, float dx, float dy) {
ptr->relativeMoveTo(dx, dy);
}
UIWIDGETS_API(void) Path_lineTo(Path* ptr, float x, float y) {
ptr->lineTo(x, y);
}
UIWIDGETS_API(void) Path_relativeLineTo(Path* ptr, float dx, float dy) {
ptr->relativeLineTo(dx, dy);
}
UIWIDGETS_API(void)
Path_quadraticBezierTo(Path* ptr, float x1, float y1, float x2, float y2) {
ptr->quadraticBezierTo(x1, y1, x2, y2);
}
UIWIDGETS_API(void)
Path_relativeQuadraticBezierTo(Path* ptr, float x1, float y1, float x2,
float y2) {
ptr->relativeQuadraticBezierTo(x1, y1, x2, y2);
}
UIWIDGETS_API(void)
Path_cubicTo(Path* ptr, float x1, float y1, float x2, float y2, float x3,
float y3) {
ptr->cubicTo(x1, y1, x2, y2, x3, y3);
}
UIWIDGETS_API(void)
Path_relativeCubicTo(Path* ptr, float x1, float y1, float x2, float y2,
float x3, float y3) {
ptr->relativeCubicTo(x1, y1, x2, y2, x3, y3);
}
UIWIDGETS_API(void)
Path_conicTo(Path* ptr, float x1, float y1, float x2, float y2, float w) {
ptr->conicTo(x1, y1, x2, y2, w);
}
UIWIDGETS_API(void)
Path_relativeConicTo(Path* ptr, float x1, float y1, float x2, float y2,
float w) {
ptr->relativeConicTo(x1, y1, x2, y2, w);
}
UIWIDGETS_API(void)
Path_arcTo(Path* ptr, float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool forceMoveTo) {
ptr->arcTo(left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
}
UIWIDGETS_API(void)
Path_arcToPoint(Path* ptr, float arcEndX, float arcEndY, float radiusX,
float radiusY, float rotation, bool largeArc, bool clockwise) {
ptr->arcToPoint(arcEndX, arcEndY, radiusX, radiusY, rotation, largeArc,
clockwise);
}
UIWIDGETS_API(void)
Path_relativeArcToPoint(Path* ptr, float arcEndX, float arcEndY, float radiusX,
float radiusY, float rotation, bool largeArc,
bool clockwise) {
ptr->relativeArcToPoint(arcEndX, arcEndY, radiusX, radiusY, rotation,
largeArc, clockwise);
}
UIWIDGETS_API(void)
Path_addRect(Path* ptr, float left, float top, float right, float bottom) {
ptr->addRect(left, top, right, bottom);
}
UIWIDGETS_API(void)
Path_addOval(Path* ptr, float left, float top, float right, float bottom) {
ptr->addOval(left, top, right, bottom);
}
UIWIDGETS_API(void)
Path_addArc(Path* ptr, float left, float top, float right, float bottom,
float startAngle, float sweepAngle) {
ptr->addArc(left, top, right, bottom, startAngle, sweepAngle);
}
UIWIDGETS_API(void)
Path_addPolygon(Path* ptr, float* points, int pointsLength, bool close) {
ptr->addPolygon(points, pointsLength, close);
}
UIWIDGETS_API(void)
Path_addRRect(Path* ptr, float* value32) { ptr->addRRect(RRect(value32)); }
UIWIDGETS_API(void)
Path_addPathWithMatrix(Path* ptr, Path* path, float dx, float dy,
float* matrix4) {
ptr->addPathWithMatrix(path, dx, dy, matrix4);
}
UIWIDGETS_API(void)
Path_addPath(Path* ptr, Path* path, float dx, float dy) {
ptr->addPath(path, dx, dy);
}
UIWIDGETS_API(void)
Path_extendWithPathAndMatrix(Path* ptr, Path* path, float dx, float dy,
float* matrix4) {
ptr->extendWithPathAndMatrix(path, dx, dy, matrix4);
}
UIWIDGETS_API(void)
Path_extendWithPath(Path* ptr, Path* path, float dx, float dy) {
ptr->extendWithPath(path, dx, dy);
}
UIWIDGETS_API(void)
Path_close(Path* ptr) { ptr->close(); }
UIWIDGETS_API(void)
Path_reset(Path* ptr) { ptr->reset(); }
UIWIDGETS_API(bool)
Path_contains(Path* ptr, float x, float y) { return ptr->contains(x, y); }
UIWIDGETS_API(Path*) Path_shift(Path* ptr, float dx, float dy) {
const auto new_path = ptr->shift(dx, dy);
new_path->AddRef();
return new_path.get();
}
UIWIDGETS_API(Path*) Path_transform(Path* ptr, float* matrix4) {
const auto new_path = ptr->transform(matrix4);
new_path->AddRef();
return new_path.get();
}
UIWIDGETS_API(void) Path_getBounds(Path* ptr, float* rect) {
ptr->getBounds(rect);
}
UIWIDGETS_API(bool)
Path_op(Path* ptr, Path* path1, Path* path2, int operation) {
return ptr->op(path1, path2, operation);
}
} // namespace uiwidgets

71
engine/src/lib/ui/painting/path.h


#pragma once
#include <flutter/fml/memory/ref_counted.h>
#include "include/core/SkPath.h"
#include "include/pathops/SkPathOps.h"
#include "rrect.h"
namespace uiwidgets {
class CanvasPath : public fml::RefCountedThreadSafe<CanvasPath> {
FML_FRIEND_MAKE_REF_COUNTED(CanvasPath);
public:
~CanvasPath();
static fml::RefPtr<CanvasPath> CreateNew() {
return fml::MakeRefCounted<CanvasPath>();
}
int getFillType();
void setFillType(int fill_type);
void moveTo(float x, float y);
void relativeMoveTo(float x, float y);
void lineTo(float x, float y);
void relativeLineTo(float x, float y);
void quadraticBezierTo(float x1, float y1, float x2, float y2);
void relativeQuadraticBezierTo(float x1, float y1, float x2, float y2);
void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3);
void relativeCubicTo(float x1, float y1, float x2, float y2, float x3,
float y3);
void conicTo(float x1, float y1, float x2, float y2, float w);
void relativeConicTo(float x1, float y1, float x2, float y2, float w);
void arcTo(float left, float top, float right, float bottom, float startAngle,
float sweepAngle, bool forceMoveTo);
void arcToPoint(float arcEndX, float arcEndY, float radiusX, float radiusY,
float xAxisRotation, bool isLargeArc,
bool isClockwiseDirection);
void relativeArcToPoint(float arcEndDeltaX, float arcEndDeltaY, float radiusX,
float radiusY, float xAxisRotation, bool isLargeArc,
bool isClockwiseDirection);
void addRect(float left, float top, float right, float bottom);
void addOval(float left, float top, float right, float bottom);
void addArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle);
void addPolygon(float* points, int points_length, bool close);
void addRRect(const RRect& rrect);
void addPath(CanvasPath* path, float dx, float dy);
void addPathWithMatrix(CanvasPath* path, float dx, float dy, float* matrix4);
void extendWithPath(CanvasPath* path, float dx, float dy);
void extendWithPathAndMatrix(CanvasPath* path, float dx, float dy,
float* matrix4);
void close();
void reset();
bool contains(float x, float y);
fml::RefPtr<CanvasPath> shift(float dx, float dy);
fml::RefPtr<CanvasPath> transform(float* matrix4);
void getBounds(float* bounds);
bool op(CanvasPath* path1, CanvasPath* path2, int operation);
fml::RefPtr<CanvasPath> clone();
const SkPath& path() const { return path_; }
private:
CanvasPath();
SkPath path_;
};
} // namespace uiwidgets

21
engine/src/lib/ui/painting/rrect.cc


#include "rrect.h"
namespace uiwidgets {
RRect::RRect(float* buffer) {
is_null = true;
if (buffer == nullptr) return;
SkVector radii[4] = {{buffer[4], buffer[5]},
{buffer[6], buffer[7]},
{buffer[8], buffer[9]},
{buffer[10], buffer[11]}};
sk_rrect.setRectRadii(
SkRect::MakeLTRB(buffer[0], buffer[1], buffer[2], buffer[3]), radii);
is_null = false;
}
} // namespace uiwidgets

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


#pragma once
#include "include/core/SkRRect.h"
namespace uiwidgets {
class RRect {
public:
explicit RRect(float* data);
SkRRect sk_rrect;
bool is_null;
};
} // namespace uiwidgets

9
engine/src/lib/ui/painting/shader.cc


#include "shader.h"
namespace uiwidgets {
Shader::Shader(SkiaGPUObject<SkShader> shader) : shader_(std::move(shader)) {}
Shader::~Shader() = default;
} // namespace uiwidgets

28
engine/src/lib/ui/painting/shader.h


#pragma once
#include "flow/skia_gpu_object.h"
#include "include/core/SkShader.h"
#include "lib/ui/ui_mono_state.h"
namespace uiwidgets {
class Shader : public fml::RefCountedThreadSafe<Shader> {
FML_FRIEND_MAKE_REF_COUNTED(Shader);
public:
virtual ~Shader();
sk_sp<SkShader> shader() { return shader_.get(); }
void set_shader(SkiaGPUObject<SkShader> shader) {
shader_ = std::move(shader);
}
protected:
Shader(SkiaGPUObject<SkShader> shader = {});
private:
SkiaGPUObject<SkShader> shader_;
};
} // namespace uiwidgets

89
engine/src/lib/ui/painting/vertices.cc


#include "vertices.h"
#include <algorithm>
#include "runtime/mono_api.h"
namespace uiwidgets {
namespace {
void DecodePoints(float* coords, int coords_length, SkPoint* points) {
for (int i = 0; i < coords_length; i += 2)
points[i / 2] = SkPoint::Make(coords[i], coords[i + 1]);
}
template <typename T>
void DecodeInts(int32_t* ints, int ints_length, T* out) {
for (int i = 0; i < ints_length; i++) out[i] = ints[i];
}
} // namespace
Vertices::Vertices() = default;
Vertices::~Vertices() = default;
fml::RefPtr<Vertices> Vertices::Create() {
return fml::MakeRefCounted<Vertices>();
}
bool Vertices::init(SkVertices::VertexMode vertex_mode, float* positions,
int positions_length, float* texture_coordinates,
int texture_coordinates_length, int32_t* colors,
int colors_length, uint16_t* indices, int indices_length) {
uint32_t builderFlags = 0;
if (texture_coordinates)
builderFlags |= SkVertices::kHasTexCoords_BuilderFlag;
if (colors) builderFlags |= SkVertices::kHasColors_BuilderFlag;
SkVertices::Builder builder(vertex_mode, positions_length / 2, indices_length,
builderFlags);
if (!builder.isValid()) return false;
// positions are required for SkVertices::Builder
FML_DCHECK(positions);
if (positions) DecodePoints(positions, positions_length, builder.positions());
if (texture_coordinates) {
// SkVertices::Builder assumes equal numbers of elements
FML_DCHECK(positions_length == texture_coordinates_length);
DecodePoints(texture_coordinates, texture_coordinates_length,
builder.texCoords());
}
if (colors) {
// SkVertices::Builder assumes equal numbers of elements
FML_DCHECK(positions_length / 2 == colors_length);
DecodeInts<SkColor>(colors, colors_length, builder.colors());
}
if (indices) {
std::copy(indices, indices + indices_length, builder.indices());
}
vertices_ = builder.detach();
return true;
}
UIWIDGETS_API(Vertices*) Vertices_constructor() {
const auto path = Vertices::Create();
path->AddRef();
return path.get();
}
UIWIDGETS_API(void) Vertices_dispose(Vertices* ptr) { ptr->Release(); }
UIWIDGETS_API(bool)
Vertices_init(Vertices* ptr, SkVertices::VertexMode vertex_mode,
float* positions, int positions_length,
float* texture_coordinates, int texture_coordinates_length,
int32_t* colors, int colors_length, uint16_t* indices,
int indices_length) {
return ptr->init(vertex_mode, positions, positions_length,
texture_coordinates, texture_coordinates_length, colors,
colors_length, indices, indices_length);
}
} // namespace uiwidgets

30
engine/src/lib/ui/painting/vertices.h


#pragma once
#include <flutter/fml/memory/ref_counted.h>
#include "include/core/SkVertices.h"
namespace uiwidgets {
class Vertices : public fml::RefCountedThreadSafe<Vertices> {
FML_FRIEND_MAKE_REF_COUNTED(Vertices);
public:
~Vertices();
static fml::RefPtr<Vertices> Create();
bool init(SkVertices::VertexMode vertex_mode, float* positions,
int positions_length, float* texture_coordinates,
int texture_coordinates_length, int32_t* colors, int colors_length,
uint16_t* indices, int indices_length);
const sk_sp<SkVertices>& vertices() const { return vertices_; }
private:
Vertices();
sk_sp<SkVertices> vertices_;
};
} // namespace uiwidgets

12
engine/src/lib/ui/window/pointer_data.cc


#include "pointer_data.h"
#include <string.h>
namespace uiwidgets {
static_assert(sizeof(PointerData) == kBytesPerField * kPointerDataFieldCount,
"PointerData has the wrong size");
void PointerData::Clear() { memset(this, 0, sizeof(PointerData)); }
} // namespace uiwidgets

83
engine/src/lib/ui/window/pointer_data.h


#pragma once
#include <stdint.h>
namespace uiwidgets {
static constexpr int kPointerDataFieldCount = 28;
static constexpr int kBytesPerField = sizeof(int32_t);
enum PointerButtonMouse : int32_t {
kPointerButtonMousePrimary = 1 << 0,
kPointerButtonMouseSecondary = 1 << 1,
kPointerButtonMouseMiddle = 1 << 2,
kPointerButtonMouseBack = 1 << 3,
kPointerButtonMouseForward = 1 << 4,
};
enum PointerButtonTouch : int32_t {
kPointerButtonTouchContact = 1 << 0,
};
enum PointerButtonStylus : int32_t {
kPointerButtonStylusContact = 1 << 0,
kPointerButtonStylusPrimary = 1 << 1,
kPointerButtonStylusSecondary = 1 << 2,
};
struct alignas(8) PointerData {
enum class Change : int32_t {
kCancel,
kAdd,
kRemove,
kHover,
kDown,
kMove,
kUp,
};
enum class DeviceKind : int32_t {
kTouch,
kMouse,
kStylus,
kInvertedStylus,
};
enum class SignalKind : int32_t {
kNone,
kScroll,
};
int32_t time_stamp;
Change change;
DeviceKind kind;
SignalKind signal_kind;
int32_t device;
int32_t pointer_identifier;
float physical_x;
float physical_y;
float physical_delta_x;
float physical_delta_y;
int32_t buttons;
int32_t obscured;
int32_t synthesized;
float pressure;
float pressure_min;
float pressure_max;
float distance;
float distance_max;
float size;
float radius_major;
float radius_minor;
float radius_min;
float radius_max;
float orientation;
float tilt;
int32_t platformData;
float scroll_delta_x;
float scroll_delta_y;
void Clear();
};
} // namespace uiwidgets

19
engine/src/lib/ui/window/pointer_data_packet.cc


#include "pointer_data_packet.h"
#include <string.h>
namespace uiwidgets {
PointerDataPacket::PointerDataPacket(size_t count)
: data_(count * sizeof(PointerData)) {}
PointerDataPacket::PointerDataPacket(uint8_t* data, size_t num_bytes)
: data_(data, data + num_bytes) {}
PointerDataPacket::~PointerDataPacket() = default;
void PointerDataPacket::SetPointerData(size_t i, const PointerData& data) {
memcpy(&data_[i * sizeof(PointerData)], &data, sizeof(PointerData));
}
} // namespace uiwidgets

27
engine/src/lib/ui/window/pointer_data_packet.h


#pragma once
#include <string.h>
#include <vector>
#include "flutter/fml/macros.h"
#include "pointer_data.h"
namespace uiwidgets {
class PointerDataPacket {
public:
explicit PointerDataPacket(size_t count);
PointerDataPacket(uint8_t* data, size_t num_bytes);
~PointerDataPacket();
void SetPointerData(size_t i, const PointerData& data);
const std::vector<uint8_t>& data() const { return data_; }
private:
std::vector<uint8_t> data_;
FML_DISALLOW_COPY_AND_ASSIGN(PointerDataPacket);
};
} // namespace uiwidgets

281
engine/src/lib/ui/window/pointer_data_packet_converter.cc


#include "pointer_data_packet_converter.h"
#include <string.h>
#include "flutter/fml/logging.h"
namespace uiwidgets {
PointerDataPacketConverter::PointerDataPacketConverter() : pointer_(0) {}
PointerDataPacketConverter::~PointerDataPacketConverter() = default;
std::unique_ptr<PointerDataPacket> PointerDataPacketConverter::Convert(
std::unique_ptr<PointerDataPacket> packet) {
size_t kBytesPerPointerData = kPointerDataFieldCount * kBytesPerField;
auto buffer = packet->data();
size_t buffer_length = buffer.size();
std::vector<PointerData> converted_pointers;
// Converts each pointer data in the buffer and stores it in the
// converted_pointers.
for (size_t i = 0; i < buffer_length / kBytesPerPointerData; i++) {
PointerData pointer_data;
memcpy(&pointer_data, &buffer[i * kBytesPerPointerData],
sizeof(PointerData));
ConvertPointerData(pointer_data, converted_pointers);
}
// Writes converted_pointers into converted_packet.
auto converted_packet =
std::make_unique<PointerDataPacket>(converted_pointers.size());
size_t count = 0;
for (auto& converted_pointer : converted_pointers) {
converted_packet->SetPointerData(count++, converted_pointer);
}
return converted_packet;
}
void PointerDataPacketConverter::ConvertPointerData(
PointerData pointer_data, std::vector<PointerData>& converted_pointers) {
if (pointer_data.signal_kind == PointerData::SignalKind::kNone) {
switch (pointer_data.change) {
case PointerData::Change::kCancel: {
// Android's three finger gesture will send a cancel event
// to a non-existing pointer. Drops the cancel if pointer
// is not previously added.
// https://github.com/flutter/flutter/issues/20517
auto iter = states_.find(pointer_data.device);
if (iter != states_.end()) {
PointerState state = iter->second;
FML_DCHECK(state.isDown);
UpdatePointerIdentifier(pointer_data, state, false);
if (LocationNeedsUpdate(pointer_data, state)) {
// Synthesizes a move event if the location does not match.
PointerData synthesized_move_event = pointer_data;
synthesized_move_event.change = PointerData::Change::kMove;
synthesized_move_event.synthesized = 1;
UpdateDeltaAndState(synthesized_move_event, state);
converted_pointers.push_back(synthesized_move_event);
}
state.isDown = false;
states_[pointer_data.device] = state;
converted_pointers.push_back(pointer_data);
}
break;
}
case PointerData::Change::kAdd: {
FML_DCHECK(states_.find(pointer_data.device) == states_.end());
EnsurePointerState(pointer_data);
converted_pointers.push_back(pointer_data);
break;
}
case PointerData::Change::kRemove: {
// Makes sure we have an existing pointer
auto iter = states_.find(pointer_data.device);
FML_DCHECK(iter != states_.end());
PointerState state = iter->second;
if (state.isDown) {
// Synthesizes cancel event if the pointer is down.
PointerData synthesized_cancel_event = pointer_data;
synthesized_cancel_event.change = PointerData::Change::kCancel;
synthesized_cancel_event.synthesized = 1;
UpdatePointerIdentifier(synthesized_cancel_event, state, false);
state.isDown = false;
states_[synthesized_cancel_event.device] = state;
converted_pointers.push_back(synthesized_cancel_event);
}
if (LocationNeedsUpdate(pointer_data, state)) {
// Synthesizes a hover event if the location does not match.
PointerData synthesized_hover_event = pointer_data;
synthesized_hover_event.change = PointerData::Change::kHover;
synthesized_hover_event.synthesized = 1;
UpdateDeltaAndState(synthesized_hover_event, state);
converted_pointers.push_back(synthesized_hover_event);
}
states_.erase(pointer_data.device);
converted_pointers.push_back(pointer_data);
break;
}
case PointerData::Change::kHover: {
auto iter = states_.find(pointer_data.device);
PointerState state;
if (iter == states_.end()) {
// Synthesizes add event if the pointer is not previously added.
PointerData synthesized_add_event = pointer_data;
synthesized_add_event.change = PointerData::Change::kAdd;
synthesized_add_event.synthesized = 1;
state = EnsurePointerState(synthesized_add_event);
converted_pointers.push_back(synthesized_add_event);
} else {
state = iter->second;
}
FML_DCHECK(!state.isDown);
if (LocationNeedsUpdate(pointer_data, state)) {
UpdateDeltaAndState(pointer_data, state);
converted_pointers.push_back(pointer_data);
}
break;
}
case PointerData::Change::kDown: {
auto iter = states_.find(pointer_data.device);
PointerState state;
if (iter == states_.end()) {
// Synthesizes a add event if the pointer is not previously added.
PointerData synthesized_add_event = pointer_data;
synthesized_add_event.change = PointerData::Change::kAdd;
synthesized_add_event.synthesized = 1;
state = EnsurePointerState(synthesized_add_event);
converted_pointers.push_back(synthesized_add_event);
} else {
state = iter->second;
}
FML_DCHECK(!state.isDown);
if (LocationNeedsUpdate(pointer_data, state)) {
// Synthesizes a hover event if the location does not match.
PointerData synthesized_hover_event = pointer_data;
synthesized_hover_event.change = PointerData::Change::kHover;
synthesized_hover_event.synthesized = 1;
UpdateDeltaAndState(synthesized_hover_event, state);
converted_pointers.push_back(synthesized_hover_event);
}
UpdatePointerIdentifier(pointer_data, state, true);
state.isDown = true;
states_[pointer_data.device] = state;
converted_pointers.push_back(pointer_data);
break;
}
case PointerData::Change::kMove: {
// Makes sure we have an existing pointer in down state
auto iter = states_.find(pointer_data.device);
FML_DCHECK(iter != states_.end());
PointerState state = iter->second;
FML_DCHECK(state.isDown);
if (LocationNeedsUpdate(pointer_data, state)) {
UpdatePointerIdentifier(pointer_data, state, false);
UpdateDeltaAndState(pointer_data, state);
converted_pointers.push_back(pointer_data);
}
break;
}
case PointerData::Change::kUp: {
// Makes sure we have an existing pointer in down state
auto iter = states_.find(pointer_data.device);
FML_DCHECK(iter != states_.end());
PointerState state = iter->second;
FML_DCHECK(state.isDown);
UpdatePointerIdentifier(pointer_data, state, false);
if (LocationNeedsUpdate(pointer_data, state)) {
// Synthesizes a move event if the location does not match.
PointerData synthesized_move_event = pointer_data;
synthesized_move_event.change = PointerData::Change::kMove;
synthesized_move_event.synthesized = 1;
UpdateDeltaAndState(synthesized_move_event, state);
converted_pointers.push_back(synthesized_move_event);
}
state.isDown = false;
states_[pointer_data.device] = state;
converted_pointers.push_back(pointer_data);
break;
}
default: {
converted_pointers.push_back(pointer_data);
break;
}
}
} else {
switch (pointer_data.signal_kind) {
case PointerData::SignalKind::kScroll: {
// Makes sure we have an existing pointer
auto iter = states_.find(pointer_data.device);
FML_DCHECK(iter != states_.end());
PointerState state = iter->second;
if (LocationNeedsUpdate(pointer_data, state)) {
if (state.isDown) {
// Synthesizes a move event if the pointer is down.
PointerData synthesized_move_event = pointer_data;
synthesized_move_event.signal_kind = PointerData::SignalKind::kNone;
synthesized_move_event.change = PointerData::Change::kMove;
synthesized_move_event.synthesized = 1;
UpdateDeltaAndState(synthesized_move_event, state);
converted_pointers.push_back(synthesized_move_event);
} else {
// Synthesizes a hover event if the pointer is up.
PointerData synthesized_hover_event = pointer_data;
synthesized_hover_event.signal_kind =
PointerData::SignalKind::kNone;
synthesized_hover_event.change = PointerData::Change::kHover;
synthesized_hover_event.synthesized = 1;
UpdateDeltaAndState(synthesized_hover_event, state);
converted_pointers.push_back(synthesized_hover_event);
}
}
converted_pointers.push_back(pointer_data);
break;
}
default: {
// Ignores unknown signal kind.
break;
}
}
}
}
PointerState PointerDataPacketConverter::EnsurePointerState(
PointerData pointer_data) {
PointerState state;
state.pointer_identifier = 0;
state.isDown = false;
state.physical_x = pointer_data.physical_x;
state.physical_y = pointer_data.physical_y;
states_[pointer_data.device] = state;
return state;
}
void PointerDataPacketConverter::UpdateDeltaAndState(PointerData& pointer_data,
PointerState& state) {
pointer_data.physical_delta_x = pointer_data.physical_x - state.physical_x;
pointer_data.physical_delta_y = pointer_data.physical_y - state.physical_y;
state.physical_x = pointer_data.physical_x;
state.physical_y = pointer_data.physical_y;
states_[pointer_data.device] = state;
}
bool PointerDataPacketConverter::LocationNeedsUpdate(
const PointerData& pointer_data, const PointerState& state) {
return state.physical_x != pointer_data.physical_x ||
state.physical_y != pointer_data.physical_y;
}
void PointerDataPacketConverter::UpdatePointerIdentifier(
PointerData& pointer_data, PointerState& state, bool start_new_pointer) {
if (start_new_pointer) {
state.pointer_identifier = ++pointer_;
states_[pointer_data.device] = state;
}
pointer_data.pointer_identifier = state.pointer_identifier;
}
} // namespace uiwidgets

50
engine/src/lib/ui/window/pointer_data_packet_converter.h


#pragma once
#include <string.h>
#include <map>
#include <memory>
#include <vector>
#include "flutter/fml/macros.h"
#include "pointer_data_packet.h"
namespace uiwidgets {
struct PointerState {
int32_t pointer_identifier;
bool isDown;
float physical_x;
float physical_y;
};
class PointerDataPacketConverter {
public:
PointerDataPacketConverter();
~PointerDataPacketConverter();
std::unique_ptr<PointerDataPacket> Convert(
std::unique_ptr<PointerDataPacket> packet);
private:
std::map<int32_t, PointerState> states_;
int32_t pointer_;
void ConvertPointerData(PointerData pointer_data,
std::vector<PointerData>& converted_pointers);
PointerState EnsurePointerState(PointerData pointer_data);
void UpdateDeltaAndState(PointerData& pointer_data, PointerState& state);
void UpdatePointerIdentifier(PointerData& pointer_data, PointerState& state,
bool start_new_pointer);
bool LocationNeedsUpdate(const PointerData& pointer_data,
const PointerState& state);
FML_DISALLOW_COPY_AND_ASSIGN(PointerDataPacketConverter);
};
} // namespace uiwidgets

68
engine/src/lib/ui/window/viewport_metrics.cc


#include "viewport_metrics.h"
#include "flutter/fml/logging.h"
namespace uiwidgets {
ViewportMetrics::ViewportMetrics(
float p_device_pixel_ratio, float p_physical_width, float p_physical_height,
float p_physical_padding_top, float p_physical_padding_right,
float p_physical_padding_bottom, float p_physical_padding_left,
float p_physical_view_inset_top, float p_physical_view_inset_right,
float p_physical_view_inset_bottom, float p_physical_view_inset_left,
float p_physical_system_gesture_inset_top,
float p_physical_system_gesture_inset_right,
float p_physical_system_gesture_inset_bottom,
float p_physical_system_gesture_inset_left)
: device_pixel_ratio(p_device_pixel_ratio),
physical_width(p_physical_width),
physical_height(p_physical_height),
physical_padding_top(p_physical_padding_top),
physical_padding_right(p_physical_padding_right),
physical_padding_bottom(p_physical_padding_bottom),
physical_padding_left(p_physical_padding_left),
physical_view_inset_top(p_physical_view_inset_top),
physical_view_inset_right(p_physical_view_inset_right),
physical_view_inset_bottom(p_physical_view_inset_bottom),
physical_view_inset_left(p_physical_view_inset_left),
physical_system_gesture_inset_top(p_physical_system_gesture_inset_top),
physical_system_gesture_inset_right(
p_physical_system_gesture_inset_right),
physical_system_gesture_inset_bottom(
p_physical_system_gesture_inset_bottom),
physical_system_gesture_inset_left(p_physical_system_gesture_inset_left) {
// Ensure we don't have nonsensical dimensions.
FML_DCHECK(physical_width >= 0);
FML_DCHECK(physical_height >= 0);
FML_DCHECK(device_pixel_ratio > 0);
}
ViewportMetrics::ViewportMetrics(
float p_device_pixel_ratio, float p_physical_width, float p_physical_height,
float p_physical_depth, float p_physical_padding_top,
float p_physical_padding_right, float p_physical_padding_bottom,
float p_physical_padding_left, float p_physical_view_inset_front,
float p_physical_view_inset_back, float p_physical_view_inset_top,
float p_physical_view_inset_right, float p_physical_view_inset_bottom,
float p_physical_view_inset_left)
: device_pixel_ratio(p_device_pixel_ratio),
physical_width(p_physical_width),
physical_height(p_physical_height),
physical_depth(p_physical_depth),
physical_padding_top(p_physical_padding_top),
physical_padding_right(p_physical_padding_right),
physical_padding_bottom(p_physical_padding_bottom),
physical_padding_left(p_physical_padding_left),
physical_view_inset_top(p_physical_view_inset_top),
physical_view_inset_right(p_physical_view_inset_right),
physical_view_inset_bottom(p_physical_view_inset_bottom),
physical_view_inset_left(p_physical_view_inset_left),
physical_view_inset_front(p_physical_view_inset_front),
physical_view_inset_back(p_physical_view_inset_back) {
// Ensure we don't have nonsensical dimensions.
FML_DCHECK(physical_width >= 0);
FML_DCHECK(physical_height >= 0);
FML_DCHECK(device_pixel_ratio > 0);
}
} // namespace uiwidgets

79
engine/src/lib/ui/window/viewport_metrics.h


#pragma once
namespace uiwidgets {
static const float kUnsetDepth = 3.402823E+38f;
struct ViewportMetrics {
ViewportMetrics() = default;
ViewportMetrics(const ViewportMetrics& other) = default;
// Create a 2D ViewportMetrics instance.
ViewportMetrics(float p_device_pixel_ratio, float p_physical_width,
float p_physical_height, float p_physical_padding_top,
float p_physical_padding_right,
float p_physical_padding_bottom,
float p_physical_padding_left,
float p_physical_view_inset_top,
float p_physical_view_inset_right,
float p_physical_view_inset_bottom,
float p_physical_view_inset_left,
float p_physical_system_gesture_inset_top,
float p_physical_system_gesture_inset_right,
float p_physical_system_gesture_inset_bottom,
float p_physical_system_gesture_inset_left);
// Create a ViewportMetrics instance that contains z information.
ViewportMetrics(
float p_device_pixel_ratio, float p_physical_width,
float p_physical_height, float p_physical_depth,
float p_physical_padding_top, float p_physical_padding_right,
float p_physical_padding_bottom, float p_physical_padding_left,
float p_physical_view_inset_front, float p_physical_view_inset_back,
float p_physical_view_inset_top, float p_physical_view_inset_right,
float p_physical_view_inset_bottom, float p_physical_view_inset_left);
float device_pixel_ratio = 1.0f;
float physical_width = 0;
float physical_height = 0;
float physical_depth = kUnsetDepth;
float physical_padding_top = 0;
float physical_padding_right = 0;
float physical_padding_bottom = 0;
float physical_padding_left = 0;
float physical_view_inset_top = 0;
float physical_view_inset_right = 0;
float physical_view_inset_bottom = 0;
float physical_view_inset_left = 0;
float physical_view_inset_front = kUnsetDepth;
float physical_view_inset_back = kUnsetDepth;
float physical_system_gesture_inset_top = 0;
float physical_system_gesture_inset_right = 0;
float physical_system_gesture_inset_bottom = 0;
float physical_system_gesture_inset_left = 0;
};
struct LogicalSize {
float width = 0.0f;
float height = 0.0f;
float depth = kUnsetDepth;
};
struct LogicalInset {
float left = 0.0f;
float top = 0.0f;
float right = 0.0f;
float bottom = 0.0f;
float front = kUnsetDepth;
float back = kUnsetDepth;
};
struct LogicalMetrics {
LogicalSize size;
float scale = 1.0f;
float scale_z = 1.0f;
LogicalInset padding;
LogicalInset view_inset;
};
} // namespace uiwidgets

270
engine/src/runtime/runtime_controller.cc


#include "runtime_controller.h"
#include "flutter/fml/message_loop.h"
#include "flutter/fml/trace_event.h"
#include "lib/ui/compositing/scene.h"
#include "lib/ui/ui_mono_state.h"
#include "lib/ui/window/window.h"
#include "runtime_delegate.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_, //
image_decoder_ //
)
.lock();
FML_CHECK(strong_root_isolate) << "Could not create root isolate.";
// The root isolate ivar is weak.
root_isolate_ = strong_root_isolate;
if (auto* window = GetWindowIfAvailable()) {
MonoState::Scope scope(strong_root_isolate);
window->DidCreateIsolate();
if (!FlushRuntimeStateToIsolate()) {
FML_DLOG(ERROR) << "Could not setup initial isolate state.";
}
} else {
FML_DCHECK(false) << "RuntimeController created without window binding.";
}
FML_DCHECK(Mono_CurrentIsolate() == nullptr);
}
RuntimeController::~RuntimeController() {
FML_DCHECK(Mono_CurrentIsolate() == nullptr);
std::shared_ptr<MonoIsolate> root_isolate = root_isolate_.lock();
if (root_isolate) {
auto result = root_isolate->Shutdown();
if (!result) {
FML_DLOG(ERROR) << "Could not shutdown the root isolate.";
}
root_isolate_ = {};
}
}
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;
}
std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
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_ //
));
}
bool RuntimeController::FlushRuntimeStateToIsolate() {
return SetViewportMetrics(window_data_.viewport_metrics) &&
SetLocales(window_data_.locale_data) &&
SetAccessibilityFeatures(window_data_.accessibility_feature_flags_) &&
SetUserSettingsData(window_data_.user_settings_data) &&
SetLifecycleState(window_data_.lifecycle_state);
}
bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) {
window_data_.viewport_metrics = metrics;
if (auto* window = GetWindowIfAvailable()) {
window->UpdateWindowMetrics(metrics);
return true;
}
return false;
}
bool RuntimeController::SetLocales(
const std::vector<std::string>& locale_data) {
window_data_.locale_data = locale_data;
if (auto* window = GetWindowIfAvailable()) {
window->UpdateLocales(locale_data);
return true;
}
return false;
}
bool RuntimeController::SetUserSettingsData(const std::string& data) {
window_data_.user_settings_data = data;
if (auto* window = GetWindowIfAvailable()) {
window->UpdateUserSettingsData(window_data_.user_settings_data);
return true;
}
return false;
}
bool RuntimeController::SetLifecycleState(const std::string& data) {
window_data_.lifecycle_state = data;
if (auto* window = GetWindowIfAvailable()) {
window->UpdateLifecycleState(window_data_.lifecycle_state);
return true;
}
return false;
}
bool RuntimeController::SetAccessibilityFeatures(int32_t flags) {
window_data_.accessibility_feature_flags_ = flags;
if (auto* window = GetWindowIfAvailable()) {
window->UpdateAccessibilityFeatures(
window_data_.accessibility_feature_flags_);
return true;
}
return false;
}
bool RuntimeController::BeginFrame(fml::TimePoint frame_time) {
if (auto* window = GetWindowIfAvailable()) {
window->BeginFrame(frame_time);
return true;
}
return false;
}
bool RuntimeController::ReportTimings(std::vector<int64_t> timings) {
if (auto* window = GetWindowIfAvailable()) {
window->ReportTimings(std::move(timings));
return true;
}
return false;
}
bool RuntimeController::NotifyIdle(int64_t deadline) {
std::shared_ptr<MonoIsolate> root_isolate = root_isolate_.lock();
if (!root_isolate) {
return false;
}
MonoState::Scope scope(root_isolate);
Mono_NotifyIdle(deadline);
// 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;
}
bool RuntimeController::DispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
"mode", "basic");
window->DispatchPlatformMessage(std::move(message));
return true;
}
return false;
}
bool RuntimeController::DispatchPointerDataPacket(
const PointerDataPacket& packet) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket",
"mode", "basic");
window->DispatchPointerDataPacket(packet);
return true;
}
return false;
}
Window* RuntimeController::GetWindowIfAvailable() {
std::shared_ptr<MonoIsolate> root_isolate = root_isolate_.lock();
return root_isolate ? root_isolate->window() : nullptr;
}
// |WindowClient|
std::string RuntimeController::DefaultRouteName() {
return client_.DefaultRouteName();
}
// |WindowClient|
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
// |WindowClient|
void RuntimeController::Render(Scene* scene) {
client_.Render(scene->takeLayerTree());
}
// |WindowClient|
void RuntimeController::HandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) {
client_.HandlePlatformMessage(std::move(message));
}
// |WindowClient|
FontCollection& RuntimeController::GetFontCollection() {
// return client_.GetFontCollection();
//return nullptr;
}
// |WindowClient|
void RuntimeController::SetNeedsReportTimings(bool value) {
client_.SetNeedsReportTimings(value);
}
RuntimeController::Locale::Locale(std::string language_code_,
std::string country_code_,
std::string script_code_,
std::string variant_code_)
: language_code(language_code_),
country_code(country_code_),
script_code(script_code_),
variant_code(variant_code_) {}
RuntimeController::Locale::~Locale() = default;
} // namespace flutter

123
engine/src/runtime/runtime_controller.h


#pragma once
#include <memory>
#include <vector>
#include "common/task_runners.h"
#include "flow/layers/layer_tree.h"
#include "flutter/fml/macros.h"
#include "lib/ui/io_manager.h"
//#include "lib/ui/text/font_collection.h"
#include "lib/ui/ui_mono_state.h"
#include "lib/ui/window/pointer_data_packet.h"
#include "lib/ui/window/window.h"
#include "mono_isolate.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "runtime/window_data.h"
namespace uiwidgets {
class Scene;
class RuntimeDelegate;
class View;
class Window;
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() override;
std::unique_ptr<RuntimeController> Clone() const;
bool SetViewportMetrics(const ViewportMetrics& metrics);
bool SetLocales(const std::vector<std::string>& locale_data);
bool SetUserSettingsData(const std::string& data);
bool SetLifecycleState(const std::string& data);
bool SetAccessibilityFeatures(int32_t flags);
bool BeginFrame(fml::TimePoint frame_time);
bool ReportTimings(std::vector<int64_t> timings);
bool NotifyIdle(int64_t deadline);
bool IsRootIsolateRunning() const;
bool DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
bool DispatchPointerDataPacket(const PointerDataPacket& packet);
std::weak_ptr<MonoIsolate> GetRootIsolate();
private:
struct Locale {
Locale(std::string language_code_, std::string country_code_,
std::string script_code_, std::string variant_code_);
~Locale();
std::string language_code;
std::string country_code;
std::string script_code;
std::string variant_code;
};
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_;
std::function<void(int64_t)> idle_notification_callback_;
WindowData window_data_;
std::weak_ptr<MonoIsolate> root_isolate_;
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();
bool FlushRuntimeStateToIsolate();
// |WindowClient|
std::string DefaultRouteName() override;
// |WindowClient|
void ScheduleFrame() override;
// |WindowClient|
void Render(Scene* scene) override;
// |WindowClient|
void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
// |WindowClient|
FontCollection& GetFontCollection() override;
// |WindowClient|
void SetNeedsReportTimings(bool value) override;
FML_DISALLOW_COPY_AND_ASSIGN(RuntimeController);
};
} // namespace uiwidgets

7
engine/src/runtime/runtime_delegate.cc


#include "runtime_delegate.h"
namespace uiwidgets {
RuntimeDelegate::~RuntimeDelegate() = default;
} // namespace uiwidgets

30
engine/src/runtime/runtime_delegate.h


#pragma once
#include <memory>
#include <vector>
#include "flow/layers/layer_tree.h"
//#include "lib/ui/text/font_collection.h"
#include "lib/ui/window/platform_message.h"
namespace uiwidgets {
class RuntimeDelegate {
public:
virtual std::string DefaultRouteName() = 0;
virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0;
virtual void Render(std::unique_ptr<LayerTree> layer_tree) = 0;
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
// virtual FontCollection& GetFontCollection() = 0;
virtual void SetNeedsReportTimings(bool value) = 0;
protected:
virtual ~RuntimeDelegate();
};
} // namespace uiwidgets

8
engine/src/runtime/window_data.cc


#include "window_data.h"
namespace uiwidgets {
WindowData::WindowData() = default;
WindowData::~WindowData() = default;
} // namespace uiwidgets

27
engine/src/runtime/window_data.h


#pragma once
#include <memory>
#include <string>
#include <vector>
#include "lib/ui/window/viewport_metrics.h"
namespace uiwidgets {
struct WindowData {
WindowData();
~WindowData();
ViewportMetrics viewport_metrics;
std::string language_code;
std::string country_code;
std::string script_code;
std::string variant_code;
std::vector<std::string> locale_data;
std::string user_settings_data = "{}";
std::string lifecycle_state;
int32_t accessibility_feature_flags_ = 0;
};
} // namespace uiwidgets

502
engine/src/shell/common/engine.cc


#include "engine.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "common/settings.h"
#include "flutter/fml/eintr_wrapper.h"
#include "flutter/fml/file.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/trace_event.h"
#include "flutter/fml/unique_fd.h"
//#include "lib/snapshot/snapshot.h"
//#include "lib/ui/text/font_collection.h"
#include "shell/common/animator.h"
#include "shell/common/platform_view.h"
#include "shell/common/shell.h"
#include "rapidjson/document.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPictureRecorder.h"
namespace uiwidgets {
static constexpr char kAssetChannel[] = "uiwidgets/assets";
static constexpr char kLifecycleChannel[] = "uiwidgets/lifecycle";
static constexpr char kNavigationChannel[] = "uiwidgets/navigation";
static constexpr char kLocalizationChannel[] = "uiwidgets/localization";
static constexpr char kSettingsChannel[] = "uiwidgets/settings";
static constexpr char kIsolateChannel[] = "uiwidgets/isolate";
Engine::Engine(Delegate& delegate,
const PointerDataDispatcherMaker& dispatcher_maker,
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
std::unique_ptr<Animator> animator,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate)
: delegate_(delegate),
settings_(std::move(settings)),
animator_(std::move(animator)),
activity_running_(true),
have_surface_(false),
image_decoder_(task_runners,
vm.GetConcurrentWorkerTaskRunner(),
io_manager),
task_runners_(std::move(task_runners)),
weak_factory_(this) {
// Runtime controller is initialized here because it takes a reference to this
// object as its delegate. The delegate may be called in the constructor and
// we want to be fully initilazed by that point.
runtime_controller_ = std::make_unique<RuntimeController>(
*this, // runtime delegate
&vm, // VM
std::move(isolate_snapshot), // isolate snapshot
task_runners_, // task runners
std::move(snapshot_delegate),
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
);
pointer_data_dispatcher_ = dispatcher_maker(*this);
}
Engine::~Engine() = default;
float Engine::GetDisplayRefreshRate() const {
return animator_->GetDisplayRefreshRate();
}
fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
return weak_factory_.GetWeakPtr();
}
bool Engine::UpdateAssetManager(
std::shared_ptr<AssetManager> new_asset_manager) {
if (asset_manager_ == new_asset_manager) {
return false;
}
asset_manager_ = new_asset_manager;
if (!asset_manager_) {
return false;
}
// Using libTXT as the text engine.
font_collection_.RegisterFonts(asset_manager_);
if (settings_.use_test_fonts) {
font_collection_.RegisterTestFonts();
}
return true;
}
bool Engine::Restart(RunConfiguration configuration) {
TRACE_EVENT0("flutter", "Engine::Restart");
if (!configuration.IsValid()) {
FML_LOG(ERROR) << "Engine run configuration was invalid.";
return false;
}
delegate_.OnPreEngineRestart();
runtime_controller_ = runtime_controller_->Clone();
UpdateAssetManager(nullptr);
return Run(std::move(configuration)) == Engine::RunStatus::Success;
}
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
if (!configuration.IsValid()) {
FML_LOG(ERROR) << "Engine run configuration was invalid.";
return RunStatus::Failure;
}
last_entry_point_ = configuration.GetEntrypoint();
last_entry_point_library_ = configuration.GetEntrypointLibrary();
auto isolate_launch_status =
PrepareAndLaunchIsolate(std::move(configuration));
if (isolate_launch_status == Engine::RunStatus::Failure) {
FML_LOG(ERROR) << "Engine not prepare and launch isolate.";
return isolate_launch_status;
} else if (isolate_launch_status ==
Engine::RunStatus::FailureAlreadyRunning) {
return 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;
}
Engine::RunStatus Engine::PrepareAndLaunchIsolate(
RunConfiguration configuration) {
TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate");
UpdateAssetManager(configuration.GetAssetManager());
auto isolate_configuration = configuration.TakeIsolateConfiguration();
std::shared_ptr<DartIsolate> isolate =
runtime_controller_->GetRootIsolate().lock();
if (!isolate) {
return RunStatus::Failure;
}
// 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;
}
}
return RunStatus::Success;
}
void Engine::BeginFrame(fml::TimePoint frame_time) {
TRACE_EVENT0("flutter", "Engine::BeginFrame");
runtime_controller_->BeginFrame(frame_time);
}
void Engine::ReportTimings(std::vector<int64_t> timings) {
TRACE_EVENT0("flutter", "Engine::ReportTimings");
runtime_controller_->ReportTimings(std::move(timings));
}
void Engine::NotifyIdle(int64_t deadline) {
auto trace_event = std::to_string(deadline - Dart_TimelineGetMicros());
TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
trace_event.c_str());
runtime_controller_->NotifyIdle(deadline);
}
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();
ScheduleFrame();
}
void Engine::OnOutputSurfaceDestroyed() {
have_surface_ = false;
StopAnimator();
}
void Engine::SetViewportMetrics(const ViewportMetrics& metrics) {
bool dimensions_changed =
viewport_metrics_.physical_height != metrics.physical_height ||
viewport_metrics_.physical_width != metrics.physical_width ||
viewport_metrics_.physical_depth != metrics.physical_depth;
viewport_metrics_ = metrics;
runtime_controller_->SetViewportMetrics(viewport_metrics_);
if (animator_) {
if (dimensions_changed)
animator_->SetDimensionChangePending();
if (have_surface_)
ScheduleFrame();
}
}
void Engine::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (message->channel() == kLifecycleChannel) {
if (HandleLifecyclePlatformMessage(message.get()))
return;
} else if (message->channel() == kLocalizationChannel) {
if (HandleLocalizationPlatformMessage(message.get()))
return;
} else if (message->channel() == kSettingsChannel) {
HandleSettingsPlatformMessage(message.get());
return;
}
if (runtime_controller_->IsRootIsolateRunning() &&
runtime_controller_->DispatchPlatformMessage(std::move(message))) {
return;
}
// If there's no runtime_, we may still need to set the initial route.
if (message->channel() == kNavigationChannel) {
HandleNavigationPlatformMessage(std::move(message));
return;
}
FML_DLOG(WARNING) << "Dropping platform message on channel: "
<< message->channel();
}
bool Engine::HandleLifecyclePlatformMessage(PlatformMessage* message) {
const auto& data = message->data();
std::string state(reinterpret_cast<const char*>(data.data()), data.size());
if (state == "AppLifecycleState.paused" ||
state == "AppLifecycleState.detached") {
activity_running_ = false;
StopAnimator();
} else if (state == "AppLifecycleState.resumed" ||
state == "AppLifecycleState.inactive") {
activity_running_ = true;
StartAnimatorIfPossible();
}
// Always schedule a frame when the app does become active as per API
// recommendation
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive?language=objc
if (state == "AppLifecycleState.resumed" && have_surface_) {
ScheduleFrame();
}
runtime_controller_->SetLifecycleState(state);
// Always forward these messages to the framework by returning false.
return false;
}
bool Engine::HandleNavigationPlatformMessage(
fml::RefPtr<PlatformMessage> message) {
const auto& data = message->data();
rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return false;
auto root = document.GetObject();
auto method = root.FindMember("method");
if (method->value != "setInitialRoute")
return false;
auto route = root.FindMember("args");
initial_route_ = std::move(route->value.GetString());
return true;
}
bool Engine::HandleLocalizationPlatformMessage(PlatformMessage* message) {
const auto& data = message->data();
rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return false;
auto root = document.GetObject();
auto method = root.FindMember("method");
if (method == root.MemberEnd() || method->value != "setLocale")
return false;
auto args = root.FindMember("args");
if (args == root.MemberEnd() || !args->value.IsArray())
return false;
const size_t strings_per_locale = 4;
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) {
if (!args->value[locale_index].IsString() ||
!args->value[locale_index + 1].IsString())
return false;
locale_data.push_back(args->value[locale_index].GetString());
locale_data.push_back(args->value[locale_index + 1].GetString());
locale_data.push_back(args->value[locale_index + 2].GetString());
locale_data.push_back(args->value[locale_index + 3].GetString());
}
return runtime_controller_->SetLocales(locale_data);
}
void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) {
const auto& data = message->data();
std::string jsonData(reinterpret_cast<const char*>(data.data()), data.size());
if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) &&
have_surface_) {
ScheduleFrame();
}
}
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);
pointer_data_dispatcher_->DispatchPacket(std::move(packet), trace_flow_id);
}
void Engine::SetAccessibilityFeatures(int32_t flags) {
runtime_controller_->SetAccessibilityFeatures(flags);
}
void Engine::StopAnimator() {
animator_->Stop();
}
void Engine::StartAnimatorIfPossible() {
if (activity_running_ && have_surface_)
animator_->Start();
}
std::string Engine::DefaultRouteName() {
if (!initial_route_.empty()) {
return initial_route_;
}
return "/";
}
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
animator_->RequestFrame(regenerate_layer_tree);
}
void Engine::Render(std::unique_ptr<uiwidgets::LayerTree> layer_tree) {
if (!layer_tree)
return;
// Ensure frame dimensions are sane.
if (layer_tree->frame_size().isEmpty() ||
layer_tree->frame_physical_depth() <= 0.0f ||
layer_tree->frame_device_pixel_ratio() <= 0.0f)
return;
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));
} else {
delegate_.OnEngineHandlePlatformMessage(std::move(message));
}
}
void Engine::UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) {
delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
}
void Engine::SetNeedsReportTimings(bool needs_reporting) {
delegate_.SetNeedsReportTimings(needs_reporting);
}
FontCollection& Engine::GetFontCollection() {
return font_collection_;
}
void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) {
animator_->EnqueueTraceFlowId(trace_flow_id);
if (runtime_controller_) {
runtime_controller_->DispatchPointerDataPacket(*packet);
}
}
void Engine::ScheduleSecondaryVsyncCallback(const fml::closure& callback) {
animator_->ScheduleSecondaryVsyncCallback(callback);
}
void Engine::HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message) {
fml::RefPtr<PlatformMessageResponse> response = message->response();
if (!response) {
return;
}
const auto& data = message->data();
std::string asset_name(reinterpret_cast<const char*>(data.data()),
data.size());
if (asset_manager_) {
std::unique_ptr<fml::Mapping> asset_mapping =
asset_manager_->GetAsMapping(asset_name);
if (asset_mapping) {
response->Complete(std::move(asset_mapping));
return;
}
}
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

149
engine/src/shell/common/engine.h


#pragma once
#include <memory>
#include <string>
#include "assets/asset_manager.h"
#include "common/task_runners.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "lib/ui/painting/image_decoder.h"
#include "lib/ui/snapshot_delegate.h"
//#include "lib/ui/text/font_collection.h"
#include "include/core/SkPicture.h"
#include "lib/ui/window/platform_message.h"
#include "lib/ui/window/viewport_metrics.h"
#include "runtime/runtime_controller.h"
#include "runtime/runtime_delegate.h"
#include "shell/common/animator.h"
#include "shell/common/platform_view.h"
#include "shell/common/pointer_data_dispatcher.h"
#include "shell/common/rasterizer.h"
#include "shell/common/run_configuration.h"
#include "shell/common/shell_io_manager.h"
namespace uiwidgets {
class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
public:
enum class RunStatus {
Success,
FailureAlreadyRunning,
Failure,
};
class Delegate {
public:
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;
};
Engine(Delegate& delegate, const PointerDataDispatcherMaker& dispatcher_maker,
TaskRunners task_runners, const WindowData window_data,
Settings settings, std::unique_ptr<Animator> animator,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate);
~Engine() override;
float GetDisplayRefreshRate() const;
fml::WeakPtr<Engine> GetWeakPtr() const;
[[nodiscard]] RunStatus Run(RunConfiguration configuration);
[[nodiscard]] bool Restart(RunConfiguration configuration);
bool UpdateAssetManager(std::shared_ptr<AssetManager> asset_manager);
void BeginFrame(fml::TimePoint frame_time);
void NotifyIdle(int64_t deadline);
void ReportTimings(std::vector<int64_t> timings);
void OnOutputSurfaceCreated();
void OnOutputSurfaceDestroyed();
void SetViewportMetrics(const ViewportMetrics& metrics);
void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id);
void SetAccessibilityFeatures(int32_t flags);
void ScheduleFrame(bool regenerate_layer_tree = true) override;
// |RuntimeDelegate|
// FontCollection& GetFontCollection() override;
// |PointerDataDispatcher::Delegate|
void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) override;
// |PointerDataDispatcher::Delegate|
void ScheduleSecondaryVsyncCallback(const fml::closure& callback) override;
private:
Engine::Delegate& delegate_;
const Settings settings_;
std::unique_ptr<Animator> animator_;
std::unique_ptr<RuntimeController> runtime_controller_;
// The pointer_data_dispatcher_ depends on animator_ and runtime_controller_.
// So it should be defined after them to ensure that pointer_data_dispatcher_
// is destructed first.
std::unique_ptr<PointerDataDispatcher> pointer_data_dispatcher_;
std::string last_entry_point_;
std::string last_entry_point_library_;
std::string initial_route_;
ViewportMetrics viewport_metrics_;
// std::shared_ptr<AssetManager> asset_manager_;
bool activity_running_;
bool have_surface_;
FontCollection font_collection_;
ImageDecoder image_decoder_;
TaskRunners task_runners_;
fml::WeakPtrFactory<Engine> weak_factory_;
// |RuntimeDelegate|
std::string DefaultRouteName() override;
// |RuntimeDelegate|
void Render(std::unique_ptr<LayerTree> layer_tree) override;
// |RuntimeDelegate|
void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
void SetNeedsReportTimings(bool value) override;
void StopAnimator();
void StartAnimatorIfPossible();
bool HandleLifecyclePlatformMessage(PlatformMessage* message);
bool HandleNavigationPlatformMessage(fml::RefPtr<PlatformMessage> message);
bool HandleLocalizationPlatformMessage(PlatformMessage* message);
void HandleSettingsPlatformMessage(PlatformMessage* message);
void HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message);
bool GetAssetAsBuffer(const std::string& name, std::vector<uint8_t>* data);
RunStatus PrepareAndLaunchIsolate(RunConfiguration configuration);
FML_DISALLOW_COPY_AND_ASSIGN(Engine);
};
} // namespace uiwidgets

119
engine/src/shell/common/platform_view.cc


#include "platform_view.h"
#include <utility>
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "include/gpu/GrContextOptions.h"
#include "include/gpu/gl/GrGLInterface.h"
#include "shell/common/rasterizer.h"
#include "shell/common/vsync_waiter_fallback.h"
namespace uiwidgets {
PlatformView::PlatformView(Delegate& delegate, TaskRunners task_runners)
: delegate_(delegate),
task_runners_(std::move(task_runners)),
size_(SkISize::Make(0, 0)),
weak_factory_(this) {}
PlatformView::~PlatformView() = default;
std::unique_ptr<VsyncWaiter> PlatformView::CreateVSyncWaiter() {
FML_DLOG(WARNING)
<< "This platform does not provide a Vsync waiter implementation. A "
"simple timer based fallback is being used.";
return std::make_unique<VsyncWaiterFallback>(task_runners_);
}
void PlatformView::DispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) {
delegate_.OnPlatformViewDispatchPlatformMessage(std::move(message));
}
void PlatformView::DispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) {
delegate_.OnPlatformViewDispatchPointerDataPacket(
pointer_data_packet_converter_.Convert(std::move(packet)));
}
void PlatformView::SetAccessibilityFeatures(int32_t flags) {
delegate_.OnPlatformViewSetAccessibilityFeatures(flags);
}
void PlatformView::SetViewportMetrics(const ViewportMetrics& metrics) {
delegate_.OnPlatformViewSetViewportMetrics(metrics);
}
void PlatformView::NotifyCreated() {
std::unique_ptr<Surface> surface;
// Threading: We want to use the platform view on the non-platform thread.
// Using the weak pointer is illegal. But, we are going to introduce a latch
// so that the platform view is not collected till the surface is obtained.
auto* platform_view = this;
fml::ManualResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetRasterTaskRunner(), [platform_view, &surface, &latch]() {
surface = platform_view->CreateRenderingSurface();
latch.Signal();
});
latch.Wait();
delegate_.OnPlatformViewCreated(std::move(surface));
}
void PlatformView::NotifyDestroyed() { delegate_.OnPlatformViewDestroyed(); }
sk_sp<GrContext> PlatformView::CreateResourceContext() const {
FML_DLOG(WARNING) << "This platform does not setup the resource "
"context on the IO thread for async texture uploads.";
return nullptr;
}
void PlatformView::ReleaseResourceContext() const {}
PointerDataDispatcherMaker PlatformView::GetDispatcherMaker() {
return [](DefaultPointerDataDispatcher::Delegate& delegate) {
return std::make_unique<DefaultPointerDataDispatcher>(delegate);
};
}
fml::WeakPtr<PlatformView> PlatformView::GetWeakPtr() const {
return weak_factory_.GetWeakPtr();
}
void PlatformView::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (auto response = message->response()) response->CompleteEmpty();
}
void PlatformView::OnPreEngineRestart() const {}
void PlatformView::RegisterTexture(std::shared_ptr<Texture> texture) {
delegate_.OnPlatformViewRegisterTexture(std::move(texture));
}
void PlatformView::UnregisterTexture(int64_t texture_id) {
delegate_.OnPlatformViewUnregisterTexture(texture_id);
}
void PlatformView::MarkTextureFrameAvailable(int64_t texture_id) {
delegate_.OnPlatformViewMarkTextureFrameAvailable(texture_id);
}
std::unique_ptr<Surface> PlatformView::CreateRenderingSurface() {
// We have a default implementation because tests create a platform view but
// never a rendering surface.
FML_DCHECK(false) << "This platform does not provide a rendering surface but "
"it was notified of surface rendering surface creation.";
return nullptr;
}
void PlatformView::SetNextFrameCallback(const fml::closure& closure) {
if (!closure) {
return;
}
delegate_.OnPlatformViewSetNextFrameCallback(closure);
}
} // namespace uiwidgets

80
engine/src/shell/common/platform_view.h


#pragma once
#include <memory>
#include "common/task_runners.h"
#include "flow/texture.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "include/core/SkSize.h"
#include "include/gpu/GrContext.h"
#include "lib/ui/window/platform_message.h"
#include "lib/ui/window/pointer_data_packet.h"
#include "lib/ui/window/pointer_data_packet_converter.h"
#include "lib/ui/window/viewport_metrics.h"
#include "shell/common/pointer_data_dispatcher.h"
#include "shell/common/surface.h"
#include "shell/common/vsync_waiter.h"
namespace uiwidgets {
class PlatformView {
public:
class Delegate {
public:
virtual void OnPlatformViewCreated(std::unique_ptr<Surface> surface) = 0;
virtual void OnPlatformViewDestroyed() = 0;
virtual void OnPlatformViewSetNextFrameCallback(
const fml::closure& closure) = 0;
virtual void OnPlatformViewSetViewportMetrics(
const ViewportMetrics& metrics) = 0;
virtual void OnPlatformViewDispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) = 0;
virtual void OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) = 0;
virtual void OnPlatformViewSetAccessibilityFeatures(int32_t flags) = 0;
virtual void OnPlatformViewRegisterTexture(
std::shared_ptr<Texture> texture) = 0;
virtual void OnPlatformViewUnregisterTexture(int64_t texture_id) = 0;
virtual void OnPlatformViewMarkTextureFrameAvailable(
int64_t texture_id) = 0;
};
explicit PlatformView(Delegate& delegate, TaskRunners task_runners);
virtual ~PlatformView();
virtual std::unique_ptr<VsyncWaiter> CreateVSyncWaiter();
void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message);
virtual void SetAccessibilityFeatures(int32_t flags);
void SetViewportMetrics(const ViewportMetrics& metrics);
void NotifyCreated();
virtual void NotifyDestroyed();
virtual sk_sp<GrContext> CreateResourceContext() const;
virtual void ReleaseResourceContext() const;
virtual PointerDataDispatcherMaker GetDispatcherMaker();
fml::WeakPtr<PlatformView> GetWeakPtr() const;
virtual void OnPreEngineRestart() const;
void SetNextFrameCallback(const fml::closure& closure);
void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet);
void RegisterTexture(std::shared_ptr<Texture> texture);
void UnregisterTexture(int64_t texture_id);
void MarkTextureFrameAvailable(int64_t texture_id);
protected:
PlatformView::Delegate& delegate_;
const TaskRunners task_runners_;
PointerDataPacketConverter pointer_data_packet_converter_;
SkISize size_;
fml::WeakPtrFactory<PlatformView> weak_factory_;
// Unlike all other methods on the platform view, this is called on the
// GPU task runner.
virtual std::unique_ptr<Surface> CreateRenderingSurface();
private:
FML_DISALLOW_COPY_AND_ASSIGN(PlatformView);
};
} // namespace uiwidgets

57
engine/src/shell/common/pointer_data_dispatcher.cc


#include "pointer_data_dispatcher.h"
namespace uiwidgets {
PointerDataDispatcher::~PointerDataDispatcher() = default;
DefaultPointerDataDispatcher::~DefaultPointerDataDispatcher() = default;
SmoothPointerDataDispatcher::SmoothPointerDataDispatcher(Delegate& delegate)
: DefaultPointerDataDispatcher(delegate), weak_factory_(this) {}
SmoothPointerDataDispatcher::~SmoothPointerDataDispatcher() = default;
void DefaultPointerDataDispatcher::DispatchPacket(
std::unique_ptr<PointerDataPacket> packet, uint64_t trace_flow_id) {
delegate_.DoDispatchPacket(std::move(packet), trace_flow_id);
}
void SmoothPointerDataDispatcher::DispatchPacket(
std::unique_ptr<PointerDataPacket> packet, uint64_t trace_flow_id) {
if (is_pointer_data_in_progress_) {
if (pending_packet_ != nullptr) {
DispatchPendingPacket();
}
pending_packet_ = std::move(packet);
pending_trace_flow_id_ = trace_flow_id;
} else {
FML_DCHECK(pending_packet_ == nullptr);
DefaultPointerDataDispatcher::DispatchPacket(std::move(packet),
trace_flow_id);
}
is_pointer_data_in_progress_ = true;
ScheduleSecondaryVsyncCallback();
}
void SmoothPointerDataDispatcher::ScheduleSecondaryVsyncCallback() {
delegate_.ScheduleSecondaryVsyncCallback(
[dispatcher = weak_factory_.GetWeakPtr()]() {
if (dispatcher && dispatcher->is_pointer_data_in_progress_) {
if (dispatcher->pending_packet_ != nullptr) {
dispatcher->DispatchPendingPacket();
} else {
dispatcher->is_pointer_data_in_progress_ = false;
}
}
});
}
void SmoothPointerDataDispatcher::DispatchPendingPacket() {
FML_DCHECK(pending_packet_ != nullptr);
FML_DCHECK(is_pointer_data_in_progress_);
DefaultPointerDataDispatcher::DispatchPacket(std::move(pending_packet_),
pending_trace_flow_id_);
pending_packet_ = nullptr;
pending_trace_flow_id_ = -1;
ScheduleSecondaryVsyncCallback();
}
} // namespace uiwidgets

72
engine/src/shell/common/pointer_data_dispatcher.h


#pragma once
#include <flutter/fml/closure.h>
#include <flutter/fml/memory/weak_ptr.h>
#include <memory>
#include "lib/ui/window/pointer_data_packet.h"
namespace uiwidgets {
class PointerDataDispatcher {
public:
class Delegate {
public:
virtual void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) = 0;
virtual void ScheduleSecondaryVsyncCallback(
const fml::closure& callback) = 0;
};
virtual void DispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) = 0;
virtual ~PointerDataDispatcher();
};
class DefaultPointerDataDispatcher : public PointerDataDispatcher {
public:
DefaultPointerDataDispatcher(Delegate& delegate) : delegate_(delegate) {}
void DispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) override;
virtual ~DefaultPointerDataDispatcher();
protected:
Delegate& delegate_;
FML_DISALLOW_COPY_AND_ASSIGN(DefaultPointerDataDispatcher);
};
class SmoothPointerDataDispatcher : public DefaultPointerDataDispatcher {
public:
SmoothPointerDataDispatcher(Delegate& delegate);
void DispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) override;
virtual ~SmoothPointerDataDispatcher();
private:
std::unique_ptr<PointerDataPacket> pending_packet_;
int pending_trace_flow_id_ = -1;
bool is_pointer_data_in_progress_ = false;
fml::WeakPtrFactory<SmoothPointerDataDispatcher> weak_factory_;
void DispatchPendingPacket();
void ScheduleSecondaryVsyncCallback();
FML_DISALLOW_COPY_AND_ASSIGN(SmoothPointerDataDispatcher);
};
using PointerDataDispatcherMaker =
std::function<std::unique_ptr<PointerDataDispatcher>(
PointerDataDispatcher::Delegate&)>;
} // namespace uiwidgets

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

525
engine/src/shell/common/shell.h


#pragma once
#include <functional>
#include <string_view>
#include <unordered_map>
#include "common/settings.h"
#include "common/task_runners.h"
#include "flow/texture.h"
#include "flutter/fml/closure.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_ptr.h"
#include "flutter/fml/memory/thread_checker.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/fml/status.h"
#include "flutter/fml/synchronization/sync_switch.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/thread.h"
#include "lib/ui/window/platform_message.h"
#include "shell/common/animator.h"
#include "shell/common/engine.h"
#include "shell/common/platform_view.h"
#include "shell/common/rasterizer.h"
#include "shell/common/shell_io_manager.h"
#include "shell/common/surface.h"
namespace uiwidgets {
class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler {
public:
template <class T>
using CreateCallback = std::function<std::unique_ptr<T>(Shell&)>;
//----------------------------------------------------------------------------
/// @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.
///
static std::unique_ptr<Shell> Create(
TaskRunners task_runners,
Settings settings,
const CreateCallback<PlatformView>& on_create_platform_view,
const 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 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.
///
static std::unique_ptr<Shell> Create(
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,
const CreateCallback<PlatformView>& on_create_platform_view,
const CreateCallback<Rasterizer>& on_create_rasterizer,
DartVMRef vm);
//----------------------------------------------------------------------------
/// @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.
///
~Shell();
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration.
///
void RunEngine(RunConfiguration run_configuration);
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration. The
/// result_callback will be called with the status of the
/// operation.
///
void RunEngine(RunConfiguration run_configuration,
const std::function<void(Engine::RunStatus)>& result_callback);
//------------------------------------------------------------------------------
/// @return The settings used to launch this shell.
///
const Settings& GetSettings() const;
//------------------------------------------------------------------------------
/// @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.
///
const TaskRunners& GetTaskRunners() const;
//----------------------------------------------------------------------------
/// @brief Rasterizers may only be accessed on the GPU task runner.
///
/// @return A weak pointer to the rasterizer.
///
fml::WeakPtr<Rasterizer> GetRasterizer() const;
//------------------------------------------------------------------------------
/// @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.
///
fml::WeakPtr<Engine> GetEngine();
//----------------------------------------------------------------------------
/// @brief Platform views may only be accessed on the platform task
/// runner.
///
/// @return A weak pointer to the platform view.
///
fml::WeakPtr<PlatformView> GetPlatformView();
// 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.
void NotifyLowMemoryWarning() const;
//----------------------------------------------------------------------------
/// @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.
///
bool IsSetup() const;
//----------------------------------------------------------------------------
/// @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.
///
Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type,
bool base64_encode);
//----------------------------------------------------------------------------
/// @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.
///
fml::Status WaitForFirstFrame(fml::TimeDelta 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.
///
bool ReloadSystemFonts();
//----------------------------------------------------------------------------
/// @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
std::shared_ptr<fml::SyncSwitch> GetIsGpuDisabledSyncSwitch() const;
//----------------------------------------------------------------------------
/// @brief Get a pointer to the Dart VM used by this running shell
/// instance.
///
/// @return The Dart VM pointer.
///
DartVM* GetDartVM();
private:
using ServiceProtocolHandler =
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
rapidjson::Document&)>;
const TaskRunners task_runners_;
const Settings settings_;
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
std::unique_ptr<ShellIOManager> io_manager_; // on IO task runner
std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch_;
fml::WeakPtr<Engine> weak_engine_; // to be shared across threads
fml::WeakPtr<Rasterizer> weak_rasterizer_; // to be shared across threads
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;
bool first_frame_rasterized_ = false;
std::atomic<bool> waiting_for_first_frame_ = true;
std::mutex waiting_for_first_frame_mutex_;
std::condition_variable waiting_for_first_frame_condition_;
// Written in the UI thread and read from the raster thread. Hence make it
// atomic.
std::atomic<bool> needs_report_timings_{false};
// Whether there's a task scheduled to report the timings to Dart through
// ui.Window.onReportTimings.
bool frame_timings_report_scheduled_ = false;
// Vector of FrameTiming::kCount * n timestamps for n frames whose timings
// have not been reported yet. Vector of ints instead of FrameTiming is stored
// here for easier conversions to Dart objects.
std::vector<int64_t> unreported_timings_;
// A cache of `Engine::GetDisplayRefreshRate` (only callable in the UI thread)
// so we can access it from `Rasterizer` (in the raster thread).
//
// The atomic is for extra thread safety as this is written in the UI thread
// and read from the raster thread.
std::atomic<float> display_refresh_rate_ = 0.0f;
// How many frames have been timed since last report.
size_t UnreportedFramesCount() const;
Shell(DartVMRef vm, TaskRunners task_runners, Settings settings);
static std::unique_ptr<Shell> CreateShellOnPlatformThread(
DartVMRef vm,
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer);
bool Setup(std::unique_ptr<PlatformView> platform_view,
std::unique_ptr<Engine> engine,
std::unique_ptr<Rasterizer> rasterizer,
std::unique_ptr<ShellIOManager> io_manager);
void ReportTimings();
// |PlatformView::Delegate|
void OnPlatformViewCreated(std::unique_ptr<Surface> surface) override;
// |PlatformView::Delegate|
void OnPlatformViewDestroyed() override;
// |PlatformView::Delegate|
void OnPlatformViewSetViewportMetrics(
const ViewportMetrics& metrics) override;
// |PlatformView::Delegate|
void OnPlatformViewDispatchPlatformMessage(
fml::RefPtr<PlatformMessage> message) override;
// |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;
// |shell:PlatformView::Delegate|
void OnPlatformViewSetAccessibilityFeatures(int32_t flags) override;
// |PlatformView::Delegate|
void OnPlatformViewRegisterTexture(
std::shared_ptr<flutter::Texture> texture) override;
// |PlatformView::Delegate|
void OnPlatformViewUnregisterTexture(int64_t texture_id) override;
// |PlatformView::Delegate|
void OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) override;
// |PlatformView::Delegate|
void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) override;
// |Animator::Delegate|
void OnAnimatorBeginFrame(fml::TimePoint frame_time) override;
// |Animator::Delegate|
void OnAnimatorNotifyIdle(int64_t deadline) override;
// |Animator::Delegate|
void OnAnimatorDraw(
fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) override;
// |Animator::Delegate|
void OnAnimatorDrawLastLayerTree() override;
// |Engine::Delegate|
void OnEngineUpdateSemantics(
SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) override;
// |Engine::Delegate|
void OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) override;
void HandleEngineSkiaMessage(fml::RefPtr<PlatformMessage> message);
// |Engine::Delegate|
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|
void OnFrameRasterized(const FrameTiming&) 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
// rasterizer callbacks.
std::unique_ptr<fml::WeakPtrFactory<Shell>> weak_factory_gpu_;
friend class testing::ShellTest;
FML_DISALLOW_COPY_AND_ASSIGN(Shell);
};
} // namespace flutter
#endif // SHELL_COMMON_SHELL_H_

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


#include "scene.h"
#include "flutter/fml/trace_event.h"
#include "lib/ui/painting/image.h"
#include "lib/ui/painting/picture.h"
#include "lib/ui/ui_mono_state.h"
#include "lib/ui/window/window.h"
namespace uiwidgets {
fml::RefPtr<Scene> Scene::create(std::shared_ptr<Layer> rootLayer,
uint32_t rasterizerTracingThreshold,
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers) {
return fml::MakeRefCounted<Scene>(
std::move(rootLayer), rasterizerTracingThreshold,
checkerboardRasterCacheImages, checkerboardOffscreenLayers);
}
Scene::Scene(std::shared_ptr<Layer> rootLayer,
uint32_t rasterizerTracingThreshold,
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers) {
auto viewport_metrics = UIMonoState::Current()->window()->viewport_metrics();
layer_tree_ = std::make_unique<LayerTree>(
SkISize::Make(viewport_metrics.physical_width,
viewport_metrics.physical_height),
static_cast<float>(viewport_metrics.physical_depth),
static_cast<float>(viewport_metrics.device_pixel_ratio));
layer_tree_->set_root_layer(std::move(rootLayer));
layer_tree_->set_rasterizer_tracing_threshold(rasterizerTracingThreshold);
layer_tree_->set_checkerboard_raster_cache_images(
checkerboardRasterCacheImages);
layer_tree_->set_checkerboard_offscreen_layers(checkerboardOffscreenLayers);
}
Scene::~Scene() {}
void Scene::dispose() {}
const char* Scene::toImage(uint32_t width, uint32_t height,
Picture::RawImageCallback raw_image_callback,
Mono_Handle callback_handle) {
TRACE_EVENT0("uiwidgets", "Scene::toImage");
if (!layer_tree_) {
return "Scene did not contain a layer tree.";
}
auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height));
if (!picture) {
return "Could not flatten scene into a layer tree.";
}
return Picture::RasterizeToImage(picture, width, height, raw_image_callback,
callback_handle);
}
std::unique_ptr<LayerTree> Scene::takeLayerTree() {
return std::move(layer_tree_);
}
} // namespace uiwidgets

39
engine/src/lib/ui/compositing/scene.h


#pragma once
#include <stdint.h>
#include <memory>
#include "flow/layers/layer_tree.h"
#include "lib/ui/painting/picture.h"
namespace uiwidgets {
class Scene : public fml::RefCountedThreadSafe<Scene> {
FML_FRIEND_MAKE_REF_COUNTED(Scene);
public:
~Scene();
static fml::RefPtr<Scene> create(std::shared_ptr<Layer> rootLayer,
uint32_t rasterizerTracingThreshold,
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers);
std::unique_ptr<LayerTree> takeLayerTree();
const char* toImage(uint32_t width, uint32_t height,
Picture::RawImageCallback raw_image_callback,
Mono_Handle callback_handle);
void dispose();
private:
explicit Scene(std::shared_ptr<Layer> rootLayer,
uint32_t rasterizerTracingThreshold,
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers);
std::unique_ptr<LayerTree> layer_tree_;
};
} // namespace uiwidgets

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


#include "scene_builder.h"
#include "flow/layers/backdrop_filter_layer.h"
#include "flow/layers/clip_path_layer.h"
#include "flow/layers/clip_rect_layer.h"
#include "flow/layers/clip_rrect_layer.h"
#include "flow/layers/color_filter_layer.h"
#include "flow/layers/container_layer.h"
#include "flow/layers/image_filter_layer.h"
#include "flow/layers/layer.h"
#include "flow/layers/layer_tree.h"
#include "flow/layers/opacity_layer.h"
#include "flow/layers/performance_overlay_layer.h"
#include "flow/layers/physical_shape_layer.h"
#include "flow/layers/picture_layer.h"
#include "flow/layers/platform_view_layer.h"
#include "flow/layers/shader_mask_layer.h"
#include "flow/layers/texture_layer.h"
#include "flow/layers/transform_layer.h"
#include "include/core/SkColorFilter.h"
#include "lib/ui/painting/matrix.h"
#include "lib/ui/painting/shader.h"
namespace uiwidgets {
SceneBuilder::SceneBuilder() { PushLayer(std::make_shared<ContainerLayer>()); }
SceneBuilder::~SceneBuilder() = default;
fml::RefPtr<EngineLayer> SceneBuilder::pushTransform(float* matrix4) {
SkMatrix sk_matrix = ToSkMatrix(matrix4);
auto layer = std::make_shared<TransformLayer>(sk_matrix);
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushOffset(float dx, float dy) {
SkMatrix sk_matrix = SkMatrix::Translate(dx, dy);
auto layer = std::make_shared<TransformLayer>(sk_matrix);
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushClipRect(float left, float right,
float top, float bottom,
int clipBehavior) {
SkRect clipRect = SkRect::MakeLTRB(left, top, right, bottom);
Clip clip_behavior = static_cast<Clip>(clipBehavior);
auto layer = std::make_shared<ClipRectLayer>(clipRect, clip_behavior);
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushClipRRect(const RRect& rrect,
int clipBehavior) {
Clip clip_behavior = static_cast<Clip>(clipBehavior);
auto layer = std::make_shared<ClipRRectLayer>(rrect.sk_rrect, clip_behavior);
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushClipPath(const CanvasPath* path,
int clipBehavior) {
Clip clip_behavior = static_cast<Clip>(clipBehavior);
FML_DCHECK(clip_behavior != Clip::none);
auto layer = std::make_shared<ClipPathLayer>(path->path(), clip_behavior);
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushOpacity(int alpha, float dx,
float dy) {
auto layer = std::make_shared<OpacityLayer>(alpha, SkPoint::Make(dx, dy));
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushColorFilter(
const ColorFilter* color_filter) {
auto layer = std::make_shared<ColorFilterLayer>(color_filter->filter());
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushImageFilter(
const ImageFilter* image_filter) {
auto layer = std::make_shared<ImageFilterLayer>(image_filter->filter());
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushBackdropFilter(ImageFilter* filter) {
auto layer = std::make_shared<BackdropFilterLayer>(filter->filter());
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushShaderMask(
Shader* shader, float maskRectLeft, float maskRectRight, float maskRectTop,
float maskRectBottom, int blendMode) {
SkRect rect = SkRect::MakeLTRB(maskRectLeft, maskRectTop, maskRectRight,
maskRectBottom);
auto layer = std::make_shared<ShaderMaskLayer>(
shader->shader(), rect, static_cast<SkBlendMode>(blendMode));
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
fml::RefPtr<EngineLayer> SceneBuilder::pushPhysicalShape(const CanvasPath* path,
float elevation,
int color,
int shadow_color,
int clipBehavior) {
auto layer = std::make_shared<PhysicalShapeLayer>(
static_cast<SkColor>(color), static_cast<SkColor>(shadow_color),
static_cast<float>(elevation), path->path(),
static_cast<Clip>(clipBehavior));
PushLayer(layer);
return EngineLayer::MakeRetained(layer);
}
void SceneBuilder::addRetained(fml::RefPtr<EngineLayer> retainedLayer) {
AddLayer(retainedLayer->Layer());
}
void SceneBuilder::pop() { PopLayer(); }
void SceneBuilder::addPicture(float dx, float dy, Picture* picture, int hints) {
SkPoint offset = SkPoint::Make(dx, dy);
SkRect pictureRect = picture->picture()->cullRect();
pictureRect.offset(offset.x(), offset.y());
auto layer = std::make_unique<PictureLayer>(
offset, UIMonoState::CreateGPUObject(picture->picture()), !!(hints & 1),
!!(hints & 2));
AddLayer(std::move(layer));
}
void SceneBuilder::addTexture(float dx, float dy, float width, float height,
int64_t textureId, bool freeze) {
auto layer = std::make_unique<TextureLayer>(
SkPoint::Make(dx, dy), SkSize::Make(width, height), textureId, freeze);
AddLayer(std::move(layer));
}
void SceneBuilder::addPlatformView(float dx, float dy, float width,
float height, int64_t viewId) {
auto layer = std::make_unique<PlatformViewLayer>(
SkPoint::Make(dx, dy), SkSize::Make(width, height), viewId);
AddLayer(std::move(layer));
}
void SceneBuilder::addPerformanceOverlay(uint64_t enabledOptions, float left,
float right, float top, float bottom) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
auto layer = std::make_unique<PerformanceOverlayLayer>(enabledOptions);
layer->set_paint_bounds(rect);
AddLayer(std::move(layer));
}
void SceneBuilder::setRasterizerTracingThreshold(uint32_t frameInterval) {
rasterizer_tracing_threshold_ = frameInterval;
}
void SceneBuilder::setCheckerboardRasterCacheImages(bool checkerboard) {
checkerboard_raster_cache_images_ = checkerboard;
}
void SceneBuilder::setCheckerboardOffscreenLayers(bool checkerboard) {
checkerboard_offscreen_layers_ = checkerboard;
}
fml::RefPtr<Scene> SceneBuilder::build() {
FML_DCHECK(layer_stack_.size() >= 1);
return Scene::create(layer_stack_[0], rasterizer_tracing_threshold_,
checkerboard_raster_cache_images_,
checkerboard_offscreen_layers_);
}
void SceneBuilder::AddLayer(std::shared_ptr<Layer> layer) {
FML_DCHECK(layer);
if (!layer_stack_.empty()) {
layer_stack_.back()->Add(std::move(layer));
}
}
void SceneBuilder::PushLayer(std::shared_ptr<ContainerLayer> layer) {
AddLayer(layer);
layer_stack_.push_back(std::move(layer));
}
void SceneBuilder::PopLayer() {
// We never pop the root layer, so that AddLayer operations are always valid.
if (layer_stack_.size() > 1) {
layer_stack_.pop_back();
}
}
} // namespace uiwidgets

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


#pragma once
#include <stdint.h>
#include <memory>
#include <vector>
#include "flow/layers/container_layer.h"
#include "lib/ui/compositing/scene.h"
#include "lib/ui/painting/color_filter.h"
#include "lib/ui/painting/engine_layer.h"
#include "lib/ui/painting/image_filter.h"
#include "lib/ui/painting/path.h"
#include "lib/ui/painting/picture.h"
#include "lib/ui/painting/rrect.h"
#include "lib/ui/painting/shader.h"
namespace uiwidgets {
class SceneBuilder : public fml::RefCountedThreadSafe<SceneBuilder> {
FML_FRIEND_MAKE_REF_COUNTED(SceneBuilder);
public:
static fml::RefPtr<SceneBuilder> create() {
return fml::MakeRefCounted<SceneBuilder>();
}
~SceneBuilder();
fml::RefPtr<EngineLayer> pushTransform(float* matrix4);
fml::RefPtr<EngineLayer> pushOffset(float dx, float dy);
fml::RefPtr<EngineLayer> pushClipRect(float left, float right, float top,
float bottom, int clipBehavior);
fml::RefPtr<EngineLayer> pushClipRRect(const RRect& rrect, int clipBehavior);
fml::RefPtr<EngineLayer> pushClipPath(const CanvasPath* path,
int clipBehavior);
fml::RefPtr<EngineLayer> pushOpacity(int alpha, float dx = 0, float dy = 0);
fml::RefPtr<EngineLayer> pushColorFilter(const ColorFilter* color_filter);
fml::RefPtr<EngineLayer> pushImageFilter(const ImageFilter* image_filter);
fml::RefPtr<EngineLayer> pushBackdropFilter(ImageFilter* filter);
fml::RefPtr<EngineLayer> pushShaderMask(Shader* shader, float maskRectLeft,
float maskRectRight,
float maskRectTop,
float maskRectBottom, int blendMode);
fml::RefPtr<EngineLayer> pushPhysicalShape(const CanvasPath* path,
float elevation, int color,
int shadowColor, int clipBehavior);
void addRetained(fml::RefPtr<EngineLayer> retainedLayer);
void pop();
void addPerformanceOverlay(uint64_t enabledOptions, float left, float right,
float top, float bottom);
void addPicture(float dx, float dy, Picture* picture, int hints);
void addTexture(float dx, float dy, float width, float height,
int64_t textureId, bool freeze);
void addPlatformView(float dx, float dy, float width, float height,
int64_t viewId);
void setRasterizerTracingThreshold(uint32_t frameInterval);
void setCheckerboardRasterCacheImages(bool checkerboard);
void setCheckerboardOffscreenLayers(bool checkerboard);
fml::RefPtr<Scene> build();
private:
SceneBuilder();
void AddLayer(std::shared_ptr<Layer> layer);
void PushLayer(std::shared_ptr<ContainerLayer> layer);
void PopLayer();
std::vector<std::shared_ptr<ContainerLayer>> layer_stack_;
int rasterizer_tracing_threshold_ = 0;
bool checkerboard_raster_cache_images_ = false;
bool checkerboard_offscreen_layers_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(SceneBuilder);
};
} // namespace uiwidgets

/com.unity.uiwidgets/Runtime/ui2/painting/Isolate.cs.meta → /com.unity.uiwidgets/Runtime/ui2/isolate.cs.meta

/com.unity.uiwidgets/Runtime/ui2/painting/native_bindings.cs.meta → /com.unity.uiwidgets/Runtime/ui2/native_bindings.cs.meta

/com.unity.uiwidgets/Runtime/ui2/painting/painting.cs.meta → /com.unity.uiwidgets/Runtime/ui2/painting.cs.meta

正在加载...
取消
保存