浏览代码

Merge pull request #54 from Unity-Technologies/siyaoH/1.17/painting

Siyao h/1.17/painting
/siyaoH-1.17-PlatformMessage
GitHub 4 年前
当前提交
50607d73
共有 42 个文件被更改,包括 2917 次插入601 次删除
  1. 32
      com.unity.uiwidgets/Runtime/external/SplayTree.cs
  2. 14
      com.unity.uiwidgets/Runtime/foundation/debug.cs
  3. 2
      com.unity.uiwidgets/Runtime/gestures/binding.cs
  4. 414
      com.unity.uiwidgets/Runtime/painting/alignment.cs
  5. 18
      com.unity.uiwidgets/Runtime/painting/beveled_rectangle_border.cs
  6. 46
      com.unity.uiwidgets/Runtime/painting/binding.cs
  7. 680
      com.unity.uiwidgets/Runtime/painting/border_radius.cs
  8. 26
      com.unity.uiwidgets/Runtime/painting/borders.cs
  9. 459
      com.unity.uiwidgets/Runtime/painting/box_border.cs
  10. 2
      com.unity.uiwidgets/Runtime/painting/box_decoration.cs
  11. 11
      com.unity.uiwidgets/Runtime/painting/circle_border.cs
  12. 276
      com.unity.uiwidgets/Runtime/painting/colors.cs
  13. 26
      com.unity.uiwidgets/Runtime/painting/continuous_rectangle_border.cs
  14. 4
      com.unity.uiwidgets/Runtime/painting/decoration.cs
  15. 69
      com.unity.uiwidgets/Runtime/painting/decoration_image.cs
  16. 42
      com.unity.uiwidgets/Runtime/painting/edge_insets.cs
  17. 10
      com.unity.uiwidgets/Runtime/painting/gradient.cs
  18. 233
      com.unity.uiwidgets/Runtime/painting/image_cache.cs
  19. 241
      com.unity.uiwidgets/Runtime/painting/image_provider.cs
  20. 66
      com.unity.uiwidgets/Runtime/painting/image_resolution.cs
  21. 198
      com.unity.uiwidgets/Runtime/painting/image_stream.cs
  22. 15
      com.unity.uiwidgets/Runtime/painting/inline_span.cs
  23. 220
      com.unity.uiwidgets/Runtime/painting/matrix_utils.cs
  24. 40
      com.unity.uiwidgets/Runtime/painting/rounded_rectangle_border.cs
  25. 9
      com.unity.uiwidgets/Runtime/painting/shape_decoration.cs
  26. 31
      com.unity.uiwidgets/Runtime/painting/stadium_border.cs
  27. 29
      com.unity.uiwidgets/Runtime/painting/strut_style.cs
  28. 31
      com.unity.uiwidgets/Runtime/painting/text_painter.cs
  29. 2
      com.unity.uiwidgets/Runtime/painting/text_span.cs
  30. 165
      com.unity.uiwidgets/Runtime/painting/text_style.cs
  31. 8
      com.unity.uiwidgets/Runtime/rendering/binding.cs
  32. 2
      com.unity.uiwidgets/Runtime/rendering/image.cs
  33. 4
      com.unity.uiwidgets/Runtime/scheduler2/binding.cs
  34. 3
      com.unity.uiwidgets/Runtime/services/binding.cs
  35. 1
      com.unity.uiwidgets/Runtime/widgets/binding.cs
  36. 5
      com.unity.uiwidgets/Runtime/widgets/container.cs
  37. 11
      com.unity.uiwidgets/Runtime/widgets/debug.cs
  38. 13
      com.unity.uiwidgets/Runtime/widgets/fade_in_image.cs
  39. 41
      com.unity.uiwidgets/Runtime/widgets/image.cs
  40. 3
      engine/.gitignore
  41. 13
      com.unity.uiwidgets/Runtime/painting/image_decoder.cs
  42. 3
      com.unity.uiwidgets/Runtime/painting/image_decoder.cs.meta

32
com.unity.uiwidgets/Runtime/external/SplayTree.cs


return new KeyValuePair<TKey, TValue>(t.Key, t.Value);
}
public TKey lastKeyBefore(TKey key) {
if (key == null) throw new Exception("should input null");
if (root == null) throw new Exception("root is null");
int comp = Splay(key);
if (comp < 0) return root.Key;
SplayTreeNode node = root.LeftChild;
if (node == null) throw new Exception("does not exist");
while (node.RightChild != null) {
node = node.RightChild;
}
return node.Key;
}
public TKey firstKeyAfter(TKey key) {
if (key == null) throw new Exception("should input null");
if (root == null) throw new Exception("root is null");
int comp = Splay(key);
if (comp > 0) return root.Key;
SplayTreeNode node = root.LeftChild;
if (node == null) throw new Exception("does not exist");
while (node.LeftChild != null) {
node = node.LeftChild;
}
return node.Key;
}
public KeyValuePair<TKey, TValue>? Last() {
SplayTreeNode t = root;

return new KeyValuePair<TKey, TValue>(t.Key, t.Value);
}
void Splay(TKey key) {
int Splay(TKey key) {
int c;
var c = key.CompareTo(t.Key);
c = key.CompareTo(t.Key);
if (c < 0) {
if (t.LeftChild == null) {
break;

t.LeftChild = header.RightChild;
t.RightChild = header.LeftChild;
root = t;
return c;
}
public bool Remove(TKey key) {

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


}*/
}
}
public static int? debugFloatPrecision;
public static string debugFormatFloat(float? value) {
if (value == null) {
return "null";
}
if (debugFloatPrecision != null) {
return value.Value.ToString($"N{debugFloatPrecision}");
}
return value.Value.ToString($"N1");
}
}
[Serializable]

2
com.unity.uiwidgets/Runtime/gestures/binding.cs


using UnityEngine;
namespace Unity.UIWidgets.gestures {
public class GestureBinding : SchedulerBinding, HitTestable, HitTestDispatcher, HitTestTarget {
public class GestureBinding : BindingBase, HitTestable, HitTestDispatcher, HitTestTarget {
protected override void initInstances() {
base.initInstances();

414
com.unity.uiwidgets/Runtime/painting/alignment.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;
using Rect = Unity.UIWidgets.ui.Rect;
public abstract class AlignmentGeometry {
public abstract class AlignmentGeometry : IEquatable<AlignmentGeometry> {
protected float _x { get; }
protected virtual float _x { get; }
protected float _start { get; }
protected virtual float _start { get; }
protected float _y { get; }
protected virtual float _y { get; }
// public static AlignmentGeometry add(AlignmentGeometry other) {
// return new _MixedAlignment(
// _x + other._x,
// _start + other._start,
// _y + other._y,
// );
// }
public virtual AlignmentGeometry add(AlignmentGeometry other) {
return new _MixedAlignment(
_x + other._x,
_start + other._start,
_y + other._y
);
}
// public abstract AlignmentGeometry operator -();
//
// public abstract AlignmentGeometry operator *(double other);
//
// public abstract AlignmentGeometry operator /(double other);
//
// public abstract AlignmentGeometry operator ~/(double other);
//
// public abstract AlignmentGeometry operator %(double other);
public abstract AlignmentGeometry SelfMinus();
// static AlignmentGeometry lerp(AlignmentGeometry a, AlignmentGeometry b, float t) {
// D.assert(t != null);
// if (a == null && b == null)
// return null;
// if (a == null)
// return b * t;
// if (b == null)
// return a * (1.0 - t);
// if (a is Alignment && b is Alignment)
// return Alignment.lerp(a, b, t);
// if (a is AlignmentDirectional && b is AlignmentDirectional)
// return AlignmentDirectional.lerp(a, b, t);
// return _MixedAlignment(
// ui.lerpDouble(a._x, b._x, t),
// ui.lerpDouble(a._start, b._start, t),
// ui.lerpDouble(a._y, b._y, t),
// );
// }
//
public static AlignmentGeometry operator -(AlignmentGeometry self) {
return self.SelfMinus();
}
public abstract AlignmentGeometry Multiply(float other);
public static AlignmentGeometry operator *(AlignmentGeometry self, float other) {
return self.Multiply(other);
}
public abstract AlignmentGeometry Divide(float other);
public static AlignmentGeometry operator /(AlignmentGeometry self, float other) {
return self.Divide(other);
}
public abstract AlignmentGeometry Remainder(float other);
public static AlignmentGeometry operator %(AlignmentGeometry self, float other) {
return self.Remainder(other);
}
public static AlignmentGeometry lerp(AlignmentGeometry a, AlignmentGeometry b, float t) {
D.assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return b * t;
if (b == null)
return a * (1.0f - t);
if (a is Alignment && b is Alignment)
return Alignment.lerp(a, b, t);
if (a is AlignmentDirectional && b is AlignmentDirectional)
return AlignmentDirectional.lerp(a, b, t);
return new _MixedAlignment(
Mathf.Lerp(a._x, b._x, t),
Mathf.Lerp(a._start, b._start, t),
Mathf.Lerp(a._y, b._y, t)
);
}
//
// @override
// String toString() {
// if (_start == 0.0)
// return Alignment._stringify(_x, _y);
// if (_x == 0.0)
// return AlignmentDirectional._stringify(_start, _y);
// return Alignment._stringify(_x, _y) + ' + ' + AlignmentDirectional._stringify(_start, 0.0);
// }
//
// @override
// bool operator ==(Object other) {
// return other is AlignmentGeometry
// && other._x == _x
// && other._start == _start
// && other._y == _y;
// }
//
// @override
// int get hashCode => hashValues(_x, _start, _y);
public override string ToString() {
if (_start == 0.0)
return Alignment._stringify(_x, _y);
if (_x == 0.0)
return AlignmentDirectional._stringify(_start, _y);
return Alignment._stringify(_x, _y) + " + " + AlignmentDirectional._stringify(_start, 0.0);
}
public bool Equals(AlignmentGeometry other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return _x.Equals(other._x) && _start.Equals(other._start) && _y.Equals(other._y);
}
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((AlignmentGeometry) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = _x.GetHashCode();
hashCode = (hashCode * 397) ^ _start.GetHashCode();
hashCode = (hashCode * 397) ^ _y.GetHashCode();
return hashCode;
}
}
}
public class Alignment : AlignmentGeometry, IEquatable<Alignment> {

return new Alignment(a.x + b.x, a.y + b.y);
}
public static Alignment operator -(Alignment a) {
return new Alignment(-a.x, -a.y);
public override AlignmentGeometry SelfMinus() {
return new Alignment(-x, -y);
public static Alignment operator *(Alignment a, float b) {
return new Alignment(a.x * b, a.y * b);
public override AlignmentGeometry Multiply(float other) {
return new Alignment(x * other, y * other);
public static Alignment operator /(Alignment a, float b) {
return new Alignment(a.x / b, a.y / b);
public override AlignmentGeometry Divide(float other) {
return new Alignment(x / other, y / other);
public static Alignment operator %(Alignment a, float b) {
return new Alignment(a.x % b, a.y % b);
public override AlignmentGeometry Remainder(float other) {
return new Alignment(x % other, y % other);
}
public Offset alongOffset(Offset other) {

case TextDirection.ltr:
return new Alignment(_x + _start, _y);
}
}
internal static String _stringify(float x, float y) {
if (x == -1.0f && y == -1.0f)
return "topLeft";
if (x == 0.0f && y == -1.0f)
return "topCenter";
if (x == 1.0f && y == -1.0f)
return "topRight";
if (x == -1.0f && y == 0.0f)
return "centerLeft";
if (x == 0.0f && y == 0.0f)
return "center";
if (x == 1.0f && y == 0.0f)
return "centerRight";
if (x == -1.0f && y == 1.0f)
return "bottomLeft";
if (x == 0.0f && y == 1.0f)
return "bottomCenter";
if (x == 1.0f && y == 1.0f)
return "bottomRight";
return $"Alignment({x}, " +
$"{y})";
}
}
public class AlignmentDirectional : AlignmentGeometry {
public AlignmentDirectional(float start, float y) {
this.start = start;
this.y = y;
}
readonly float _px;
protected override float _x {
get => 0;
}
readonly float start;
protected override float _start {
get => start;
}
readonly float y;
protected override float _y {
get => y;
}
public static readonly AlignmentDirectional topStart = new AlignmentDirectional(-1.0f, -1.0f);
public static readonly AlignmentDirectional topCenter = new AlignmentDirectional(0.0f, -1.0f);
public static readonly AlignmentDirectional topEnd = new AlignmentDirectional(1.0f, -1.0f);
public static readonly AlignmentDirectional centerStart = new AlignmentDirectional(-1.0f, 0.0f);
public static readonly AlignmentDirectional center = new AlignmentDirectional(0.0f, 0.0f);
public static readonly AlignmentDirectional centerEnd = new AlignmentDirectional(1.0f, 0.0f);
public static readonly AlignmentDirectional bottomStart = new AlignmentDirectional(-1.0f, 1.0f);
public static readonly AlignmentDirectional bottomCenter = new AlignmentDirectional(0.0f, 1.0f);
public static readonly AlignmentDirectional bottomEnd = new AlignmentDirectional(1.0f, 1.0f);
public override AlignmentGeometry add(AlignmentGeometry other) {
if (other is AlignmentDirectional alignmentDirectional)
return this + alignmentDirectional;
return base.add(other);
}
public static AlignmentDirectional operator -(AlignmentDirectional self, AlignmentDirectional other) {
return new AlignmentDirectional(self.start - other.start, self.y - other.y);
}
public static AlignmentDirectional operator +(AlignmentDirectional self, AlignmentDirectional other) {
return new AlignmentDirectional(self.start + other.start, self.y + other.y);
}
public override AlignmentGeometry SelfMinus() {
return new AlignmentDirectional(-start, -y);
}
public override AlignmentGeometry Multiply(float other) {
return new AlignmentDirectional(start * other, y * other);
}
public override AlignmentGeometry Divide(float other) {
return new AlignmentDirectional(start / other, y / other);
}
public override AlignmentGeometry Remainder(float other) {
return new AlignmentDirectional(start % other, y % other);
}
static AlignmentDirectional lerp(AlignmentDirectional a, AlignmentDirectional b, float t) {
D.assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return new AlignmentDirectional(MathUtils.lerpFloat(0.0f, b.start, t),
MathUtils.lerpFloat(0.0f, b.y, t));
if (b == null)
return new AlignmentDirectional(MathUtils.lerpFloat(a.start, 0.0f, t),
MathUtils.lerpFloat(a.y, 0.0f, t));
return new AlignmentDirectional(MathUtils.lerpFloat(a.start, b.start, t), MathUtils.lerpFloat(a.y, b.y, t));
}
public override Alignment resolve(TextDirection? direction) {
D.assert(direction != null);
switch (direction) {
case TextDirection.rtl:
return new Alignment(-start, y);
case TextDirection.ltr:
return new Alignment(start, y);
}
return null;
}
internal static String _stringify(double start, double y) {
if (start == -1.0f && y == -1.0f)
return "AlignmentDirectional.topStart";
if (start == 0.0f && y == -1.0f)
return "AlignmentDirectional.topCenter";
if (start == 1.0f && y == -1.0f)
return "AlignmentDirectional.topEnd";
if (start == -1.0f && y == 0.0f)
return "AlignmentDirectional.centerStart";
if (start == 0.0f && y == 0.0f)
return "AlignmentDirectional.center";
if (start == 1.0f && y == 0.0f)
return "AlignmentDirectional.centerEnd";
if (start == -1.0f && y == 1.0f)
return "AlignmentDirectional.bottomStart";
if (start == 0.0f && y == 1.0f)
return "AlignmentDirectional.bottomCenter";
if (start == 1.0f && y == 1.0f)
return "AlignmentDirectional.bottomEnd";
return $"AlignmentDirectional({start}, {y})";
}
public override string ToString() => _stringify(start, y);
}
class _MixedAlignment : AlignmentGeometry {
internal _MixedAlignment(float _x, float _start, float _y) {
_px = _x;
_pstart = _start;
_py = _y;
}
readonly float _px;
protected override float _x {
get => _px;
}
readonly float _pstart;
protected override float _start {
get => _pstart;
}
readonly float _py;
protected override float _y {
get => _py;
}
public override AlignmentGeometry SelfMinus() {
return new _MixedAlignment(
-_x,
-_start,
-_y
);
}
public override AlignmentGeometry Multiply(float other) {
return new _MixedAlignment(
_x * other,
_start * other,
_y * other
);
}
public override AlignmentGeometry Divide(float other) {
return new _MixedAlignment(
_x / other,
_start / other,
_y / other
);
}
public override AlignmentGeometry Remainder(float other) {
return new _MixedAlignment(
_x % other,
_start % other,
_y % other
);
}
public override Alignment resolve(TextDirection? direction) {
D.assert(direction != null);
switch (direction) {
case TextDirection.rtl:
return new Alignment(_x - _start, _y);
case TextDirection.ltr:
return new Alignment(_x + _start, _y);
}
return null;
}
}
public class TextAlignVertical {
public TextAlignVertical(float y) {
D.assert(y != null);
D.assert(y >= -1.0 && y <= 1.0);
this.y = y;
}
public readonly double y;
public static readonly TextAlignVertical top = new TextAlignVertical(y: -1.0f);
public static readonly TextAlignVertical center = new TextAlignVertical(y: 0.0f);
public static readonly TextAlignVertical bottom = new TextAlignVertical(y: 1.0f);
public override string ToString() {
return $"{foundation_.objectRuntimeType(this, "TextAlignVertical")}(y: {y})";
}
}
}

18
com.unity.uiwidgets/Runtime/painting/beveled_rectangle_border.cs


public readonly BorderRadius borderRadius;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get { return EdgeInsets.all(side.width); }
}

borderRadius: borderRadius * t
borderRadius: (BorderRadius) (borderRadius * t)
);
}

return path;
}
public override Path getInnerPath(Rect rect) {
return _getPath(borderRadius.toRRect(rect).deflate(side.width));
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
return _getPath(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.width));
public override Path getOuterPath(Rect rect) {
return _getPath(borderRadius.toRRect(rect));
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
return _getPath(borderRadius.resolve(textDirection).toRRect(rect));
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
if (rect.isEmpty) {
return;
}

break;
case BorderStyle.solid:
Path path = getOuterPath(rect);
path.addPath(getInnerPath(rect), Offset.zero);
Path path = getOuterPath(rect, textDirection);
path.addPath(getInnerPath(rect, textDirection), Offset.zero);
canvas.drawPath(path, side.toPaint());
break;
}

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


using System;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.scheduler2;
using Unity.UIWidgets.services;
public class PaintingBinding : GestureBinding {
public class PaintingBinding : ServicesBinding {
protected override void initInstances() {
base.initInstances();
instance = this;

}
public new static PaintingBinding instance {
get { return (PaintingBinding) GestureBinding.instance; }
get { return (PaintingBinding) ServicesBinding.instance; }
set { Window.instance._binding = value; }
}

ImageCache _imageCache;
readonly _SystemFontsNotifier _systemFonts = new _SystemFontsNotifier();
public _SystemFontsNotifier systemFonts {
public Listenable systemFonts {
readonly _SystemFontsNotifier _systemFonts = new _SystemFontsNotifier();
}
public static partial class painting_ {
public static ImageCache imageCache => PaintingBinding.instance.imageCache;
public Future<ui.Codec> instantiateImageCodec(byte[] bytes,
int? cacheWidth = null,
int? cacheHeight = null
) {
D.assert(cacheWidth == null || cacheWidth > 0);
D.assert(cacheHeight == null || cacheHeight > 0);
return ui_.instantiateImageCodec(
bytes,
targetWidth: cacheWidth,
targetHeight: cacheHeight
);
}
public class _SystemFontsNotifier : Listenable {
HashSet<VoidCallback> _systemFontsCallbacks = new HashSet<VoidCallback>();
internal class _SystemFontsNotifier : Listenable {
readonly HashSet<VoidCallback> _systemFontsCallbacks = new HashSet<VoidCallback>();
void notifyListeners () {
void notifyListeners() {
public void addListener(VoidCallback listener) {
_systemFontsCallbacks.Add(listener);
}

}
}
public static partial class painting_ {
public static ImageCache imageCache => PaintingBinding.instance.imageCache;
}
}

680
com.unity.uiwidgets/Runtime/painting/border_radius.cs


using System;
using System.Text;
using Unity.UIWidgets.foundation;
public class BorderRadius : IEquatable<BorderRadius> {
public abstract class BorderRadiusGeometry : IEquatable<BorderRadiusGeometry> {
public BorderRadiusGeometry() {
}
protected virtual Radius _topLeft { get; }
protected virtual Radius _topRight { get; }
protected virtual Radius _bottomLeft { get; }
protected virtual Radius _bottomRight { get; }
protected virtual Radius _topStart { get; }
protected virtual Radius _topEnd { get; }
protected virtual Radius _bottomStart { get; }
protected virtual Radius _bottomEnd { get; }
public virtual BorderRadiusGeometry subtract(BorderRadiusGeometry other) {
return new _MixedBorderRadius(
_topLeft - other._topLeft,
_topRight - other._topRight,
_bottomLeft - other._bottomLeft,
_bottomRight - other._bottomRight,
_topStart - other._topStart,
_topEnd - other._topEnd,
_bottomStart - other._bottomStart,
_bottomEnd - other._bottomEnd
);
}
public virtual BorderRadiusGeometry add(BorderRadiusGeometry other) {
return new _MixedBorderRadius(
_topLeft + other._topLeft,
_topRight + other._topRight,
_bottomLeft + other._bottomLeft,
_bottomRight + other._bottomRight,
_topStart + other._topStart,
_topEnd + other._topEnd,
_bottomStart + other._bottomStart,
_bottomEnd + other._bottomEnd
);
}
public abstract BorderRadiusGeometry SelfMinus();
public static BorderRadiusGeometry operator -(BorderRadiusGeometry other) {
return other.SelfMinus();
}
public abstract BorderRadiusGeometry Multiply(float other);
public static BorderRadiusGeometry operator *(BorderRadiusGeometry self, float other) {
return self.Multiply(other);
}
public abstract BorderRadiusGeometry Divide(float other);
public static BorderRadiusGeometry operator /(BorderRadiusGeometry self, float other) {
return self.Divide(other);
}
public abstract BorderRadiusGeometry Remainder(float other);
public static BorderRadiusGeometry operator %(BorderRadiusGeometry self, float other) {
return self.Remainder(other);
}
public static BorderRadiusGeometry lerp(BorderRadiusGeometry a, BorderRadiusGeometry b, float t) {
if (a == null && b == null)
return null;
a = a ?? BorderRadius.zero;
b = b ?? BorderRadius.zero;
return a.add((b.subtract(a)) * t);
}
public abstract BorderRadius resolve(TextDirection? textDirection);
public override string ToString() {
String visual = null, logical = null;
if (_topLeft == _topRight &&
_topRight == _bottomLeft &&
_bottomLeft == _bottomRight) {
if (_topLeft != Radius.zero) {
if (_topLeft.x == _topLeft.y) {
visual = $"BorderRadius.circular({_topLeft.x})";
}
else {
visual = $"BorderRadius.all({_topLeft})";
}
}
}
else {
StringBuilder result = new StringBuilder();
result.Append("BorderRadius.only(");
bool comma = false;
if (_topLeft != Radius.zero) {
result.Append($"topLeft: {_topLeft}");
comma = true;
}
if (_topRight != Radius.zero) {
if (comma)
result.Append(", ");
result.Append($"topRight: {_topRight}");
comma = true;
}
if (_bottomLeft != Radius.zero) {
if (comma)
result.Append(", ");
result.Append($"bottomLeft: {_bottomLeft}");
comma = true;
}
if (_bottomRight != Radius.zero) {
if (comma)
result.Append(", ");
result.Append($"bottomRight: {_bottomRight}");
}
result.Append(")");
visual = result.ToString();
}
if (_topStart == _topEnd &&
_topEnd == _bottomEnd &&
_bottomEnd == _bottomStart) {
if (_topStart != Radius.zero) {
if (_topStart.x == _topStart.y) {
logical = $"BorderRadiusDirectional.circular({_topStart.x})";
}
else {
logical = $"BorderRadiusDirectional.all({_topStart})";
}
}
}
else {
StringBuilder result = new StringBuilder();
result.Append("BorderRadiusDirectional.only(");
bool comma = false;
if (_topStart != Radius.zero) {
result.Append($"topStart: {_topStart}");
comma = true;
}
if (_topEnd != Radius.zero) {
if (comma)
result.Append(", ");
result.Append($"topEnd: {_topEnd}");
comma = true;
}
if (_bottomStart != Radius.zero) {
if (comma)
result.Append(", ");
result.Append($"bottomStart: {_bottomStart}");
comma = true;
}
if (_bottomEnd != Radius.zero) {
if (comma)
result.Append(", ");
result.Append($"bottomEnd: {_bottomEnd}");
}
result.Append(")");
logical = result.ToString();
}
if (visual != null && logical != null)
return $"{visual} + {logical}";
if (visual != null)
return visual;
if (logical != null)
return logical;
return "BorderRadius.zero";
}
public static bool operator ==(BorderRadiusGeometry left, BorderRadiusGeometry right) {
return Equals(left, right);
}
public static bool operator !=(BorderRadiusGeometry left, BorderRadiusGeometry right) {
return Equals(left, right);
}
public bool Equals(BorderRadiusGeometry other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return Equals(_topLeft, other._topLeft) && Equals(_topRight, other._topRight) &&
Equals(_bottomLeft, other._bottomLeft) && Equals(_bottomRight, other._bottomRight) &&
Equals(_topStart, other._topStart) && Equals(_topEnd, other._topEnd) &&
Equals(_bottomStart, other._bottomStart) && Equals(_bottomEnd, other._bottomEnd);
}
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((BorderRadiusGeometry) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = (_topLeft != null ? _topLeft.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_topRight != null ? _topRight.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_bottomLeft != null ? _bottomLeft.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_bottomRight != null ? _bottomRight.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_topStart != null ? _topStart.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_topEnd != null ? _topEnd.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_bottomStart != null ? _bottomStart.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (_bottomEnd != null ? _bottomEnd.GetHashCode() : 0);
return hashCode;
}
}
}
public class BorderRadius : BorderRadiusGeometry, IEquatable<BorderRadius> {
BorderRadius(
Radius topLeft,
Radius topRight,

public static readonly BorderRadius zero = all(Radius.zero);
public readonly Radius topLeft;
protected override Radius _topLeft {
get => topLeft;
}
protected override Radius _topRight {
get => topRight;
}
public readonly Radius bottomLeft;
protected override Radius _bottomLeft {
get => bottomLeft;
}
public readonly Radius bottomLeft;
protected override Radius _bottomRight {
get => bottomRight;
}
protected override Radius _topStart {
get => Radius.zero;
}
protected override Radius _topEnd {
get => Radius.zero;
}
protected override Radius _bottomStart {
get => Radius.zero;
}
protected override Radius _bottomEnd {
get => Radius.zero;
}
public RRect toRRect(Rect rect) {
return RRect.fromRectAndCorners(

);
}
public static BorderRadius operator -(BorderRadius it) {
public override BorderRadiusGeometry SelfMinus() {
topLeft: -it.topLeft,
topRight: -it.topRight,
bottomLeft: -it.bottomLeft,
bottomRight: -it.bottomRight
topLeft: -topLeft,
topRight: -topRight,
bottomLeft: -bottomLeft,
bottomRight: -bottomRight
public static BorderRadius operator *(BorderRadius it, float other) {
public override BorderRadiusGeometry Multiply(float other) {
topLeft: it.topLeft * other,
topRight: it.topRight * other,
bottomLeft: it.bottomLeft * other,
bottomRight: it.bottomRight * other
topLeft: topLeft * other,
topRight: topRight * other,
bottomLeft: bottomLeft * other,
bottomRight: bottomRight * other
public static BorderRadius operator /(BorderRadius it, float other) {
public override BorderRadiusGeometry Divide(float other) {
topLeft: it.topLeft / other,
topRight: it.topRight / other,
bottomLeft: it.bottomLeft / other,
bottomRight: it.bottomRight / other
topLeft: topLeft / other,
topRight: topRight / other,
bottomLeft: bottomLeft / other,
bottomRight: bottomRight / other
public static BorderRadius operator %(BorderRadius it, float other) {
public override BorderRadiusGeometry Remainder(float other) {
topLeft: it.topLeft % other,
topRight: it.topRight % other,
bottomLeft: it.bottomLeft % other,
bottomRight: it.bottomRight % other
topLeft: topLeft % other,
topRight: topRight % other,
bottomLeft: bottomLeft % other,
bottomRight: bottomRight % other
);
}

}
if (a == null) {
return b * t;
return (BorderRadius) (b * t);
return a * (1.0f - t);
return (BorderRadius) (a * (1.0f - t));
}
return only(

public static bool operator !=(BorderRadius a, BorderRadius b) {
return !Equals(a, b);
}
public BorderRadius resolve(TextDirection direction) => this;
public override string ToString() {
string visual = null;
if (topLeft == topRight &&
topRight == bottomLeft &&
bottomLeft == bottomRight) {
if (topLeft != Radius.zero) {
if (topLeft.x == topLeft.y) {
visual = $"BorderRadius.circular({topLeft.x:F1})";
}
else {
visual = $"BorderRadius.all({topLeft})";
}
}
}
else {
var result = new StringBuilder();
result.Append("BorderRadius.only(");
bool comma = false;
if (topLeft != Radius.zero) {
result.Append($"topLeft: {topLeft}");
comma = true;
}
public override BorderRadius resolve(TextDirection? textDirection) => this;
}
if (topRight != Radius.zero) {
if (comma) {
result.Append(", ");
}
public class BorderRadiusDirectional : BorderRadiusGeometry {
BorderRadiusDirectional(
Radius topStart,
Radius topEnd,
Radius bottomStart,
Radius bottomEnd) {
this.topStart = topStart ?? Radius.zero;
this.topEnd = topEnd ?? Radius.zero;
this.bottomStart = bottomStart ?? Radius.zero;
this.bottomEnd = bottomEnd ?? Radius.zero;
}
public static BorderRadiusDirectional all(Radius radius) {
return only(
topStart: radius,
topEnd: radius,
bottomStart: radius,
bottomEnd: radius
);
}
public static BorderRadiusDirectional circular(float radius) {
return all(
Radius.circular(radius)
);
}
public static BorderRadiusDirectional vertical(
Radius top = null,
Radius bottom = null
) {
top = top ?? Radius.zero;
bottom = bottom ?? Radius.zero;
return only(
topStart: top,
topEnd: top,
bottomStart: bottom,
bottomEnd: bottom
);
}
result.Append($"topRight: {topRight}");
comma = true;
}
public static BorderRadiusDirectional horizontal(
Radius start = null,
Radius end = null
) {
start = start ?? Radius.zero;
end = end ?? Radius.zero;
return only(
topStart: start,
topEnd: end,
bottomStart: start,
bottomEnd: end
);
}
if (bottomLeft != Radius.zero) {
if (comma) {
result.Append(", ");
}
public static BorderRadiusDirectional only(
Radius topStart,
Radius topEnd,
Radius bottomStart,
Radius bottomEnd) {
return new BorderRadiusDirectional(topStart, topEnd, bottomStart, bottomEnd);
}
result.Append($"bottomLeft: {bottomLeft}");
comma = true;
}
public static readonly BorderRadiusDirectional zero = BorderRadiusDirectional.all(Radius.zero);
if (bottomRight != Radius.zero) {
if (comma) {
result.Append(", ");
}
public readonly Radius topStart;
result.Append($"bottomRight: {bottomRight}");
}
result.Append(")");
visual = result.ToString();
protected override Radius _topStart {
get => topStart;
}
public readonly Radius topEnd;
protected override Radius _topEnd {
get => topEnd;
}
public readonly Radius bottomStart;
protected override Radius _bottomStart {
get => bottomStart;
}
public readonly Radius bottomEnd;
protected override Radius _bottomEnd {
get => bottomEnd;
}
protected override Radius _topLeft {
get => Radius.zero;
}
protected override Radius _topRight {
get => Radius.zero;
}
protected override Radius _bottomLeft {
get => Radius.zero;
}
protected override Radius _bottomRight {
get => Radius.zero;
}
public override BorderRadiusGeometry subtract(BorderRadiusGeometry other) {
if (other is BorderRadiusDirectional borderRadiusDirectional)
return this - borderRadiusDirectional;
return base.subtract(other);
}
public override BorderRadiusGeometry add(BorderRadiusGeometry other) {
if (other is BorderRadiusDirectional)
return this + (BorderRadiusDirectional) other;
return base.add(other);
}
public static BorderRadiusDirectional operator -(BorderRadiusDirectional self, BorderRadiusDirectional other) {
return BorderRadiusDirectional.only(
topStart: self.topStart - other.topStart,
topEnd: self.topEnd - other.topEnd,
bottomStart: self.bottomStart - other.bottomStart,
bottomEnd: self.bottomEnd - other.bottomEnd
);
}
public static BorderRadiusDirectional operator +(BorderRadiusDirectional other, BorderRadiusDirectional right) {
return BorderRadiusDirectional.only(
topStart: other.topStart + right.topStart,
topEnd: other.topEnd + right.topEnd,
bottomStart: other.bottomStart + right.bottomStart,
bottomEnd: other.bottomEnd + right.bottomEnd
);
}
public override BorderRadiusGeometry SelfMinus() {
return BorderRadiusDirectional.only(
topStart: -topStart,
topEnd: -topEnd,
bottomStart: -bottomStart,
bottomEnd: -bottomEnd
);
}
public override BorderRadiusGeometry Multiply(float other) {
return BorderRadiusDirectional.only(
topStart: topStart * other,
topEnd: topEnd * other,
bottomStart: bottomStart * other,
bottomEnd: bottomEnd * other
);
}
public override BorderRadiusGeometry Divide(float other) {
return BorderRadiusDirectional.only(
topStart: topStart / other,
topEnd: topEnd / other,
bottomStart: bottomStart / other,
bottomEnd: bottomEnd / other
);
}
public override BorderRadiusGeometry Remainder(float other) {
return BorderRadiusDirectional.only(
topStart: topStart % other,
topEnd: topEnd % other,
bottomStart: bottomStart % other,
bottomEnd: bottomEnd % other
);
}
public static BorderRadiusDirectional lerp(BorderRadiusDirectional a, BorderRadiusDirectional b, float t) {
if (a == null && b == null)
return null;
if (a == null)
return (BorderRadiusDirectional) (b * t);
if (b == null)
return (BorderRadiusDirectional) (a * (1.0f - t));
return BorderRadiusDirectional.only(
topStart: Radius.lerp(a.topStart, b.topStart, t),
topEnd: Radius.lerp(a.topEnd, b.topEnd, t),
bottomStart: Radius.lerp(a.bottomStart, b.bottomStart, t),
bottomEnd: Radius.lerp(a.bottomEnd, b.bottomEnd, t)
);
}
public override BorderRadius resolve(TextDirection? direction) {
switch (direction) {
case TextDirection.rtl:
return BorderRadius.only(
topLeft: topEnd,
topRight: topStart,
bottomLeft: bottomEnd,
bottomRight: bottomStart
);
case TextDirection.ltr:
return BorderRadius.only(
topLeft: topStart,
topRight: topEnd,
bottomLeft: bottomStart,
bottomRight: bottomEnd
);
if (visual != null) {
return visual;
return null;
}
}
class _MixedBorderRadius : BorderRadiusGeometry {
internal _MixedBorderRadius(
Radius _topLeft,
Radius _topRight,
Radius _bottomLeft,
Radius _bottomRight,
Radius _topStart,
Radius _topEnd,
Radius _bottomStart,
Radius _bottomEnd) {
this._topLeft = _topLeft;
this._topRight = _topRight;
this._bottomLeft = _bottomLeft;
this._bottomRight = _bottomRight;
this._topStart = _topStart;
this._topEnd = _topEnd;
this._bottomStart = _bottomStart;
this._bottomEnd = _bottomEnd;
}
protected override Radius _topLeft { get; }
protected override Radius _topRight { get; }
protected override Radius _bottomLeft { get; }
protected override Radius _bottomRight { get; }
protected override Radius _topStart { get; }
protected override Radius _topEnd { get; }
protected override Radius _bottomStart { get; }
protected override Radius _bottomEnd { get; }
public override BorderRadiusGeometry SelfMinus() {
return new _MixedBorderRadius(
-_topLeft,
-_topRight,
-_bottomLeft,
-_bottomRight,
-_topStart,
-_topEnd,
-_bottomStart,
-_bottomEnd
);
}
public override BorderRadiusGeometry Multiply(float other) {
return new _MixedBorderRadius(
_topLeft * other,
_topRight * other,
_bottomLeft * other,
_bottomRight * other,
_topStart * other,
_topEnd * other,
_bottomStart * other,
_bottomEnd * other
);
}
public override BorderRadiusGeometry Divide(float other) {
return new _MixedBorderRadius(
_topLeft / other,
_topRight / other,
_bottomLeft / other,
_bottomRight / other,
_topStart / other,
_topEnd / other,
_bottomStart / other,
_bottomEnd / other
);
}
public override BorderRadiusGeometry Remainder(float other) {
return new _MixedBorderRadius(
_topLeft % other,
_topRight % other,
_bottomLeft % other,
_bottomRight % other,
_topStart % other,
_topEnd % other,
_bottomStart % other,
_bottomEnd % other
);
}
public override BorderRadius resolve(TextDirection? direction) {
switch (direction) {
case TextDirection.rtl:
return BorderRadius.only(
topLeft: _topLeft + _topEnd,
topRight: _topRight + _topStart,
bottomLeft: _bottomLeft + _bottomEnd,
bottomRight: _bottomRight + _bottomStart
);
case TextDirection.ltr:
return BorderRadius.only(
topLeft: _topLeft + _topStart,
topRight: _topRight + _topEnd,
bottomLeft: _bottomLeft + _bottomStart,
bottomRight: _bottomRight + _bottomEnd
);
return "BorderRadius.zero";
return null;
}
}
}

26
com.unity.uiwidgets/Runtime/painting/borders.cs


}
public override string ToString() {
return $"{GetType()}({color}, {width:F1}, {style})";
return $"{foundation_.objectRuntimeType(this, "BorderSize")}({color}, {width:F1}, {style})";
}
}

public abstract EdgeInsets dimensions { get; }
public virtual EdgeInsetsGeometry dimensions { get; }
public virtual ShapeBorder add(ShapeBorder other, bool reversed = false) {
return null;

return result ?? (t < 0.5 ? a : b);
}
public abstract Path getOuterPath(Rect rect);
public abstract Path getOuterPath(Rect rect, TextDirection? textDirection = null);
public abstract Path getInnerPath(Rect rect);
public abstract Path getInnerPath(Rect rect, TextDirection? textDirection = null);
public abstract void paint(Canvas canvas, Rect rect);
public abstract void paint(Canvas canvas, Rect rect, TextDirection? textDirection);
return $"{GetType()}()";
return $"{foundation_.objectRuntimeType(this, "BorderShape")}()";
}
}

public readonly List<ShapeBorder> borders;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get {
return borders.Aggregate(
EdgeInsets.zero,

return new _CompoundBorder(results);
}
public override Path getInnerPath(Rect rect) {
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
rect = borders[index].dimensions.deflateRect(rect);
rect = borders[index].dimensions.resolve(textDirection).deflateRect(rect);
public override Path getOuterPath(Rect rect) {
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
border.paint(canvas, rect);
rect = border.dimensions.deflateRect(rect);
border.paint(canvas, rect, textDirection);
rect = border.dimensions.resolve(textDirection).deflateRect(rect);
}
}

459
com.unity.uiwidgets/Runtime/painting/box_border.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.painting {

}
public class Border : ShapeBorder, IEquatable<Border> {
public abstract class BoxBorder : ShapeBorder {
public BoxBorder() {
isUniform = false;
}
public virtual BorderSide top { get; }
public virtual BorderSide bottom { get; }
public virtual bool isUniform { get; }
public override ShapeBorder add(ShapeBorder other, bool reversed = false) => null;
public static BoxBorder lerp(BoxBorder a, BoxBorder b, float t) {
D.assert(t != null);
if ((a is Border || a == null) && (b is Border || b == null))
return Border.lerp((Border) a, (Border) b, t);
if ((a is BorderDirectional || a == null) && (b is BorderDirectional || b == null))
return BorderDirectional.lerp(a as BorderDirectional, b as BorderDirectional, t);
if (b is Border && a is BorderDirectional) {
BoxBorder c = b;
b = a;
a = c;
t = 1.0f - t;
}
if (a is Border border && b is BorderDirectional borderDirectional) {
if (borderDirectional.start == BorderSide.none && borderDirectional.end == BorderSide.none) {
return new Border(
top: BorderSide.lerp(border.top, borderDirectional.top, t),
right: BorderSide.lerp(border.right, BorderSide.none, t),
bottom: BorderSide.lerp(border.bottom, borderDirectional.bottom, t),
left: BorderSide.lerp(border.left, BorderSide.none, t)
);
}
if (border.left == BorderSide.none && border.right == BorderSide.none) {
return new BorderDirectional(
top: BorderSide.lerp(border.top, borderDirectional.top, t),
start: BorderSide.lerp(BorderSide.none, borderDirectional.start, t),
end: BorderSide.lerp(BorderSide.none, borderDirectional.end, t),
bottom: BorderSide.lerp(border.bottom, borderDirectional.bottom, t)
);
}
if (t < 0.5f) {
return new Border(
top: BorderSide.lerp(border.top, borderDirectional.top, t),
right: BorderSide.lerp(border.right, BorderSide.none, t * 2.0f),
bottom: BorderSide.lerp(border.bottom, borderDirectional.bottom, t),
left: BorderSide.lerp(border.left, BorderSide.none, t * 2.0f)
);
}
return new BorderDirectional(
top: BorderSide.lerp(border.top, borderDirectional.top, t),
start: BorderSide.lerp(BorderSide.none, borderDirectional.start, (t - 0.5f) * 2.0f),
end: BorderSide.lerp(BorderSide.none, borderDirectional.end, (t - 0.5f) * 2.0f),
bottom: BorderSide.lerp(border.bottom, borderDirectional.bottom, t)
);
}
throw new UIWidgetsError(new List<DiagnosticsNode>() {
new ErrorSummary("BoxBorder.lerp can only interpolate Border and BorderDirectional classes."),
new ErrorDescription(
"BoxBorder.lerp() was called with two objects of type ${a.runtimeType} and ${b.runtimeType}:\n" +
" $a\n" +
" $b\n" +
"However, only Border and BorderDirectional classes are supported by this method."
),
new ErrorHint("For a more general interpolation method, consider using ShapeBorder.lerp instead.")
});
}
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
D.assert(textDirection != null,
() => "The textDirection argument to $runtimeType.getInnerPath must not be null.");
var result = new Path();
result.addRect(dimensions.resolve(textDirection).deflateRect(rect));
return result;
}
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
D.assert(textDirection != null,
() => "The textDirection argument to $runtimeType.getOuterPath must not be null.");
var result = new Path();
result.addRect(rect);
return result;
}
public virtual void paint(
Canvas canvas,
Rect rect,
TextDirection? textDirection = null,
BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadus = null
) {
paint(canvas, rect, textDirection);
}
internal static void _paintUniformBorderWithRadius(Canvas canvas, Rect rect, BorderSide side,
BorderRadius borderRadius) {
D.assert(side.style != BorderStyle.none);
Paint paint = new Paint();
paint.color = side.color;
RRect outer = borderRadius.toRRect(rect);
float width = side.width;
if (width == 0.0f) {
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 0.0f;
canvas.drawRRect(outer, paint);
}
else {
RRect inner = outer.deflate(width);
canvas.drawDRRect(outer, inner, paint);
}
}
internal static void _paintUniformBorderWithCircle(Canvas canvas, Rect rect, BorderSide side) {
D.assert(side.style != BorderStyle.none);
float width = side.width;
Paint paint = side.toPaint();
float radius = (rect.shortestSide - width) / 2.0f;
canvas.drawCircle(rect.center, radius, paint);
}
internal static void _paintUniformBorderWithRectangle(Canvas canvas, Rect rect, BorderSide side) {
D.assert(side.style != BorderStyle.none);
float width = side.width;
Paint paint = side.toPaint();
canvas.drawRect(rect.deflate(width / 2.0f), paint);
}
}
public class Border : BoxBorder, IEquatable<Border> {
public Border(
BorderSide top = null,
BorderSide right = null,

public readonly BorderSide bottom;
public readonly BorderSide left;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get {
return EdgeInsets.fromLTRB(
left.width,

);
}
public override void paint(Canvas canvas, Rect rect) {
paint(canvas, rect, BoxShape.rectangle, null);
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection) {
paint(canvas, rect, textDirection);
TextDirection? textDirection = null,
BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadius = null) {
if (isUniform) {

BorderUtils.paintBorder(canvas, rect,
top: top, right: right, bottom: bottom, left: left);
}
public override Path getInnerPath(Rect rect) {
var path = new Path();
path.addRect(dimensions.deflateRect(rect));
return path;
}
public override Path getOuterPath(Rect rect) {
var path = new Path();
path.addRect(rect);
return path;
}
static void _paintUniformBorderWithRadius(Canvas canvas, Rect rect, BorderSide side,

}
}
public override string ToString() {
if (isUniform) {
return $"{GetType()}.all({top})";

}
return $"{GetType()}({string.Join(", ", arguments)})";
}
}
public class BorderDirectional : BoxBorder, IEquatable<BorderDirectional> {
public BorderDirectional(
BorderSide top,
BorderSide start,
BorderSide end,
BorderSide bottom
) {
if (top == null) {
this.top = BorderSide.none;
}
if (start == null) {
this.start = BorderSide.none;
}
if (end == null) {
this.end = BorderSide.none;
}
if (bottom == null) {
this.bottom = BorderSide.none;
}
this.top = top;
this.start = start;
this.end = end;
this.bottom = bottom;
}
static BorderDirectional merge(BorderDirectional a, BorderDirectional b) {
D.assert(a != null);
D.assert(b != null);
D.assert(BorderSide.canMerge(a.top, b.top));
D.assert(BorderSide.canMerge(a.start, b.start));
D.assert(BorderSide.canMerge(a.end, b.end));
D.assert(BorderSide.canMerge(a.bottom, b.bottom));
return new BorderDirectional(
top: BorderSide.merge(a.top, b.top),
start: BorderSide.merge(a.start, b.start),
end: BorderSide.merge(a.end, b.end),
bottom: BorderSide.merge(a.bottom, b.bottom)
);
}
public override BorderSide top { get; }
public readonly BorderSide start;
public readonly BorderSide end;
public override BorderSide bottom { get; }
public override EdgeInsetsGeometry dimensions {
get => EdgeInsetsDirectional.fromSTEB(start.width, top.width, end.width, bottom.width);
}
public override bool isUniform {
get {
Color topColor = top.color;
if (start.color != topColor ||
end.color != topColor ||
bottom.color != topColor)
return false;
float topWidth = top.width;
if (start.width != topWidth ||
end.width != topWidth ||
bottom.width != topWidth)
return false;
BorderStyle topStyle = top.style;
if (start.style != topStyle ||
end.style != topStyle ||
bottom.style != topStyle)
return false;
return true;
}
}
public override ShapeBorder add(ShapeBorder other, bool reversed = false) {
if (other is BorderDirectional otherBorderDirectional) {
BorderDirectional typedOther = otherBorderDirectional;
if (BorderSide.canMerge(top, typedOther.top) &&
BorderSide.canMerge(start, typedOther.start) &&
BorderSide.canMerge(end, typedOther.end) &&
BorderSide.canMerge(bottom, typedOther.bottom)) {
return BorderDirectional.merge(this, typedOther);
}
return null;
}
if (other is Border otherBorder) {
Border typedOther = otherBorder;
if (!BorderSide.canMerge(typedOther.top, top) ||
!BorderSide.canMerge(typedOther.bottom, bottom))
return null;
if (start != BorderSide.none ||
end != BorderSide.none) {
if (typedOther.left != BorderSide.none ||
typedOther.right != BorderSide.none)
return null;
D.assert(typedOther.left == BorderSide.none);
D.assert(typedOther.right == BorderSide.none);
return new BorderDirectional(
top: BorderSide.merge(typedOther.top, top),
start: start,
end: end,
bottom: BorderSide.merge(typedOther.bottom, bottom)
);
}
D.assert(start == BorderSide.none);
D.assert(end == BorderSide.none);
return new Border(
top: BorderSide.merge(typedOther.top, top),
right: typedOther.right,
bottom: BorderSide.merge(typedOther.bottom, bottom),
left: typedOther.left
);
}
return null;
}
public override ShapeBorder scale(float t) {
return new BorderDirectional(
top: top.scale(t),
start: start.scale(t),
end: end.scale(t),
bottom: bottom.scale(t)
);
}
public override ShapeBorder lerpFrom(ShapeBorder a, float t) {
if (a is BorderDirectional borderDirectional)
return BorderDirectional.lerp(borderDirectional, this, t);
return base.lerpFrom(a, t);
}
public override ShapeBorder lerpTo(ShapeBorder b, float t) {
if (b is BorderDirectional borderDirectional)
return BorderDirectional.lerp(this, borderDirectional, t);
return base.lerpTo(b, t);
}
public static BorderDirectional lerp(BorderDirectional a, BorderDirectional b, float t) {
D.assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return (BorderDirectional) b.scale(t);
if (b == null)
return (BorderDirectional) a.scale(1.0f - t);
return new BorderDirectional(
top: BorderSide.lerp(a.top, b.top, t),
end: BorderSide.lerp(a.end, b.end, t),
bottom: BorderSide.lerp(a.bottom, b.bottom, t),
start: BorderSide.lerp(a.start, b.start, t)
);
}
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection) {
paint(canvas, rect, textDirection);
}
public override void paint(
Canvas canvas,
Rect rect,
TextDirection? textDirection = null,
BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadius = null
) {
if (isUniform) {
switch (top.style) {
case BorderStyle.none:
return;
case BorderStyle.solid:
switch (shape) {
case BoxShape.circle:
D.assert(borderRadius == null,
() => "A borderRadius can only be given for rectangular boxes.");
BoxBorder._paintUniformBorderWithCircle(canvas, rect, top);
break;
case BoxShape.rectangle:
if (borderRadius != null) {
BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius);
return;
}
BoxBorder._paintUniformBorderWithRectangle(canvas, rect, top);
break;
}
return;
}
}
D.assert(borderRadius == null, () => "A borderRadius can only be given for uniform borders.");
D.assert(shape == BoxShape.rectangle, () => "A border can only be drawn as a circle if it is uniform.");
BorderSide left = null, right = null;
D.assert(textDirection != null,
() => "Non-uniform BorderDirectional objects require a TextDirection when painting.");
switch (textDirection) {
case TextDirection.rtl:
left = end;
right = start;
break;
case TextDirection.ltr:
left = start;
right = end;
break;
}
BorderUtils.paintBorder(canvas, rect, top: top, left: left, bottom: bottom, right: right);
}
public override string ToString() {
List<String> arguments = new List<string>();
if
(top != BorderSide.none) {
arguments.Add("top: $top");
}
if (start != BorderSide.none) {
arguments.Add("start: $start");
}
if (end != BorderSide.none) {
arguments.Add("end: $end");
}
if (bottom != BorderSide.none) {
arguments.Add("bottom: $bottom");
}
return $"{foundation_.objectRuntimeType(this, "BorderDirectional")}({String.Join(", ", arguments)}";
}
public bool Equals(BorderDirectional other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return Equals(start, other.start) && Equals(end, other.end) && Equals(top, other.top) &&
Equals(bottom, other.bottom);
}
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((BorderDirectional) obj);
}
public static bool operator ==(BorderDirectional left, object right) {
if (left is null) {
return right is null;
}
return left.Equals(right);
}
public static bool operator !=(BorderDirectional left, object right) {
if (left is null) {
return !(right is null);
}
return !left.Equals(right);
}
public override int GetHashCode() {
unchecked {
var hashCode = (start != null ? start.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (end != null ? end.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (top != null ? top.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (bottom != null ? bottom.GetHashCode() : 0);
return hashCode;
}
}
}
}

2
com.unity.uiwidgets/Runtime/painting/box_decoration.cs


public readonly BlendMode? backgroundBlendMode;
public readonly BoxShape shape;
public override EdgeInsets padding {
public override EdgeInsetsGeometry padding {
get { return border?.dimensions; }
}

11
com.unity.uiwidgets/Runtime/painting/circle_border.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;

public readonly BorderSide side;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get { return EdgeInsets.all(side.width); }
}

return base.lerpTo(b, t);
}
public override Path getInnerPath(Rect rect) {
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
var path = new Path();
path.addOval(Rect.fromCircle(
center: rect.center,

}
public override Path getOuterPath(Rect rect) {
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
var path = new Path();
path.addOval(Rect.fromCircle(
center: rect.center,

}
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
switch (side.style) {
case BorderStyle.none:
break;

}
public override string ToString() {
return $"{GetType()}({side})";
return $"{foundation_.objectRuntimeType(this, "CircleBorder")}({side})";
}
}
}

276
com.unity.uiwidgets/Runtime/painting/colors.cs


using System;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
public partial class painting_ {
internal static float _getHue(float red, float green, float blue, float max, float delta) {
float hue = 0;
if (max == 0.0f) {
hue = 0.0f;
}
else if (max == red) {
hue = 60.0f * (((green - blue) / delta) % 6);
}
else if (max == green) {
hue = 60.0f * (((blue - red) / delta) + 2);
}
else if (max == blue) {
hue = 60.0f * (((red - green) / delta) + 4);
}
return hue;
}
internal static Color _colorFromHue(
float alpha,
float hue,
float chroma,
float secondary,
float match
) {
float red;
float green;
float blue;
if (hue < 60.0f) {
red = chroma;
green = secondary;
blue = 0.0f;
}
else if (hue < 120.0f) {
red = secondary;
green = chroma;
blue = 0.0f;
}
else if (hue < 180.0f) {
red = 0.0f;
green = chroma;
blue = secondary;
}
else if (hue < 240.0f) {
red = 0.0f;
green = secondary;
blue = chroma;
}
else if (hue < 300.0f) {
red = secondary;
green = 0.0f;
blue = chroma;
}
else {
red = chroma;
green = 0.0f;
blue = secondary;
}
return Color.fromARGB((alpha * 0xFF).round(), ((red + match) * 0xFF).round(),
((green + match) * 0xFF).round(), ((blue + match) * 0xFF).round());
}
}
public class HSVColor {
HSVColor(float alpha, float hue, float saturation, float value) {
D.assert(this.alpha >= 0);

float secondary = chroma * (1.0f - (((hue / 60.0f) % 2.0f) - 1.0f).abs());
float match = value - chroma;
return ColorUtils._colorFromHue(alpha, hue, chroma, secondary, match);
return painting_._colorFromHue(alpha, hue, chroma, secondary, match);
}
public readonly float alpha;

public override string ToString() {
return $"{foundation_.objectRuntimeType(this, "HSVColor")}({alpha}, {hue}, {saturation},{value})";
}
public class HSLColor : IEquatable<HSLColor> {
private HSLColor(float alpha,
float hue,
float saturation,
float lightness) {
this.alpha = alpha;
this.hue = hue;
this.saturation = saturation;
this.lightness = lightness;
}
public static HSLColor fromAHSL(float alpha, float hue, float saturation, float lightness) {
D.assert(alpha >= 0.0f);
D.assert(alpha <= 1.0f);
D.assert(hue >= 0.0f);
D.assert(hue <= 360.0f);
D.assert(saturation >= 0.0f);
D.assert(saturation <= 1.0f);
D.assert(lightness >= 0.0f);
D.assert(lightness <= 1.0f);
return new HSLColor(alpha, hue, saturation, lightness);
}
public static HSLColor fromColor(Color color) {
float red = color.red / 0xFF;
float green = color.green / 0xFF;
float blue = color.blue / 0xFF;
float max = Mathf.Max(red, Mathf.Max(green, blue));
float min = Mathf.Min(red, Mathf.Min(green, blue));
float delta = max - min;
float alpha = color.alpha / 0xFF;
float hue = painting_._getHue(red, green, blue, max, delta);
float lightness = (max + min) / 2.0f;
float saturation = lightness == 1.0f
? 0.0f
: ((delta / (1.0f - Mathf.Abs(2.0f * lightness - 1.0f))).clamp(0.0f, 1.0f));
return HSLColor.fromAHSL(alpha, hue, saturation, lightness);
}
readonly float alpha;
readonly float hue;
readonly float saturation;
readonly float lightness;
HSLColor withAlpha(float alpha) {
return HSLColor.fromAHSL(alpha, hue, saturation, lightness);
}
HSLColor withHue(float hue) {
return HSLColor.fromAHSL(alpha, hue, saturation, lightness);
}
HSLColor withSaturation(float saturation) {
return HSLColor.fromAHSL(alpha, hue, saturation, lightness);
}
HSLColor withLightness(float lightness) {
return HSLColor.fromAHSL(alpha, hue, saturation, lightness);
}
Color toColor() {
float chroma = Mathf.Abs(1.0f - (2.0f * lightness - 1.0f) * saturation);
float secondary = chroma * (1.0f - Mathf.Abs(((hue / 60.0f) % 2.0f) - 1.0f));
float match = lightness - chroma / 2.0f;
return painting_._colorFromHue(alpha, hue, chroma, secondary, match);
}
HSLColor _scaleAlpha(float factor) {
return withAlpha(alpha * factor);
}
static HSLColor lerp(HSLColor a, HSLColor b, float t) {
D.assert(t != null);
if (a == null && b == null)
return null;
if (a == null)
return b._scaleAlpha(t);
if (b == null)
return a._scaleAlpha(1.0f - t);
return HSLColor.fromAHSL(
Mathf.Lerp(a.alpha, b.alpha, t).clamp(0.0f, 1.0f),
Mathf.Lerp(a.hue, b.hue, t) % 360.0f,
Mathf.Lerp(a.saturation, b.saturation, t).clamp(0.0f, 1.0f),
Mathf.Lerp(a.lightness, b.lightness, t).clamp(0.0f, 1.0f)
);
}
public override string ToString() {
return $"{foundation_.objectRuntimeType(this, "HSLColor")}({alpha}, {hue}, {saturation}, {lightness})";
}
public static bool operator ==(HSLColor left, HSLColor right) {
return Equals(left, right);
}
public static bool operator !=(HSLColor left, HSLColor right) {
return !Equals(left, right);
}
public bool Equals(HSLColor other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return alpha.Equals(other.alpha) && hue.Equals(other.hue) && saturation.Equals(other.saturation) &&
lightness.Equals(other.lightness);
}
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((HSLColor) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = alpha.GetHashCode();
hashCode = (hashCode * 397) ^ hue.GetHashCode();
hashCode = (hashCode * 397) ^ saturation.GetHashCode();
hashCode = (hashCode * 397) ^ lightness.GetHashCode();
return hashCode;
}
}
}
public class ColorSwatch<T> : Color {
public ColorSwatch(
uint primary,

return GetType() + "(primary value: " + base.ToString() + ")";
}
}
public class ColorProperty : DiagnosticsProperty<Color> {
public ColorProperty(
string name = "",

D.assert(showName != null);
D.assert(style != null);
D.assert(level != null);
}
public override Dictionary<string, object> toJsonMap(DiagnosticsSerializationDelegate Delegate) {
}
public override Dictionary<string, object> toJsonMap(DiagnosticsSerializationDelegate Delegate) {
Dictionary<string, object> json = base.toJsonMap(Delegate);
if (value != null) {
json["valueProperties"] = new Dictionary<string, object> {

{"alpha", value.alpha}
};
}
}
}
public static class ColorUtils {
internal static Color _colorFromHue(
float alpha,
float hue,
float chroma,
float secondary,
float match
) {
float red;
float green;
float blue;
if (hue < 60.0) {
red = chroma;
green = secondary;
blue = 0.0f;
}
else if (hue < 120.0) {
red = secondary;
green = chroma;
blue = 0.0f;
}
else if (hue < 180.0) {
red = 0.0f;
green = chroma;
blue = secondary;
}
else if (hue < 240.0) {
red = 0.0f;
green = secondary;
blue = chroma;
}
else if (hue < 300.0) {
red = secondary;
green = 0.0f;
blue = chroma;
}
else {
red = chroma;
green = 0.0f;
blue = secondary;
}
return Color.fromARGB((alpha * 0xFF).round(),
((red + match) * 0xFF).round(),
((green + match) * 0xFF).round(), ((blue + match) * 0xFF).round());
}
}
}

26
com.unity.uiwidgets/Runtime/painting/continuous_rectangle_border.cs


public readonly BorderSide side;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get {
return EdgeInsets.all(side.width);
}

return new ContinuousRectangleBorder(
side: side.scale(t),
borderRadius: borderRadius * t
borderRadius: (BorderRadius) (borderRadius * t)
);
}

path.cubicTo(left, top, left, top, left + tlRadiusY, top);
path.lineTo(right - trRadiusX, top);
path.cubicTo(right, top, right, top, right, top + trRadiusY);
path.lineTo(right, bottom - blRadiusX);
path.cubicTo(right, bottom, right, bottom, right - blRadiusY, bottom);
path.lineTo(left + brRadiusX, bottom);
path.cubicTo(left, bottom, left, bottom, left, bottom - brRadiusY);
path.lineTo(right, bottom - brRadiusX);
path.cubicTo(right, bottom, right, bottom, right - brRadiusY, bottom);
path.lineTo(left + blRadiusX, bottom);
path.cubicTo(left, bottom, left, bottom, left, bottom - blRadiusY);
public override Path getInnerPath(Rect rect) {
return _getPath(borderRadius.toRRect(rect).deflate(side.width));
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
return _getPath(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.width));
public override Path getOuterPath(Rect rect) {
return _getPath(borderRadius.toRRect(rect));
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
return _getPath(borderRadius.resolve(textDirection).toRRect(rect));
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
if (rect.isEmpty) {
return;
}

break;
case BorderStyle.solid:
Path path = getOuterPath(rect);
Path path = getOuterPath(rect, textDirection);
Paint paint = side.toPaint();
canvas.drawPath(path, paint);
break;

}
public override string ToString() {
return $"{GetType()}({side}, {borderRadius})";
return $"{foundation_.objectRuntimeType(this, "ContinuousRectangleBorder")}({side}, {borderRadius})";
}
}
}

4
com.unity.uiwidgets/Runtime/painting/decoration.cs


}
public override string toStringShort() {
return GetType().ToString();
return foundation_.objectRuntimeType(this, "Decoration");
}
public virtual bool debugAssertIsValid() {

public virtual EdgeInsets padding {
public virtual EdgeInsetsGeometry padding {
get { return EdgeInsets.zero; }
}

69
com.unity.uiwidgets/Runtime/painting/decoration_image.cs


public class DecorationImage : IEquatable<DecorationImage> {
public DecorationImage(
ImageProvider image = null,
ImageErrorListener onError = null,
ImageRepeat repeat = ImageRepeat.noRepeat
ImageRepeat repeat = ImageRepeat.noRepeat,
bool matchTextDirection = false
this.onError = onError;
this.matchTextDirection = matchTextDirection;
public readonly ImageErrorListener onError;
public readonly bool matchTextDirection;
public DecorationImagePainter createPainter(VoidCallback onChanged) {
D.assert(onChanged != null);

D.assert(rect != null);
D.assert(configuration != null);
bool flipHorizontally = false;
if (_details.matchTextDirection) {
D.assert(() => {
// We check this first so that the assert will fire immediately, not just
// when the image is ready.
if (configuration.textDirection == null) {
throw new UIWidgetsError(new List<DiagnosticsNode>() {
new ErrorSummary(
"DecorationImage.matchTextDirection can only be used when a TextDirection is available."),
new ErrorDescription(
"When DecorationImagePainter.paint() was called, there was no text direction provided " +
"in the ImageConfiguration object to match."
),
new DiagnosticsProperty<DecorationImage>("The DecorationImage was", _details,
style: DiagnosticsTreeStyle.errorProperty),
new DiagnosticsProperty<ImageConfiguration>("The ImageConfiguration was", configuration,
style: DiagnosticsTreeStyle.errorProperty)
});
}
return true;
});
if (configuration.textDirection == TextDirection.rtl)
flipHorizontally = true;
}
_imageStream?.removeListener(_imageListener);
ImageStreamListener listener = new ImageStreamListener(
_handleImage,
onError: _details.onError
);
_imageStream?.removeListener(listener);
_imageStream.addListener(_imageListener);
_imageStream.addListener(listener);
}
if (_image == null) {

canvas.clipPath(clipPath);
}
ImageUtils.paintImage(
painting_.paintImage(
canvas: canvas,
rect: rect,
image: _image.image,

alignment: _details.alignment,
centerSlice: _details.centerSlice,
repeat: _details.repeat
repeat: _details.repeat,
flipHorizontally: flipHorizontally,
filterQuality: FilterQuality.low
);
if (clipPath != null) {

void _imageListener(ImageInfo value, bool synchronousCall) {
void _handleImage(ImageInfo value, bool synchronousCall) {
if (_image == value) {
return;
}

}
public void Dispose() {
_imageStream?.removeListener(_imageListener);
_imageStream?.removeListener(new ImageStreamListener(
_handleImage,
onError: _details.onError
));
}
public override string ToString() {

public static class ImageUtils {
public static partial class painting_ {
public static void paintImage(
Canvas canvas = null,
Rect rect = null,

Alignment alignment = null,
Rect centerSlice = null,
ImageRepeat repeat = ImageRepeat.noRepeat,
bool flipHorizontally = false,
bool invertColors = false,
FilterQuality filterQuality = FilterQuality.low
) {

float halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0f;
float halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0f;
float dx = halfWidthDelta + alignment.x * halfWidthDelta;
float dx = halfWidthDelta + (flipHorizontally ? -alignment.x : alignment.x) * halfWidthDelta;
bool needSave = repeat != ImageRepeat.noRepeat;
bool needSave = repeat != ImageRepeat.noRepeat || flipHorizontally;
}
if (flipHorizontally) {
float dxInside = -(rect.left + rect.width / 2.0f);
canvas.translate(-dxInside, 0.0f);
canvas.scale(-1.0f, 1.0f);
canvas.translate(dxInside, 0.0f);
}
if (repeat != ImageRepeat.noRepeat) {

42
com.unity.uiwidgets/Runtime/painting/edge_insets.cs


public abstract class EdgeInsetsGeometry {
float _bottom { get; }
float _end { get; }
float _left { get; }
float _right { get; }
float _start { get; }
float _top { get; }
internal float _bottom { get; }
internal float _end { get; }
internal float _left { get; }
internal float _right { get; }
internal float _start { get; }
internal float _top { get; }
public static EdgeInsetsGeometry infinity = _MixedEdgeInsets.fromLRSETB(

);
}
EdgeInsetsGeometry clamp(EdgeInsetsGeometry min, EdgeInsetsGeometry max) {
public virtual EdgeInsetsGeometry clamp(EdgeInsetsGeometry min, EdgeInsetsGeometry max) {
return _MixedEdgeInsets.fromLRSETB(
_left.clamp(min._left, max._left),
_right.clamp(min._right, max._right),

}
public abstract EdgeInsets resolve(TextDirection direction);
public abstract EdgeInsets resolve(TextDirection? direction);
public bool Equals(EdgeInsetsGeometry other) {
if (ReferenceEquals(null, other)) {

);
}
public override EdgeInsets resolve(TextDirection direction) {
public override EdgeInsets resolve(TextDirection? direction) {
D.assert(direction != null);
switch (direction) {
case TextDirection.rtl:

);
}
public override EdgeInsets resolve(TextDirection direction) {
public override EdgeInsets resolve(TextDirection? direction) {
D.assert(direction != null);
switch (direction) {
case TextDirection.rtl:

);
}
public EdgeInsets add(EdgeInsets other) {
public EdgeInsets add(EdgeInsetsGeometry other) {
left + other.left,
top + other.top,
right + other.right,
bottom + other.bottom
left + other._left,
top + other._top,
right + other._right,
bottom + other._bottom
public EdgeInsets clamp(EdgeInsets min, EdgeInsets max) {
public override EdgeInsetsGeometry clamp(EdgeInsetsGeometry min, EdgeInsetsGeometry max) {
left.clamp(min.left, min.left),
top.clamp(min.top, min.top),
right.clamp(min.right, min.right),
bottom.clamp(min.bottom, min.bottom)
left.clamp(min._left, max._left),
top.clamp(min._top, max._top),
right.clamp(min._right, max._right),
bottom.clamp(min._bottom, max._bottom)
);
}

&& bottom.Equals(other.bottom);
}
public override EdgeInsets resolve(TextDirection direction) {
public override EdgeInsets resolve(TextDirection? direction) {
return this;
}

10
com.unity.uiwidgets/Runtime/painting/gradient.cs


}
public readonly List<Color> colors;
public readonly List<float> stops;
public readonly GradientTransform transform;

}
public override string ToString() {
return $"{GetType()}({begin}, {end}," +
return $"{foundation_.objectRuntimeType(this, "LinearGradient")}({begin}, {end}," +
$"{colors.toStringList()}, {stops.toStringList()}, {tileMode})";
}
}

}
public override string ToString() {
return $"{GetType()}({center}, {radius}," +
return $"{foundation_.objectRuntimeType(this, "RadialGradient")}({center}, {radius}," +
$"{colors.toStringList()}, {stops.toStringList()}, {tileMode})";
}
}

}
public override string ToString() {
return $"{GetType()}({center}, {startAngle}, {endAngle}, " +
$"{colors.toStringList()}, {stops.toStringList()}, {tileMode})";
return $"{foundation_.objectRuntimeType(this, "SweepGradient")}({center}, {startAngle}," +
$" {endAngle}, {colors.toStringList()}, {stops.toStringList()}, {tileMode})";
}
}
}

233
com.unity.uiwidgets/Runtime/painting/image_cache.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
//TODO: TimeLineTask
public class ImageCache {
const int _kDefaultSize = 1000;
const int _kDefaultSizeBytes = 100 << 20; // 100 MiB

readonly Dictionary<object, _CachedImage> _cache = new Dictionary<object, _CachedImage>();
readonly Dictionary<object, _LiveImage> _liveImages = new Dictionary<object, _LiveImage>();
readonly LinkedList<object> _lruKeys = new LinkedList<object>();
int _maximumSize = _kDefaultSize;

_lruKeys.Clear();
}
public bool evict(object key) {
public bool evict(object key, bool includeLive = true) {
if (includeLive) {
_LiveImage liveImage = _liveImages.getOrDefault(key);
_liveImages.Remove(key);
liveImage?.removeListener();
}
D.assert(key != null);
if (_pendingImages.TryGetValue(key, out var pendingImage)) {

}
if (_cache.TryGetValue(key, out var image)) {
_currentSizeBytes -= image.sizeBytes;
_currentSizeBytes -= image.sizeBytes ?? 0;
_cache.Remove(key);
_lruKeys.Remove(image.node);
return true;

}
void _touch(Object key, _CachedImage image) {
D.assert(foundation_.kReleaseMode);
if (image.sizeBytes != null && image.sizeBytes <= maximumSizeBytes) {
_currentSizeBytes += image.sizeBytes ?? 0;
_cache[key] = image;
// _checkCacheSize(timelineTask);
}
}
void _trackLiveImage(Object key, _LiveImage image, bool debugPutOk = true) {
var imageOut = _liveImages.putIfAbsent(key, () => {
D.assert(debugPutOk);
image.completer.addOnLastListenerRemovedCallback(image.handleRemove);
return image;
});
imageOut.sizeBytes = image.sizeBytes ?? image.sizeBytes;
}
public ImageStreamCompleter putIfAbsent(object key, Func<ImageStreamCompleter> loader,
ImageErrorListener onError = null) {
D.assert(key != null);

}
if (_cache.TryGetValue(key, out var image)) {
// put to the MRU position
_trackLiveImage(key, new _LiveImage(image.completer, image.sizeBytes, () => _liveImages.Remove(key)));
_CachedImage liveImage = _liveImages[key];
if (liveImage != null) {
_touch(key, liveImage);
return liveImage.completer;
}
_trackLiveImage(key, new _LiveImage(result, null, () => _liveImages.Remove(key)));
}
catch (Exception ex) {
if (onError != null) {

}
}
bool listenedOnce = false;
_PendingImage untrackedPendingImage = null;
if (maximumSizeBytes > 0 && imageSize > maximumSizeBytes) {
_maximumSizeBytes = imageSize + 1000;
_trackLiveImage(
key,
new _LiveImage(
result,
imageSize,
() => _liveImages.Remove(key)
),
debugPutOk: syncCall
);
_PendingImage _pendingImage = untrackedPendingImage ?? _pendingImages.getOrDefault(key);
_pendingImages.Remove(key);
if (_pendingImage != null) {
_pendingImage.removeListener();
_currentSizeBytes += imageSize;
if (_pendingImages.TryGetValue(key, out var loadedPendingImage)) {
loadedPendingImage.removeListener();
_pendingImages.Remove(key);
if (untrackedPendingImage == null) {
_touch(key, image);
D.assert(!_cache.ContainsKey(key));
_cache[key] = cachedImage;
cachedImage.node = _lruKeys.AddLast(key);
_checkCacheSize();
listenedOnce = true;
ImageStreamListener streamListener = new ImageStreamListener(listener);
_pendingImages[key] = new _PendingImage(result, listener);
result.addListener(listener);
_pendingImages[key] = new _PendingImage(result, streamListener);
}
else {
untrackedPendingImage = new _PendingImage(result, streamListener);
result.addListener(streamListener);
public ImageCacheStatus statusForKey(Object key) {
return new ImageCacheStatus(
pending: _pendingImages.ContainsKey(key),
keepAlive: _cache.ContainsKey(key),
live: _liveImages.ContainsKey(key)
);
}
bool containsKey(Object key) {
return _pendingImages[key] != null || _cache[key] != null;
}
int liveImageCount {
get => _liveImages.Count;
}
int pendingImageCount {
get => _pendingImages.Count;
}
void clearLiveImages() {
foreach (_LiveImage
image in _liveImages.Values) {
image.removeListener();
}
_liveImages.Clear();
}
while (_currentSizeBytes > _maximumSizeBytes || _cache.Count > _maximumSize) {
var node = _lruKeys.First;
var key = node.Value; // get the LRU item
Dictionary<string, object> finishArgs = new Dictionary<string, object>();
// TimelineTask checkCacheTask;
if (!foundation_.kReleaseMode) {
// checkCacheTask = TimelineTask(parent: timelineTask)..start('checkCacheSize');
finishArgs["evictedKeys"] = new List<string>();
finishArgs["currentSize"] = currentSize;
finishArgs["currentSizeBytes"] = currentSizeBytes;
}
D.assert(_cache.ContainsKey(key));
while (_currentSizeBytes > _maximumSizeBytes || _cache.Count > _maximumSize) {
object key = _cache.Keys.GetEnumerator().Current;
_currentSizeBytes -= image.sizeBytes ?? 0;
_cache.Remove(key);
if (!foundation_.kReleaseMode) {
((List<string>) finishArgs["evictedKeys"]).Add(key.ToString());
}
}
D.assert(node == image.node);
_currentSizeBytes -= image.sizeBytes;
_cache.Remove(key);
_lruKeys.Remove(image.node);
if (!foundation_.kReleaseMode) {
finishArgs["endSize"] = currentSize;
finishArgs["endSizeBytes"] = currentSizeBytes;
// checkCacheTask.finish(arguments: finishArgs);
}
D.assert(_currentSizeBytes >= 0);

}
public class ImageCacheStatus : IEquatable<ImageCacheStatus> {
internal ImageCacheStatus(
bool pending = false,
bool keepAlive = false,
bool live = false
) {
D.assert(!pending || !keepAlive);
this.pending = pending;
this.keepAlive = keepAlive;
this.live = live;
}
public bool pending;
public bool keepAlive;
public bool live;
public bool tracked {
get => pending || keepAlive || live;
}
public bool untracked {
get => !pending && !keepAlive && !live;
}
public override string ToString() =>
$"{foundation_.objectRuntimeType(this, "ImageCacheStatus")}(pending: {pending}, live: {live}, keepAlive: {keepAlive})";
public bool Equals(ImageCacheStatus other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return pending == other.pending && keepAlive == other.keepAlive && live == other.live;
}
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((ImageCacheStatus) obj);
}
public static bool operator ==(ImageCacheStatus left, object right) {
return Equals(left, right);
}
public static bool operator !=(ImageCacheStatus left, object right) {
return !Equals(left, right);
}
public override int GetHashCode() {
unchecked {
var hashCode = pending.GetHashCode();
hashCode = (hashCode * 397) ^ keepAlive.GetHashCode();
hashCode = (hashCode * 397) ^ live.GetHashCode();
return hashCode;
}
}
}
public _CachedImage(ImageStreamCompleter completer, int sizeBytes) {
public _CachedImage(ImageStreamCompleter completer, int? sizeBytes) {
public int sizeBytes;
public int? sizeBytes;
class _LiveImage : _CachedImage {
internal _LiveImage(ImageStreamCompleter completer, int? sizeBytes, VoidCallback handleRemove)
: base(completer, sizeBytes) {
this.handleRemove = handleRemove;
}
public readonly VoidCallback handleRemove;
public void removeListener() {
completer.removeOnLastListenerRemovedCallback(handleRemove);
}
}
ImageListener listener
ImageStreamListener listener
) {
this.completer = completer;
this.listener = listener;

public readonly ImageListener listener;
public readonly ImageStreamListener listener;
public void removeListener() {
completer.removeListener(listener);

241
com.unity.uiwidgets/Runtime/painting/image_provider.cs


public abstract class ImageProvider {
public abstract ImageStream resolve(ImageConfiguration configuration);
public static bool operator !=(ImageProvider left, ImageProvider right) {
return !Equals(left, right);
}

return stream;
}
public ImageStream createStream(ImageConfiguration configuration) {
return new ImageStream();
}
// This is an unusual edge case where someone has told us that they found
// the image we want before getting to this method. We should avoid calling
// load again, but still update the image cache with LRU information.
if (stream.completer != null) {
ImageStreamCompleter completerEdge = PaintingBinding.instance.imageCache.putIfAbsent(
key,

return obtainKey(configuration).then(key => cache.evict(key)).to<bool>();
}
protected abstract ImageStreamCompleter load(T assetBundleImageKey, DecoderCallback decode);
public abstract ImageStreamCompleter load(T assetBundleImageKey, DecoderCallback decode);
public abstract Future<T> obtainKey(ImageConfiguration configuration);
Future<ImageCacheStatus> obtainCacheStatus(
ImageConfiguration configuration,
ImageErrorListener handleError = null
) {
D.assert(configuration != null);
Completer completer = Completer.create();
_createErrorHandlerAndKey(
configuration,
(T key, Action<Exception> innerHandleError) => {
completer.complete(FutureOr.value(PaintingBinding.instance.imageCache.statusForKey(key)));
},
(T key, Exception exception) => {
if (handleError != null) {
handleError(exception);
}
else {
InformationCollector collector = null;
D.assert(() => {
IEnumerable<DiagnosticsNode> infoCollector() {
yield return new DiagnosticsProperty<ImageProvider>("Image provider", this);
yield return new DiagnosticsProperty<ImageConfiguration>("Image configuration",
configuration);
yield return new DiagnosticsProperty<T>("Image key", key, defaultValue: null);
}
protected abstract Future<T> obtainKey(ImageConfiguration configuration);
collector = infoCollector;
return true;
});
UIWidgetsError.onError(new UIWidgetsErrorDetails(
context: new ErrorDescription("while checking the cache location of an image"),
informationCollector: collector,
exception: exception
));
completer.complete();
}
return Future.value();
}
);
return completer.future.to<ImageCacheStatus>();
}
private void _createErrorHandlerAndKey(
ImageConfiguration configuration,

didError = true;
};
// If an error is added to a synchronous completer before a listener has been
// added, it can throw an error both into the zone and up the stack. Thus, it
// looks like the error has been caught, but it is in fact also bubbling to the
// zone. Since we cannot prevent all usage of Completer.sync here, or rather
// that changing them would be too breaking, we instead hook into the same
// zone mechanism to intercept the uncaught error and deliver it to the
// image stream's error handler. Note that these errors may be duplicated,
// hence the need for the `didError` flag.
Zone dangerZone = Zone.current.fork(
specification: new ZoneSpecification(
handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone, Exception error) => {

protected AssetBundleImageProvider() {
}
protected override ImageStreamCompleter load(AssetBundleImageKey key, DecoderCallback decode) {
public override ImageStreamCompleter load(AssetBundleImageKey key, DecoderCallback decode) {
return new MultiFrameImageStreamCompleter(
codec: _loadAsync(key, decode),
scale: key.scale,

}
}
internal class _SizeAwareCacheKey : IEquatable<_SizeAwareCacheKey> {
internal _SizeAwareCacheKey(object providerCacheKey, int width, int height) {
this.providerCacheKey = providerCacheKey;
this.width = width;
this.height = height;
}
public readonly object providerCacheKey;
public readonly int width;
public readonly int height;
public static bool operator ==(_SizeAwareCacheKey left, object right) {
return Equals(left, right);
}
public static bool operator !=(_SizeAwareCacheKey left, object right) {
return !Equals(left, right);
}
public bool Equals(_SizeAwareCacheKey other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return Equals(providerCacheKey, other.providerCacheKey) && width == other.width && height == other.height;
}
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((_SizeAwareCacheKey) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = (providerCacheKey != null ? providerCacheKey.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ width;
hashCode = (hashCode * 397) ^ height;
return hashCode;
}
}
}
internal class ResizeImage : ImageProvider<_SizeAwareCacheKey> {
public ResizeImage(
ImageProvider<object> imageProvider,
int width = 0,
int height = 0
) {
D.assert(width != null || height != null);
this.imageProvider = imageProvider;
this.width = width;
this.height = height;
}
public readonly ImageProvider<object> imageProvider;
public readonly int width;
public readonly int height;
public static ImageProvider resizeIfNeeded(int cacheWidth, int cacheHeight, ImageProvider<object> provider) {
if (cacheWidth != null || cacheHeight != null) {
return new ResizeImage(provider, width: cacheWidth, height: cacheHeight);
}
return provider;
}
public override ImageStreamCompleter load(_SizeAwareCacheKey assetBundleImageKey, DecoderCallback decode) {
Future<Codec> decodeResize(byte[] bytes, int? cacheWidth = 0, int? cacheHeight = 0) {
D.assert(
cacheWidth == null && cacheHeight == null,
() =>
"ResizeImage cannot be composed with another ImageProvider that applies cacheWidth or cacheHeight."
);
return decode(bytes, cacheWidth: width, cacheHeight: height);
}
return imageProvider.load(assetBundleImageKey.providerCacheKey, decodeResize);
}
public override Future<_SizeAwareCacheKey> obtainKey(ImageConfiguration configuration) {
Completer completer = null;
SynchronousFuture<_SizeAwareCacheKey> result = null;
imageProvider.obtainKey(configuration).then((object key) => {
// TODO: completer is always null?
if (completer == null) {
result = new SynchronousFuture<_SizeAwareCacheKey>(new _SizeAwareCacheKey(key, width, height));
}
else {
completer.complete(FutureOr.value(new _SizeAwareCacheKey(key, width, height)));
}
});
if (result != null) {
return result;
}
completer = Completer.create();
return completer.future.to<_SizeAwareCacheKey>();
}
}
public class NetworkImage : ImageProvider<NetworkImage>, IEquatable<NetworkImage> {
public NetworkImage(string url,
float scale = 1.0f,

public readonly IDictionary<string, string> headers;
protected override Future<NetworkImage> obtainKey(ImageConfiguration configuration) {
public override Future<NetworkImage> obtainKey(ImageConfiguration configuration) {
protected override ImageStreamCompleter load(NetworkImage key, DecoderCallback decode) {
public override ImageStreamCompleter load(NetworkImage key, DecoderCallback decode) {
return new MultiFrameImageStreamCompleter(
codec: _loadAsync(key, decode),
scale: key.scale,

var completer = Completer.create();
var isolate = Isolate.current;
var panel = UIWidgetsPanel.current;
panel.StartCoroutine(_loadCoroutine(key.url, completer, isolate));
panel.StartCoroutine(_loadCoroutine(key.url, completer, isolate));
IEnumerator _loadCoroutine(string key, Completer completer, Isolate isolate) {
var url = new Uri(key);
using (var www = UnityWebRequest.Get(url)) {

public readonly float scale;
protected override Future<FileImage> obtainKey(ImageConfiguration configuration) {
public override Future<FileImage> obtainKey(ImageConfiguration configuration) {
protected override ImageStreamCompleter load(FileImage key, DecoderCallback decode) {
public override ImageStreamCompleter load(FileImage key, DecoderCallback decode) {
return new MultiFrameImageStreamCompleter(_loadAsync(key, decode),
scale: key.scale,
informationCollector: infoCollector);

byte[] bytes = File.ReadAllBytes("Assets/StreamingAssets/" + key.file);
if (bytes != null && bytes.Length > 0 ) {
if (bytes != null && bytes.Length > 0) {
throw new Exception("not loaded");
}

}
public override string ToString() {
return $"{GetType()}(\"{file}\", scale: {scale})";
return $"{foundation_.objectRuntimeType(this, "FileImage")}({file}, scale: {scale})";
}
}

public readonly float scale;
protected override Future<MemoryImage> obtainKey(ImageConfiguration configuration) {
public override Future<MemoryImage> obtainKey(ImageConfiguration configuration) {
protected override ImageStreamCompleter load(MemoryImage key, DecoderCallback decode) {
public override ImageStreamCompleter load(MemoryImage key, DecoderCallback decode) {
return new MultiFrameImageStreamCompleter(
_loadAsync(key, decode),
scale: key.scale);

}
public override string ToString() {
return $"{GetType()}({foundation_.describeIdentity(bytes)}), scale: {scale}";
return
$"{foundation_.objectRuntimeType(this, "MemoryImage")}({foundation_.describeIdentity(bytes)}), scale: {scale}";
}
}

public readonly AssetBundle bundle;
protected override Future<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) {
public override Future<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) {
return Future.value(FutureOr.value(new AssetBundleImageKey(
bundle: bundle ? bundle : configuration.bundle,
name: assetName,

}
public override string ToString() {
return $"{GetType()}(name: \"{assetName}\", scale: {scale}, bundle: {bundle})";
return
$"{foundation_.objectRuntimeType(this, "ExactAssetImage")}(name: \"{assetName}\", scale: {scale}, bundle: {bundle})";
}
}

silent: silent
);
}
}
public class NetworkImageLoadException : Exception {
NetworkImageLoadException(int statusCode, Uri uri) {
D.assert(uri != null);
D.assert(statusCode != null);
this.statusCode = statusCode;
this.uri = uri;
_message = $"HTTP request failed, statusCode: {statusCode}, {uri}";
}
public readonly int statusCode;
readonly string _message;
public readonly Uri uri;
public override string ToString() => _message;
}
}

66
com.unity.uiwidgets/Runtime/painting/image_resolution.cs


using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Unity.UIWidgets.external;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;

}
public readonly string assetName;
public string keyName {
get { return package == null ? assetName : "packages/$package/$assetName"; }
}
public readonly string package;
public const float _naturalResolution = 1.0f;
protected override Future<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) {
public override Future<AssetBundleImageKey> obtainKey(ImageConfiguration configuration) {
AssetImageConfiguration assetConfig = new AssetImageConfiguration(configuration, assetName);
AssetBundleImageKey key;
var cache = AssetBundleCache.instance.get(configuration.bundle);

var devicePixelRatio = configuration.devicePixelRatio ?? Window.instance.devicePixelRatio;
key = _loadAsset(chosenBundle, devicePixelRatio);
cache[assetConfig] = key;
internal string _chooseVariant(string main, ImageConfiguration config, List<string> candidates) {
if (config.devicePixelRatio == null || candidates == null || candidates.isEmpty())
return main;
SplayTree<float, string> mapping = new SplayTree<float, string>();
foreach (string candidate in candidates) {
mapping[_parseScale(candidate)] = candidate;
}
return _findNearest(mapping, config.devicePixelRatio ?? 0);
}
string _findNearest(SplayTree<float, string> candidates, float value) {
if (candidates.ContainsKey(value))
return candidates[value];
float lower = candidates.lastKeyBefore(value);
float upper = candidates.firstKeyAfter(value);
if (lower == null)
return candidates[upper];
if (upper == null)
return candidates[lower];
if (value > (lower + upper) / 2)
return candidates[upper];
else
return candidates[lower];
}
internal static readonly Regex _extractRatioRegExp = new Regex(@"/?(\d+(\.\d*)?)x$");
float _parseScale(string key) {
if (key == assetName) {
return _naturalResolution;
}
Uri assetUri = new Uri(key);
string directoryPath = "";
if (assetUri.Segments.Length > 1) {
directoryPath = assetUri.Segments[assetUri.Segments.Length - 2];
}
Match match = _extractRatioRegExp.Match(directoryPath);
if (match != null && match.Groups.Count > 0)
return float.Parse(match.Groups[1].Value);
return _naturalResolution;
}
AssetBundleImageKey _loadAsset(AssetBundle bundle, float devicePixelRatio) {
var extension = Path.GetExtension(this.assetName);
var name = Path.GetFileNameWithoutExtension(this.assetName);

Object asset;
if (bundle == null) {
asset = Resources.Load(assetName);
} else {
}
else {
asset = bundle.LoadAsset(assetName);
}

} else {
}
else {
bundle.Unload(asset);
}

}
public override string ToString() {
return $"{GetType()}(bundle: {bundle}, name: \"{assetName}\")";
return $"{foundation_.objectRuntimeType(this, "AssetImage")}(bundle: {bundle}, name: \"{assetName}\")";
}
}

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


}
}
public class ImageStreamListener : IEquatable<ImageStreamListener> {
public ImageStreamListener(
ImageListener onImage,
ImageChunkListener onChunk = null,
ImageErrorListener onError = null
) {
D.assert(onImage != null);
this.onImage = onImage;
this.onChunk = onChunk;
this.onError = onError;
}
public readonly ImageListener onImage;
public readonly ImageChunkListener onChunk;
public readonly ImageErrorListener onError;
public bool Equals(ImageStreamListener other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return Equals(onImage, other.onImage) && Equals(onChunk, other.onChunk) && Equals(onError, other.onError);
}
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((ImageStreamListener) obj);
}
public static bool operator ==(ImageStreamListener left, ImageStreamListener right) {
return Equals(left, right);
}
public static bool operator !=(ImageStreamListener left, ImageStreamListener right) {
return !Equals(left, right);
}
public override int GetHashCode() {
unchecked {
var hashCode = (onImage != null ? onImage.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (onChunk != null ? onChunk.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (onError != null ? onError.GetHashCode() : 0);
return hashCode;
}
}
}
public delegate void ImageChunkListener(ImageChunkEvent evt);
class _ImageListenerPair {
public ImageListener listener;
public ImageErrorListener errorListener;
public class ImageChunkEvent : Diagnosticable {
public ImageChunkEvent(
int cumulativeBytesLoaded,
int expectedTotalBytes
) {
D.assert(cumulativeBytesLoaded >= 0);
D.assert(expectedTotalBytes >= 0);
this.cumulativeBytesLoaded = cumulativeBytesLoaded;
this.expectedTotalBytes = expectedTotalBytes;
}
public readonly int cumulativeBytesLoaded;
public readonly int expectedTotalBytes;
public override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new IntProperty("cumulativeBytesLoaded", cumulativeBytesLoaded));
properties.add(new IntProperty("expectedTotalBytes", expectedTotalBytes));
}
}
public class ImageStream : Diagnosticable {

get { return _completer; }
}
List<_ImageListenerPair> _listeners;
List<ImageStreamListener> _listeners;
public void setCompleter(ImageStreamCompleter value) {
D.assert(_completer == null);

var initialListeners = _listeners;
_listeners = null;
foreach (_ImageListenerPair listenerPair in initialListeners) {
_completer.addListener(
listenerPair.listener,
listenerPair.errorListener
);
}
initialListeners.ForEach(_completer.addListener);
public void addListener(ImageListener listener, ImageErrorListener onError = null) {
public void addListener(ImageStreamListener listener) {
_completer.addListener(listener, onError);
_completer.addListener(listener);
_listeners = new List<_ImageListenerPair>();
_listeners = new List<ImageStreamListener>();
_listeners.Add(new _ImageListenerPair {listener = listener, errorListener = onError});
_listeners.Add(listener);
public void removeListener(ImageListener listener) {
public void removeListener(ImageStreamListener listener) {
if (_completer != null) {
_completer.removeListener(listener);
return;

for (int i = 0; i < _listeners.Count; i++) {
if (_listeners[i].listener == listener) {
if (_listeners[i] == listener) {
_listeners.RemoveAt(i);
break;
}

ifPresent: _completer?.toStringShort(),
ifNull: "unresolved"
));
properties.add(new ObjectFlagProperty<List<_ImageListenerPair>>(
properties.add(new ObjectFlagProperty<List<ImageStreamListener>>(
"listeners",
_listeners,
ifPresent: $"{_listeners?.Count} listener{(_listeners?.Count == 1 ? "" : "s")}",

}
public abstract class ImageStreamCompleter : Diagnosticable {
internal readonly List<_ImageListenerPair> _listeners = new List<_ImageListenerPair>();
public ImageInfo currentImage;
public UIWidgetsErrorDetails currentError;
internal readonly List<ImageStreamListener> _listeners = new List<ImageStreamListener>();
internal ImageInfo _currentImage;
internal UIWidgetsErrorDetails _currentError;
public virtual void addListener(ImageListener listener, ImageErrorListener onError = null) {
_listeners.Add(new _ImageListenerPair {listener = listener, errorListener = onError});
if (currentImage != null) {
public virtual void addListener(ImageStreamListener listener) {
_listeners.Add(listener);
if (_currentImage != null) {
listener(currentImage, true);
listener.onImage(_currentImage, true);
catch (Exception ex) {
catch (Exception exception) {
exception: ex
exception: exception
if (currentError != null && onError != null) {
if (_currentError != null && listener.onError != null) {
onError(currentError.exception);
listener.onError(_currentError.exception);
catch (Exception ex) {
catch (Exception exception) {
exception: ex,
exception: exception,
context: new ErrorDescription("when reporting an error to an image listener")
context: new ErrorDescription("by a synchronously-called image error listener")
)
);
}

public virtual void removeListener(ImageListener listener) {
for (int i = 0; i < _listeners.Count; i++) {
if (_listeners[i].listener == listener) {
public virtual void removeListener(ImageStreamListener listener) {
for (int i = 0; i < _listeners.Count; i += 1) {
if (_listeners[i] == listener) {
if (_listeners.isEmpty()) {
foreach (VoidCallback callback in _onLastListenerRemovedCallbacks) {
callback();
}
_onLastListenerRemovedCallbacks.Clear();
}
readonly List<VoidCallback> _onLastListenerRemovedCallbacks = new List<VoidCallback>();
public void addOnLastListenerRemovedCallback(VoidCallback callback) {
D.assert(callback != null);
_onLastListenerRemovedCallbacks.Add(callback);
}
public void removeOnLastListenerRemovedCallback(VoidCallback callback) {
D.assert(callback != null);
_onLastListenerRemovedCallbacks.Remove(callback);
}
currentImage = image;
_currentImage = image;
var localListeners = _listeners.Select(l => l.listener).ToList();
var localListeners = _listeners.Select(l => l).ToList();
listener(image, false);
listener.onImage(image, false);
}
catch (Exception ex) {
reportError(

Exception exception = null,
InformationCollector informationCollector = null,
bool silent = false) {
currentError = new UIWidgetsErrorDetails(
_currentError = new UIWidgetsErrorDetails(
exception: exception,
library: "image resource service",
context: context,

var localErrorListeners = _listeners.Select(l => l.errorListener).Where(l => l != null).ToList();
var localErrorListeners = _listeners
.Select(l => l.onError)
.Where(l => l != null)
.ToList();
UIWidgetsError.reportError(currentError);
UIWidgetsError.reportError(_currentError);
}
else {
foreach (var errorListener in localErrorListeners) {

public override void debugFillProperties(DiagnosticPropertiesBuilder description) {
base.debugFillProperties(description);
description.add(new DiagnosticsProperty<ImageInfo>(
"current", currentImage, ifNull: "unresolved", showName: false));
description.add(new ObjectFlagProperty<List<_ImageListenerPair>>(
"current", _currentImage, ifNull: "unresolved", showName: false));
description.add(new ObjectFlagProperty<List<ImageStreamListener>>(
"listeners",
_listeners,
ifPresent: $"{_listeners.Count} listener{(_listeners.Count == 1 ? "" : "s")}"

}
}
// TODO: update stream
public class MultiFrameImageStreamCompleter : ImageStreamCompleter {
public MultiFrameImageStreamCompleter(
Future<Codec> codec,

TimeSpan delay = _frameDuration.Value - (timestamp - _shownTimestamp.Value);
delay = new TimeSpan((long) (delay.Ticks * scheduler_.timeDilation));
// TODO: time dilation
_timer = Timer.create(delay , ()=> _scheduleAppFrame());
_timer = Timer.create(delay, () => _scheduleAppFrame());
}
bool _isFirstFrame() {

_framesEmitted += 1;
}
public override void addListener(ImageListener listener, ImageErrorListener onError = null) {
public override void addListener(ImageStreamListener listener) {
base.addListener(listener, onError: onError);
base.addListener(listener);
public override void removeListener(ImageListener listener) {
public override void removeListener(ImageStreamListener listener) {
base.removeListener(listener);
if (!hasListeners) {
_timer?.cancel();

15
com.unity.uiwidgets/Runtime/painting/inline_span.cs


public abstract class InlineSpan : DiagnosticableTree, IEquatable<InlineSpan> {
public InlineSpan(
TextStyle style = null
TextStyle style = null
public abstract void build(ParagraphBuilder builder,
float textScaleFactor = 1, List<PlaceholderDimensions> dimensions = null
);

public virtual string toPlainText(
bool includeSemanticsLabels = true,
bool includePlaceholders = true)
{
bool includePlaceholders = true) {
StringBuilder buffer = new StringBuilder();
computeToPlainText(buffer, includeSemanticsLabels: includeSemanticsLabels,
includePlaceholders: includePlaceholders);

public abstract void computeToPlainText(
StringBuilder buffer,
bool includeSemanticsLabels = true,
bool includeSemanticsLabels = true,
bool includePlaceholders = true);
public int? codeUnitAt(int index) {

public virtual bool debugAssertIsValid() => true;
public abstract RenderComparison compareTo(InlineSpan other);
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
public virtual void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.whitespace;
if (style != null) {

public override int GetHashCode() {
return (style != null ? style.GetHashCode() : 0);
}
public static bool operator ==(InlineSpan left, InlineSpan right) {
return Equals(left, right);
}

220
com.unity.uiwidgets/Runtime/painting/matrix_utils.cs


public static float dot(this Vector3 left, Vector3 right) {
return left.x * right.x + left.y * right.y + left.z * right.z;
}
public static Offset getAsTranslation(this Matrix4 values) {
if (values[0] == 1 && // col 1
values[1] == 0 &&

return null;
}
}
q.w = Mathf.Sqrt( Mathf.Max( 0, 1 + m.entry(0,0) + m.entry(1,1) + m.entry(2,2) ) ) / 2;
q.x = Mathf.Sqrt( Mathf.Max( 0, 1 + m.entry(0,0) - m.entry(1,1) - m.entry(2,2) ) ) / 2;
q.y = Mathf.Sqrt( Mathf.Max( 0, 1 - m.entry(0,0) + m.entry(1,1) - m.entry(2,2) ) ) / 2;
q.z = Mathf.Sqrt( Mathf.Max( 0, 1 - m.entry(0,0) - m.entry(1,1) + m.entry(2,2) ) ) / 2;
q.x *= Mathf.Sign( q.x * ( m.entry(2,1) - m.entry(1,2) ) );
q.y *= Mathf.Sign( q.y * ( m.entry(0,2) - m.entry(2,0) ) );
q.z *= Mathf.Sign( q.z * ( m.entry(1,0) - m.entry(0,1) ) );
q.w = Mathf.Sqrt(Mathf.Max(0, 1 + m.entry(0, 0) + m.entry(1, 1) + m.entry(2, 2))) / 2;
q.x = Mathf.Sqrt(Mathf.Max(0, 1 + m.entry(0, 0) - m.entry(1, 1) - m.entry(2, 2))) / 2;
q.y = Mathf.Sqrt(Mathf.Max(0, 1 - m.entry(0, 0) + m.entry(1, 1) - m.entry(2, 2))) / 2;
q.z = Mathf.Sqrt(Mathf.Max(0, 1 - m.entry(0, 0) - m.entry(1, 1) + m.entry(2, 2))) / 2;
q.x *= Mathf.Sign(q.x * (m.entry(2, 1) - m.entry(1, 2)));
q.y *= Mathf.Sign(q.y * (m.entry(0, 2) - m.entry(2, 0)));
q.z *= Mathf.Sign(q.z * (m.entry(1, 0) - m.entry(0, 1)));
}
public static Quaternion scaled(this Quaternion lhs, float scale) {

lhs.w *= scale;
return lhs;
}
public static Quaternion add(this Quaternion lhs, Quaternion rhs) {
lhs.x += rhs.x;
lhs.y += rhs.y;

return new List<string> {"null"};
}
List<string> result = new List<string>(3);
List<string> result = new List<string>(){
$"[0] ${D.debugFormatFloat(transform.entry(0, 0))},${D.debugFormatFloat(transform.entry(0, 1))},${D.debugFormatFloat(transform.entry(0, 2))},${D.debugFormatFloat(transform.entry(0, 3))}",
$"[1] ${D.debugFormatFloat(transform.entry(1, 0))},${D.debugFormatFloat(transform.entry(1, 1))},${D.debugFormatFloat(transform.entry(1, 2))},${D.debugFormatFloat(transform.entry(1, 3))}",
$"[2] ${D.debugFormatFloat(transform.entry(2, 0))},${D.debugFormatFloat(transform.entry(2, 1))},${D.debugFormatFloat(transform.entry(2, 2))},${D.debugFormatFloat(transform.entry(2, 3))}",
$"[3] ${D.debugFormatFloat(transform.entry(3, 0))},${D.debugFormatFloat(transform.entry(3, 1))},${D.debugFormatFloat(transform.entry(3, 2))},${D.debugFormatFloat(transform.entry(3, 3))}"
};
for (int i = 0; i < 3; i++) {
result.Add($"[{i}] {transform[i * 3]}, {transform[i * 3 + 1]}, {transform[i * 3 + 2]}");
}

public static Offset transformPoint(Matrix4 transform, Offset point) {
Vector3 position3 = new Vector3(point.dx, point.dy, 0);
Vector3 transformed3 = transform.perspectiveTransform(position3);
return new Offset(transformed3.x, transformed3.y);
float[] storage = transform.storage;
float x = point.dx;
float y = point.dy;
float rx = storage[0] * x + storage[4] * y + storage[12];
float ry = storage[1] * x + storage[5] * y + storage[13];
float rw = storage[3] * x + storage[7] * y + storage[15];
if (rw == 1.0f) {
return new Offset(rx, ry);
}
else {
return new Offset(rx / rw, ry / rw);
}
}
internal static Rect _safeTransformRect(Matrix4 transform, Rect rect) {
float[] storage = transform.storage;
bool isAffine = storage[3] == 0.0 &&
storage[7] == 0.0 &&
storage[15] == 1.0;
_minMax = _minMax ?? new float[4];
_accumulate(storage, rect.left, rect.top, true, isAffine);
_accumulate(storage, rect.right, rect.top, false, isAffine);
_accumulate(storage, rect.left, rect.bottom, false, isAffine);
_accumulate(storage, rect.right, rect.bottom, false, isAffine);
return Rect.fromLTRB(_minMax[0], _minMax[1], _minMax[2], _minMax[3]);
}
static float[] _minMax;
static void _accumulate(float[] m, float x, float y, bool first, bool isAffine) {
float w = isAffine ? 1.0f : 1.0f / (m[3] * x + m[7] * y + m[15]);
float tx = (m[0] * x + m[4] * y + m[12]) * w;
float ty = (m[1] * x + m[5] * y + m[13]) * w;
if (first) {
_minMax[0] = _minMax[2] = tx;
_minMax[1] = _minMax[3] = ty;
}
else {
if (tx < _minMax[0]) {
_minMax[0] = tx;
}
if (ty < _minMax[1]) {
_minMax[1] = ty;
}
if (tx > _minMax[2]) {
_minMax[2] = tx;
}
if (ty > _minMax[3]) {
_minMax[3] = ty;
}
}
Offset point1 = transformPoint(transform, rect.topLeft);
Offset point2 = transformPoint(transform, rect.topRight);
Offset point3 = transformPoint(transform, rect.bottomLeft);
Offset point4 = transformPoint(transform, rect.bottomRight);
return Rect.fromLTRB(
_min4(point1.dx, point2.dx, point3.dx, point4.dx),
_min4(point1.dy, point2.dy, point3.dy, point4.dy),
_max4(point1.dx, point2.dx, point3.dx, point4.dx),
_max4(point1.dy, point2.dy, point3.dy, point4.dy)
);
float[] storage = transform.storage;
float x = rect.left;
float y = rect.top;
float w = rect.right - x;
float h = rect.bottom - y;
if (!w.isFinite() || !h.isFinite()) {
return _safeTransformRect(transform, rect);
}
float wx = storage[0] * w;
float hx = storage[4] * h;
float rx = storage[0] * x + storage[4] * y + storage[12];
float wy = storage[1] * w;
float hy = storage[5] * h;
float ry = storage[1] * x + storage[5] * y + storage[13];
if (storage[3] == 0.0f && storage[7] == 0.0f && storage[15] == 1.0f) {
float left = rx;
float right = rx;
if (wx < 0) {
left += wx;
}
else {
right += wx;
}
if (hx < 0) {
left += hx;
}
else {
right += hx;
}
float top = ry;
float bottom = ry;
if (wy < 0) {
top += wy;
}
else {
bottom += wy;
}
if (hy < 0) {
top += hy;
}
else {
bottom += hy;
}
return Rect.fromLTRB(left, top, right, bottom);
}
else {
float ww = storage[3] * w;
float hw = storage[7] * h;
float rw = storage[3] * x + storage[7] * y + storage[15];
float ulx = rx / rw;
float uly = ry / rw;
float urx = (rx + wx) / (rw + ww);
float ury = (ry + wy) / (rw + ww);
float llx = (rx + hx) / (rw + hw);
float lly = (ry + hy) / (rw + hw);
float lrx = (rx + wx + hx) / (rw + ww + hw);
float lry = (ry + wy + hy) / (rw + ww + hw);
return Rect.fromLTRB(
_min4(ulx, urx, llx, lrx),
_min4(uly, ury, lly, lry),
_max4(ulx, urx, llx, lrx),
_max4(uly, ury, lly, lry)
);
}
}
static bool isIdentity(Matrix4 a) {

&& a[14] == 0.0
&& a[15] == 1.0;
}
public static Rect inverseTransformRect(Matrix4 transform, Rect rect) {
D.assert(rect != null);
D.assert(transform.determinant() != 0.0);

return transformRect(transform, rect);
}
return Mathf.Min(a, Mathf.Min(b, Mathf.Min(c, d)));
float e = (a < b) ? a : b;
float f = (c < d) ? c : d;
return (e < f) ? e : f;
return Mathf.Max(a, Mathf.Max(b, Mathf.Max(c, d)));
float e = (a > b) ? a : b;
float f = (c > d) ? c : d;
return (e > f) ? e : f;
}
static Matrix4 createCylindricalProjectionTransform(
float radius,
float angle,
float perspective = 0.001f,
Axis? orientation = null
) {
D.assert(perspective >= 0 && perspective <= 1.0);
if (orientation == null) {
orientation = Axis.vertical;
}
Matrix4 result = Matrix4.identity();
result.setEntry(3, 2, -perspective);
result.setEntry(2, 3, -radius);
result.setEntry(3, 3, perspective * radius + 1.0f);
result = result * ((
orientation == Axis.horizontal
? Matrix4.rotationY(angle)
: Matrix4.rotationX(angle)
) * Matrix4.translationValues(0.0f, 0.0f, radius)) as Matrix4;
return result;
}
static Matrix4 forceToPoint(Offset offset) {
var result = Matrix4.identity();
result.setRow(0, new Vector4(0, 0, 0, offset.dx));
result.setRow(1, new Vector4(0, 0, 0, offset.dy));
return result;
}
}

object defaultValue = null,
DiagnosticLevel level = DiagnosticLevel.info
) : base(name, value, showName: showName, defaultValue: defaultValue ?? foundation_.kNoDefaultValue,
level: level) { }
level: level) {
}
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) {
if (parentConfiguration != null && !parentConfiguration.lineBreakProperties) {

40
com.unity.uiwidgets/Runtime/painting/rounded_rectangle_border.cs


public readonly BorderRadius borderRadius;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get { return EdgeInsets.all(side.width); }
}

borderRadius: borderRadius * t
borderRadius: (BorderRadius) (borderRadius * t)
);
}

return base.lerpTo(b, t);
}
public override Path getInnerPath(Rect rect) {
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
path.addRRect(borderRadius.toRRect(rect).deflate(side.width));
path.addRRect(borderRadius.resolve(textDirection).toRRect(rect).deflate(side.width));
public override Path getOuterPath(Rect rect) {
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
path.addRRect(borderRadius.toRRect(rect));
path.addRRect(borderRadius.resolve(textDirection).toRRect(rect));
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
switch (side.style) {
case BorderStyle.none:
break;

canvas.drawRRect(borderRadius.toRRect(rect), side.toPaint());
canvas.drawRRect(borderRadius.resolve(textDirection).toRRect(rect), side.toPaint());
RRect outer = borderRadius.toRRect(rect);
RRect outer = borderRadius.resolve(textDirection).toRRect(rect);
RRect inner = outer.deflate(width);
Paint paint = new Paint {
color = side.color,

public readonly float circleness;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get { return EdgeInsets.all(side.width); }
}

borderRadius: borderRadius * t,
borderRadius: (BorderRadius) (borderRadius * t),
circleness: t
);
}

}
}
BorderRadius _adjustBorderRadius(Rect rect) {
BorderRadius resolvedRadius = borderRadius;
BorderRadius _adjustBorderRadius(Rect rect, TextDirection? textDirection) {
BorderRadius resolvedRadius = borderRadius.resolve(textDirection);
if (circleness == 0.0f) {
return resolvedRadius;
}

public override Path getInnerPath(Rect rect) {
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
path.addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)).deflate(side.width));
path.addRRect(_adjustBorderRadius(rect, textDirection).toRRect(_adjustRect(rect)).deflate(side.width));
public override Path getOuterPath(Rect rect) {
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
path.addRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)));
path.addRRect(_adjustBorderRadius(rect, textDirection).toRRect(_adjustRect(rect)));
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
switch (side.style) {
case BorderStyle.none:
break;

canvas.drawRRect(_adjustBorderRadius(rect).toRRect(_adjustRect(rect)),
canvas.drawRRect(_adjustBorderRadius(rect, textDirection).toRRect(_adjustRect(rect)),
RRect outer = _adjustBorderRadius(rect).toRRect(_adjustRect(rect));
RRect outer = _adjustBorderRadius(rect, textDirection).toRRect(_adjustRect(rect));
RRect inner = outer.deflate(width);
Paint paint = new Paint {
color = side.color,

9
com.unity.uiwidgets/Runtime/painting/shape_decoration.cs


public override Path getClipPath(Rect rect, TextDirection textDirection) {
return shape.getOuterPath(rect);
}
public override EdgeInsets padding {
public override EdgeInsetsGeometry padding {
get { return shape.dimensions; }
}

public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.whitespace;
properties.add(new DiagnosticsProperty<Color>("color", color,
properties.add(new ColorProperty("color", color,
defaultValue: foundation_.kNullDefaultValue));
properties.add(new DiagnosticsProperty<Gradient>("gradient", gradient,
defaultValue: foundation_.kNullDefaultValue));

D.assert(configuration != null);
D.assert(configuration.size != null);
Rect rect = offset & configuration.size;
TextDirection textDirection = configuration.textDirection;
_decoration.shape.paint(canvas, rect);
_decoration.shape.paint(canvas, rect, textDirection: textDirection);
}
}
}

31
com.unity.uiwidgets/Runtime/painting/stadium_border.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.painting {

public readonly BorderSide side;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get { return EdgeInsets.all(side.width); }
}

return base.lerpTo(b, t);
}
public override Path getInnerPath(Rect rect) {
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
Radius radius = Radius.circular(rect.shortestSide / 2.0f);
var path = new Path();
path.addRRect(RRect.fromRectAndRadius(rect, radius).deflate(side.width));

public override Path getOuterPath(Rect rect) {
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
Radius radius = Radius.circular(rect.shortestSide / 2.0f);
var path = new Path();
path.addRRect(RRect.fromRectAndRadius(rect, radius));

public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
switch (side.style) {
case BorderStyle.none:
break;

}
public override string ToString() {
return $"{GetType()}({side})";
return $"{foundation_.objectRuntimeType(this, "StadiumBorder")}({side})";
}
}

public readonly float circleness;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get { return EdgeInsets.all(side.width); }
}

return BorderRadius.circular(rect.shortestSide / 2.0f);
}
public override Path getInnerPath(Rect rect) {
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
public override Path getOuterPath(Rect rect) {
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
switch (side.style) {
case BorderStyle.none:
break;

}
public override string ToString() {
return $"StadiumBorder($side, {circleness * 100:F1}% " +
return $"StadiumBorder({side}, {circleness * 100:F1}% " +
"of the way to being a CircleBorder)";
}
}

public readonly float rectness;
public override EdgeInsets dimensions {
public override EdgeInsetsGeometry dimensions {
get { return EdgeInsets.all(side.width); }
}

borderRadius: borderRadius * t,
borderRadius: (BorderRadius) (borderRadius * t),
rectness: t
);
}

);
}
public override Path getInnerPath(Rect rect) {
public override Path getInnerPath(Rect rect, TextDirection? textDirection = null) {
public override Path getOuterPath(Rect rect) {
public override Path getOuterPath(Rect rect, TextDirection? textDirection = null) {
public override void paint(Canvas canvas, Rect rect) {
public override void paint(Canvas canvas, Rect rect, TextDirection? textDirection = null) {
switch (side.style) {
case BorderStyle.none:
break;

29
com.unity.uiwidgets/Runtime/painting/strut_style.cs


}
public override string toStringShort() {
return $"{GetType()}";
return $"{foundation_.objectRuntimeType(this, "StrutStyle")}";
debugFillProperties(properties, "");
}
public void debugFillProperties(DiagnosticPropertiesBuilder properties, string prefix = "") {
properties.add(new MessageProperty("debugLabel", debugLabel));
properties.add(new MessageProperty($"{prefix}debugLabel", debugLabel));
styles.Add(new StringProperty("family", fontFamily, defaultValue: foundation_.kNullDefaultValue,
styles.Add(new StringProperty($"{prefix}family", fontFamily, defaultValue: foundation_.kNullDefaultValue,
styles.Add(new EnumerableProperty<string>("familyFallback", fontFamilyFallback));
styles.Add(new DiagnosticsProperty<float?>("size", fontSize,
styles.Add(new EnumerableProperty<string>($"{prefix}familyFallback", fontFamilyFallback));
styles.Add(new DiagnosticsProperty<float?>($"{prefix}size", fontSize,
defaultValue: foundation_.kNullDefaultValue));
string weightDescription = "";
if (fontWeight != null) {

styles.Add(new DiagnosticsProperty<FontWeight>(
"weight", fontWeight,
$"{prefix}weight", fontWeight,
styles.Add(new EnumProperty<FontStyle?>("style", fontStyle,
styles.Add(new EnumProperty<FontStyle?>($"{prefix}style", fontStyle,
styles.Add(new DiagnosticsProperty<float?>("height", height,
defaultValue: foundation_.kNullDefaultValue));
styles.Add(new FlagProperty("forceStrutHeight", value: forceStrutHeight,
styles.Add(new DiagnosticsProperty<float?>($"{prefix}height", height,
styles.Add(new FlagProperty($"{prefix}forceStrutHeight", value: forceStrutHeight,
defaultValue: foundation_.kNullDefaultValue, ifTrue: $"{prefix}<strut height forced>",
ifFalse: $"{prefix}<strut height normal>"));
bool styleSpecified = styles.Any((DiagnosticsNode n) => !n.isFiltered(DiagnosticLevel.info));
foreach (var style in styles) {

if (!styleSpecified) {
properties.add(new FlagProperty("forceStrutHeight", value: forceStrutHeight,
ifTrue: "<strut height forced>",
ifFalse: "<strut height normal>"));
ifTrue: $"{prefix}<strut height forced>",
ifFalse: $"{prefix}<strut height normal>"));
}
}
}

31
com.unity.uiwidgets/Runtime/painting/text_painter.cs


markNeedsLayout();
}
}
get {
return _locale;
}
get { return _locale; }
set {
if (_locale == value)
return;

}
public TextWidthBasis textWidthBasis {
get { return _textWidthBasis; }
set {

_paragraph.layout(new ParagraphConstraints(newWidth));
}
}
_inlinePlaceholderBoxes = _paragraph.getBoxesForPlaceholders();
}

BoxHeightStyle boxHeightStyle = BoxHeightStyle.tight,
BoxWidthStyle boxWidthStyle = BoxWidthStyle.tight) {
D.assert(!_needsLayout);
var results = _paragraph.getBoxesForRange(selection.start, selection.end, boxHeightStyle: boxHeightStyle,
var results = _paragraph.getBoxesForRange(
selection.start,
selection.end,
boxHeightStyle: boxHeightStyle,
boxWidthStyle: boxWidthStyle);
return results;
}

D.assert(!_needsLayout);
return _paragraph.getLineBoundary(position);
}
List<ui.LineMetrics> computeLineMetrics() {
D.assert(!_needsLayout);
return _paragraph.computeLineMetrics();
}
ParagraphStyle _createParagraphStyle(TextDirection defaultTextDirection = TextDirection.ltr) {
D.assert(textAlign != null);

textDirection: textDirection ?? defaultTextDirection,
textScaleFactor: textScaleFactor,
maxLines: _maxLines,
// textHeightBehavior: _textHeightBehavior,
ellipsis: _ellipsis
// locale: _locale,
// strutStyle: _strutStyle,
textHeightBehavior: _textHeightBehavior,
ellipsis: _ellipsis,
locale: _locale,
strutStyle: _strutStyle
ellipsis: ellipsis
// locale: locale,
ellipsis: ellipsis,
locale: locale
);
}

2
com.unity.uiwidgets/Runtime/painting/text_span.cs


}
public override string toStringShort() {
return GetType().ToString();
return foundation_.objectRuntimeType(this, "TextSpan");
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {

165
com.unity.uiwidgets/Runtime/painting/text_style.cs


}
public RenderComparison compareTo(TextStyle other) {
if (inherit != other.inherit || fontFamily != other.fontFamily ||
fontSize != other.fontSize || fontWeight != other.fontWeight ||
fontStyle != other.fontStyle || letterSpacing != other.letterSpacing ||
wordSpacing != other.wordSpacing || textBaseline != other.textBaseline ||
height != other.height || background != other.background ||
shadows.equalsList(other.shadows) || fontFeatures.equalsList(other.fontFeatures)) {
if (ReferenceEquals(this, other))
return RenderComparison.identical;
if (inherit != other.inherit ||
fontFamily != other.fontFamily ||
fontSize != other.fontSize ||
fontWeight != other.fontWeight ||
fontStyle != other.fontStyle ||
letterSpacing != other.letterSpacing ||
wordSpacing != other.wordSpacing ||
textBaseline != other.textBaseline ||
height != other.height ||
foreground != other.foreground ||
background != other.background ||
!shadows.equalsList(other.shadows) ||
!fontFeatures.equalsList(other.fontFeatures) ||
!fontFamilyFallback.equalsList(other.fontFamilyFallback)) {
if (color != other.color || decoration != other.decoration ||
if (color != other.color ||
backgroundColor != other.backgroundColor ||
decoration != other.decoration ||
decorationColor != other.decorationColor ||
decorationStyle != other.decorationStyle) {
return RenderComparison.paint;

}
public ParagraphStyle getParagraphStyle(TextAlign textAlign,
TextDirection textDirection, string ellipsis, int? maxLines,
public ParagraphStyle getParagraphStyle(
TextAlign textAlign,
TextDirection textDirection,
float? textScaleFactor = 1.0f,
string ellipsis = null,
int? maxLines = null,
float textScaleFactor = 1.0f) {
return new ParagraphStyle(
Locale locale = null,
String fontFamily = null,
float? fontSize = null,
FontWeight fontWeight = null,
FontStyle? fontStyle = null,
float? height = null,
StrutStyle strutStyle = null
) {
D.assert(textScaleFactor != null);
D.assert(maxLines == null || maxLines > 0);
return new ui.ParagraphStyle(
fontWeight: fontWeight,
fontStyle: fontStyle,
maxLines: maxLines,
fontSize: (fontSize ?? _defaultFontSize) * textScaleFactor,
fontFamily: fontFamily,
height: height,
fontWeight: fontWeight ?? this.fontWeight,
fontStyle: fontStyle ?? this.fontStyle,
fontFamily: fontFamily ?? this.fontFamily,
fontSize: (fontSize ?? this.fontSize ?? _defaultFontSize) * textScaleFactor,
height: height ?? this.height,
ellipsis: ellipsis
strutStyle: strutStyle == null
? null
: new ui.StrutStyle(
fontFamily: strutStyle.fontFamily,
fontFamilyFallback: strutStyle.fontFamilyFallback,
fontSize: strutStyle.fontSize == null ? null : strutStyle.fontSize * textScaleFactor,
height: strutStyle.height,
leading: strutStyle.leading,
fontWeight: strutStyle.fontWeight,
fontStyle: strutStyle.fontStyle,
forceStrutHeight: strutStyle.forceStrutHeight
),
maxLines: maxLines,
ellipsis: ellipsis,
locale: locale
);
}

decorationThickness: decorationThickness == null
? null
: decorationThickness * decorationThicknessFactor + decorationThicknessDelta,
shadows: shadows ?? this.shadows,
shadows: shadows ?? this.shadows,
fontFeatures: fontFeatures,
debugLabel: modifiedDebugLabel
);

);
}
ui.ParagraphStyle getParagraphStyle(
TextAlign? textAlign = null,
TextDirection? textDirection = null,
float textScaleFactor = 1.0f,
String ellipsis = null,
int? maxLines = null,
ui.TextHeightBehavior textHeightBehavior = null,
Locale locale = null,
String fontFamily = null,
float? fontSize = null,
FontWeight fontWeight = null,
FontStyle? fontStyle = null,
float? height = null,
StrutStyle strutStyle = null
) {
D.assert(maxLines == null || maxLines > 0);
return new ui.ParagraphStyle(
textAlign: textAlign,
textDirection: textDirection,
fontWeight: fontWeight ?? this.fontWeight,
fontStyle: fontStyle ?? this.fontStyle,
fontFamily: fontFamily ?? this.fontFamily,
fontSize: (fontSize ?? this.fontSize ?? _defaultFontSize) * textScaleFactor,
height: height ?? this.height,
textHeightBehavior: textHeightBehavior,
strutStyle: strutStyle == null
? null
: new ui.StrutStyle(
fontFamily: strutStyle.fontFamily,
fontFamilyFallback: strutStyle.fontFamilyFallback,
fontSize: strutStyle.fontSize == null ? null : strutStyle.fontSize * textScaleFactor,
height: strutStyle.height,
leading: strutStyle.leading,
fontWeight: strutStyle.fontWeight,
fontStyle: strutStyle.fontStyle,
forceStrutHeight: strutStyle.forceStrutHeight
),
maxLines: maxLines,
ellipsis: ellipsis,
locale: locale
);
}
public ui.TextStyle getTextStyle(float textScaleFactor = 1.0f) {
var backgroundPaint = new Paint();
if (background != null) {

);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
debugFillProperties(properties, "");
}
public void debugFillProperties(DiagnosticPropertiesBuilder properties, string prefix = "") {
styles.Add(new DiagnosticsProperty<Color>("color", color,
styles.Add(new ColorProperty($"{prefix}color", color,
styles.Add(new DiagnosticsProperty<Color>("backgroundColor", backgroundColor,
styles.Add(new ColorProperty($"{prefix}backgroundColor", backgroundColor,
styles.Add(new StringProperty("family", fontFamily, defaultValue: foundation_.kNullDefaultValue,
styles.Add(new StringProperty($"{prefix}family", fontFamily, defaultValue: foundation_.kNullDefaultValue,
styles.Add(new EnumerableProperty<string>("familyFallback", fontFamilyFallback,
styles.Add(new EnumerableProperty<string>($"{prefix}familyFallback", fontFamilyFallback,
styles.Add(new DiagnosticsProperty<float?>("size", fontSize,
styles.Add(new DiagnosticsProperty<float?>($"{prefix}size", fontSize,
defaultValue: foundation_.kNullDefaultValue));
string weightDescription = "";
if (fontWeight != null) {

description: weightDescription,
defaultValue: foundation_.kNullDefaultValue
));
styles.Add(new EnumProperty<FontStyle?>("style", fontStyle,
styles.Add(new EnumProperty<FontStyle?>($"{prefix}style", fontStyle,
styles.Add(new DiagnosticsProperty<float?>("letterSpacing", letterSpacing,
styles.Add(new DiagnosticsProperty<float?>($"{prefix}letterSpacing", letterSpacing,
styles.Add(new DiagnosticsProperty<float?>("wordSpacing", wordSpacing,
styles.Add(new DiagnosticsProperty<float?>($"{prefix}wordSpacing", wordSpacing,
styles.Add(new EnumProperty<TextBaseline?>("baseline", textBaseline,
styles.Add(new EnumProperty<TextBaseline?>($"{prefix}baseline", textBaseline,
styles.Add(new DiagnosticsProperty<float?>("height", height,
styles.Add(new DiagnosticsProperty<float?>($"{prefix}height", height,
styles.Add(new StringProperty("foreground", foreground == null ? null : foreground.ToString(),
styles.Add(new StringProperty($"{prefix}foreground", foreground == null ? null : foreground.ToString(),
styles.Add(new StringProperty("background", background == null ? null : background.ToString(),
styles.Add(new StringProperty($"{prefix}background", background == null ? null : background.ToString(),
defaultValue: foundation_.kNullDefaultValue, quoted: false));
if (decoration != null) {
List<string> decorationDescription = new List<string>();

styles.Add(new DiagnosticsProperty<Color>("decorationColor", decorationColor,
styles.Add(new ColorProperty($"{prefix}decorationColor", decorationColor,
defaultValue: foundation_.kNullDefaultValue,
level: DiagnosticLevel.fine));
if (decorationColor != null) {

styles.Add(new DiagnosticsProperty<TextDecoration>("decoration", decoration,
styles.Add(new DiagnosticsProperty<TextDecoration>($"{prefix}decoration", decoration,
decorationDescription.Add("$decoration");
decorationDescription.Add($"{decoration}");
styles.Add(new MessageProperty("decoration", string.Join(" ", decorationDescription.ToArray())));
styles.Add(new FloatProperty("decorationThickness", decorationThickness, unit: "x",
styles.Add(new MessageProperty($"{prefix}decoration", string.Join(" ", decorationDescription.ToArray())));
styles.Add(new FloatProperty($"{prefix}decorationThickness", decorationThickness, unit: "x",
defaultValue: foundation_.kNoDefaultValue));
}

}
if (!styleSpecified) {
properties.add(new FlagProperty("inherit", value: inherit, ifTrue: "<all styles inherited>",
ifFalse: "<no style specified>"));
properties.add(new FlagProperty("inherit", value: inherit, ifTrue: $"{prefix}<all styles inherited>",
ifFalse: $"{prefix}<no style specified>"));
}
}

Equals(background, other.background) &&
fontFamilyFallback.equalsList(other.fontFamilyFallback) &&
shadows.equalsList(other.shadows) &&
fontFeatures.equalsList(other.fontFeatures) &&
fontFeatures.equalsList(other.fontFeatures) &&
string.Equals(fontFamily, other.fontFamily);
}

8
com.unity.uiwidgets/Runtime/rendering/binding.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.scheduler2;
public class RendererBinding : PaintingBinding {
public class RendererBinding : SchedulerBinding {
get { return (RendererBinding) PaintingBinding.instance; }
set { PaintingBinding.instance = value; }
get { return (RendererBinding) SchedulerBinding.instance; }
set { Window.instance._binding = value; }
}
protected override void initInstances() {

2
com.unity.uiwidgets/Runtime/rendering/image.cs


return;
}
ImageUtils.paintImage(
painting_.paintImage(
canvas: context.canvas,
rect: offset & size,
image: _image,

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


using Unity.UIWidgets.async;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using UnityEditor.PackageManager;
using UnityEngine;
using FrameTiming = Unity.UIWidgets.ui.FrameTiming;
using Timer = Unity.UIWidgets.async2.Timer;

postFrameCallbacks,
}
public class SchedulerBinding : BindingBase {
public class SchedulerBinding : PaintingBinding {
protected override void initInstances() {
base.initInstances();
instance = this;

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


using System.Collections.Generic;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
public class ServicesBinding : BindingBase {
public class ServicesBinding : GestureBinding {
protected override void initInstances() {
base.initInstances();
instance = this;

1
com.unity.uiwidgets/Runtime/widgets/binding.cs


using System.Collections.Generic;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using UnityEngine;

5
com.unity.uiwidgets/Runtime/widgets/container.cs


using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace Unity.UIWidgets.widgets {
public class DecoratedBox : SingleChildRenderObjectWidget {

return padding;
}
EdgeInsets decorationPadding = decoration.padding;
Debug.LogError("EdgeInsets needs to be update to EdgeInsetsGeometry");
EdgeInsets decorationPadding = (EdgeInsets)decoration.padding;
if (padding == null) {
return decorationPadding;
}

11
com.unity.uiwidgets/Runtime/widgets/debug.cs


return true;
}
/*static int debugDoublePrecision;
public static string debugFormatDouble(float value) {
if (value == null) {
return "null";
}
if (debugDoublePrecision != null) {
return value.toStringAsPrecision(debugDoublePrecision);
}
return value.toStringAsFixed(1);
}*/
internal static UIWidgetsErrorDetails _debugReportException(
string context,
Exception exception,

13
com.unity.uiwidgets/Runtime/widgets/fade_in_image.cs


_imageStream = provider.resolve(ImageUtils.createLocalImageConfiguration(state.context, size));
D.assert(_imageStream != null);
if (_imageStream.key != oldImageStream?.key) {
oldImageStream?.removeListener(_handleImageChanged);
_imageStream.addListener(_handleImageChanged);
}
// TODO: update
// if (_imageStream.key != oldImageStream?.key) {
// oldImageStream?.removeListener(_handleImageChanged);
// _imageStream.addListener(_handleImageChanged);
// }
}
void _handleImageChanged(ImageInfo imageInfo, bool synchronousCall) {

public void stopListening() {
_imageStream?.removeListener(_handleImageChanged);
// TODO: update
// _imageStream?.removeListener(_handleImageChanged);
}
}

41
com.unity.uiwidgets/Runtime/widgets/image.cs


ImageStream stream = provider.resolve(config);
void listener(ImageInfo image, bool sync) {
if (!completer.isCompleted) {
stream.removeListener(listener);
}
SchedulerBinding.instance.addPostFrameCallback(timeStamp => { stream.removeListener(listener); });
// TODO: update
// if (!completer.isCompleted) {
// stream.removeListener(listener);
// }
//
// SchedulerBinding.instance.addPostFrameCallback(timeStamp => { stream.removeListener(listener); });
}
void errorListener(Exception exception) {

stream.removeListener(listener);
// TODO: update
// stream.removeListener(listener);
if (onError != null) {
onError(exception);
}

}
}
stream.addListener(listener, onError: errorListener);
// TODO: update
// stream.addListener(listener, onError: errorListener);
return completer.future;
}
}

return;
}
if (_isListeningToStream) {
_imageStream.removeListener(_handleImageChanged);
}
// TODO: update
// if (_isListeningToStream) {
// _imageStream.removeListener(_handleImageChanged);
// }
_imageStream = newStream;
if (_isListeningToStream) {
_imageStream.addListener(_handleImageChanged);
}
// TODO: update
// _imageStream = newStream;
// if (_isListeningToStream) {
// _imageStream.addListener(_handleImageChanged);
// }
}
void _listenToStream() {

_imageStream.addListener(_handleImageChanged);
_isListeningToStream = true;
// TODO: update
// _imageStream.addListener(_handleImageChanged);
// _isListeningToStream = true;
}
void _stopListeningToStream() {

_imageStream.removeListener(_handleImageChanged);
// TODO: update
// _imageStream.removeListener(_handleImageChanged);
_isListeningToStream = false;
}

3
engine/.gitignore


artifacts
build
obj
*.gen.*
*.gen.*
third_party/skia

13
com.unity.uiwidgets/Runtime/painting/image_decoder.cs


using Unity.UIWidgets.async2;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.painting {
public partial class painting_ {
public static Future<ui.Image> decodeImageFromList(byte[] bytes) {
Future<Codec> codec = PaintingBinding.instance.instantiateImageCodec(bytes);
Future<FrameInfo> frameInfo = codec.then_<FrameInfo>(code => code.getNextFrame());
var result = frameInfo.then_<Image>(frame => FutureOr.value(frame.image));
return result;
}
}
}

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


fileFormatVersion: 2
guid: 8e4fc5e77c5b4ce3b8cdc8644ac3f398
timeCreated: 1610527018
正在加载...
取消
保存