浏览代码

fix mesh leak.

fix matrix transform.
cache font
cache bezier tessellation.
/main
kg 6 年前
当前提交
9b669ea8
共有 31 个文件被更改,包括 667 次插入365 次删除
  1. 4
      Runtime/editor/rasterizer.cs
  2. 27
      Runtime/editor/surface.cs
  3. 4
      Runtime/flow/compositor_context.cs
  4. 12
      Runtime/flow/picture_layer.cs
  5. 27
      Runtime/flow/raster_cache.cs
  6. 4
      Runtime/rendering/box.cs
  7. 12
      Runtime/rendering/layer.cs
  8. 9
      Runtime/rendering/object.cs
  9. 25
      Runtime/rendering/proxy_box.cs
  10. 2
      Runtime/rendering/proxy_box.mixin.gen.cs
  11. 2
      Runtime/rendering/proxy_box.mixin.njk
  12. 16
      Runtime/rendering/sliver.cs
  13. 4
      Runtime/rendering/sliver_multi_box_adaptor.cs
  14. 4
      Runtime/rendering/sliver_padding.cs
  15. 6
      Runtime/rendering/view.cs
  16. 10
      Runtime/rendering/viewport.cs
  17. 14
      Runtime/ui/matrix.cs
  18. 12
      Runtime/ui/painting/canvas_clip.cs
  19. 136
      Runtime/ui/painting/canvas_impl.cs
  20. 22
      Runtime/ui/painting/painting.cs
  21. 259
      Runtime/ui/painting/path.cs
  22. 6
      Runtime/ui/painting/picture.cs
  23. 14
      Runtime/ui/painting/txt/font_manager.cs
  24. 82
      Runtime/ui/painting/txt/mesh_generator.cs
  25. 5
      Runtime/widgets/binding.cs
  26. 2
      Runtime/widgets/scroll_position_with_single_context.cs
  27. 4
      Runtime/widgets/widget_inspector.cs
  28. 24
      Tests/Editor/CanvasAndLayers.cs
  29. 35
      Tests/Editor/Widgets.cs
  30. 238
      Runtime/ui/painting/tessellation_generator.cs
  31. 11
      Runtime/ui/painting/tessellation_generator.cs.meta

4
Runtime/editor/rasterizer.cs


public void setup(Surface surface) {
this._surface = surface;
this._compositorContext.onGrContextCreated();
this._compositorContext.onGrContextCreated(this._surface);
}
public void teardown() {

var canvas = frame.getCanvas();
using (var compositorFrame = this._compositorContext.acquireFrame(canvas)) {
if (compositorFrame != null && compositorFrame.raster(layerTree, false)) {
if (compositorFrame != null && compositorFrame.raster(layerTree, true)) {
frame.submit();
this._fireNextFrameCallbackIfPresent();
return true;

27
Runtime/editor/surface.cs


public interface Surface : IDisposable {
SurfaceFrame acquireFrame(Size size, double devicePixelRatio);
MeshPool getMeshPool();
}
public class EditorWindowSurface : Surface {

GrSurface _surface;
DrawToTargetFunc _drawToTargetFunc;
readonly DrawToTargetFunc _drawToTargetFunc;
MeshPool _meshPool = new MeshPool();
public EditorWindowSurface(DrawToTargetFunc drawToTargetFunc = null) {
this._drawToTargetFunc = drawToTargetFunc;

(frame, canvas) => this._presentSurface(canvas));
}
public MeshPool getMeshPool() {
return this._meshPool;
}
}
if (this._meshPool != null) {
this._meshPool.Dispose();
this._meshPool = null;
}
}

this._surface = null;
}
this._surface = new GrSurface(size, devicePixelRatio);
this._surface = new GrSurface(size, devicePixelRatio, this._meshPool);
}
}

public readonly double devicePixelRatio;
readonly MeshPool _meshPool;
Canvas _canvas;
CommandBufferCanvas _canvas;
public RenderTexture getRenderTexture() {
return this._renderTexture;

if (this._canvas == null) {
this._canvas = new CommandBufferCanvas(this._renderTexture, (float) this.devicePixelRatio);
this._canvas = new CommandBufferCanvas(
this._renderTexture, (float) this.devicePixelRatio, this._meshPool);
public GrSurface(Size size, double devicePixelRatio) {
public GrSurface(Size size, double devicePixelRatio, MeshPool meshPool) {
this.size = size;
this.devicePixelRatio = devicePixelRatio;

this._renderTexture = new RenderTexture(desc);
this._renderTexture.hideFlags = HideFlags.HideAndDontSave;
this._meshPool = meshPool;
}
public void Dispose() {

4
Runtime/flow/compositor_context.cs


using System;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.flow {

return new ScopedFrame(this, canvas);
}
public void onGrContextCreated() {
public void onGrContextCreated(Surface surface) {
this._rasterCache.meshPool = surface.getMeshPool();
}
public void onGrContextDestroyed() {

12
Runtime/flow/picture_layer.cs


public override void preroll(PrerollContext context, Matrix3 matrix) {
if (context.rasterCache != null) {
Matrix3 ctm = Matrix3.makeTrans((float) this._offset.dx, (float) this._offset.dy);
ctm.preConcat(matrix);
ctm[6] = ctm[6].alignToPixel(context.devicePixelRatio);
ctm[7] = ctm[7].alignToPixel(context.devicePixelRatio);
Matrix3 ctm = new Matrix3(matrix);
ctm.postTranslate((float) this._offset.dx, (float) this._offset.dy);
ctm[2] = ctm[2].alignToPixel(context.devicePixelRatio);
ctm[5] = ctm[5].alignToPixel(context.devicePixelRatio);
this._rasterCacheResult = context.rasterCache.getPrerolledImage(
this._picture, ctm, context.devicePixelRatio, this._isComplex, this._willChange);

// align to pixel
var matrix = canvas.getTotalMatrix();
var devicePixelRatio = context.canvas.getDevicePixelRatio();
matrix[6] = matrix[6].alignToPixel(devicePixelRatio);
matrix[7] = matrix[7].alignToPixel(devicePixelRatio);
matrix[2] = matrix[2].alignToPixel(devicePixelRatio);
matrix[5] = matrix[5].alignToPixel(devicePixelRatio);
canvas.setMatrix(matrix);
try {

27
Runtime/flow/raster_cache.cs


D.assert(matrix != null);
this.picture = picture;
this.matrix = new Matrix3(matrix);
var x = this.matrix[6] * devicePixelRatio;
var y = this.matrix[7] * devicePixelRatio;
var x = this.matrix[2] * devicePixelRatio;
var y = this.matrix[5] * devicePixelRatio;
this.matrix[6] = (x - (int) x) / devicePixelRatio; // x
this.matrix[7] = (y - (int) y) / devicePixelRatio; // y
D.assert(this.matrix[6] == 0);
D.assert(this.matrix[7] == 0);
this.matrix[2] = (x - (int) x) / devicePixelRatio; // x
this.matrix[5] = (y - (int) y) / devicePixelRatio; // y
D.assert(this.matrix[2] == 0);
D.assert(this.matrix[5] == 0);
this.devicePixelRatio = devicePixelRatio;
}

readonly Dictionary<_RasterCacheKey, _RasterCacheEntry> _cache;
MeshPool _meshPool;
public MeshPool meshPool {
set { this._meshPool = value; }
}
public RasterCacheResult getPrerolledImage(
Picture picture, Matrix3 transform, float devicePixelRatio, bool isComplex, bool willChange) {
if (this.threshold == 0) {

}
if (entry.image == null) {
entry.image = this._rasterizePicture(picture, transform, devicePixelRatio);
D.assert(this._meshPool != null);
entry.image = this._rasterizePicture(picture, transform, devicePixelRatio, this._meshPool);
}
return entry.image;

return true;
}
RasterCacheResult _rasterizePicture(Picture picture, Matrix3 transform, float devicePixelRatio) {
RasterCacheResult _rasterizePicture(Picture picture, Matrix3 transform, float devicePixelRatio, MeshPool meshPool) {
var bounds = transform.mapRect(picture.paintBounds);
var desc = new RenderTextureDescriptor(

var renderTexture = new RenderTexture(desc);
renderTexture.hideFlags = HideFlags.HideAndDontSave;
var canvas = new CommandBufferCanvas(renderTexture, devicePixelRatio);
var canvas = new CommandBufferCanvas(renderTexture, devicePixelRatio, meshPool);
return new RasterCacheResult(new Image(renderTexture), bounds, devicePixelRatio);
return new RasterCacheResult(new Image(renderTexture), picture.paintBounds, devicePixelRatio);
}
public void sweepAfterFrame() {

4
Runtime/rendering/box.cs


return false;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
D.assert(child != null);
D.assert(child.parent == this);
D.assert(() => {

var childParentData = (BoxParentData) child.parentData;
var offset = childParentData.offset;
transform = Matrix3.makeTrans(offset) * transform;
transform.preTranslate((float) offset.dx, (float) offset.dy);
}
public Offset globalToLocal(Offset point, RenderObject ancestor = null) {

12
Runtime/rendering/layer.cs


}
}
public virtual void applyTransform(Layer child, ref Matrix3 transform) {
public virtual void applyTransform(Layer child, Matrix3 transform) {
D.assert(child != null);
}

Matrix3 _lastEffectiveTransform;
public override void addToScene(SceneBuilder builder, Offset layerOffset) {
this._lastEffectiveTransform = this.transform;
this._lastEffectiveTransform = this._transform;
this._lastEffectiveTransform =
Matrix3.makeTrans(totalOffset) * this._lastEffectiveTransform;
this._lastEffectiveTransform = Matrix3.makeTrans((float) totalOffset.dx, (float) totalOffset.dy);
this._lastEffectiveTransform.preConcat(this._transform);
}
builder.pushTransform(this._lastEffectiveTransform);

public override void applyTransform(Layer child, ref Matrix3 transform) {
public override void applyTransform(Layer child, Matrix3 transform) {
transform = transform * this._lastEffectiveTransform;
transform.preConcat(this._lastEffectiveTransform);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {

9
Runtime/rendering/object.cs


public void pushTransform(bool needsCompositing, Offset offset, Matrix3 transform,
PaintingContextCallback painter) {
var effectiveTransform = Matrix3.makeTrans(offset)
* transform * Matrix3.makeTrans(-offset);
var effectiveTransform = Matrix3.makeTrans((float) offset.dx, (float) offset.dy);
effectiveTransform.preConcat(transform);
effectiveTransform.preTranslate((float) -offset.dx, (float) -offset.dy);
if (needsCompositing) {
var inverse = Matrix3.I();

public virtual void paint(PaintingContext context, Offset offset) {
}
public virtual void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public virtual void applyPaintTransform(RenderObject child, Matrix3 transform) {
D.assert(child.parent == this);
}

var transform = Matrix3.I();
for (int index = renderers.Count - 1; index > 0; index -= 1) {
renderers[index].applyPaintTransform(renderers[index - 1], ref transform);
renderers[index].applyPaintTransform(renderers[index - 1], transform);
}
return transform;
}

25
Runtime/rendering/proxy_box.cs


}
public void rotateZ(double degrees) {
this._transform = Matrix3.makeRotate((float) degrees) * this._transform;
this._transform.preRotate((float)degrees);
this._transform = Matrix3.makeTrans((float) x, (float) y) * this._transform;
this._transform.preTranslate((float) x, (float) y);
this._transform = Matrix3.makeScale((float) x, (float) y) * this._transform;
this._transform.preScale((float) x, (float) y);
this.markNeedsPaint();
}

var result = Matrix3.I();
if (this._origin != null) {
result = Matrix3.makeTrans((float) this._origin.dx, (float) this._origin.dy) *
result;
result.preTranslate((float) this._origin.dx, (float) this._origin.dy);
translation = resolvedAlignment.alongSize(this.size);
result = Matrix3.makeTrans((float) translation.dx, (float) translation.dy) * result;
translation = resolvedAlignment.alongSize(this.size);
result.preTranslate((float) translation.dx, (float) translation.dy);
result = this._transform * result;
result.preConcat(this._transform);
result = Matrix3.makeTrans((float) -translation.dx, (float) -translation.dy) *
result;
result.preTranslate((float) -translation.dx, (float) -translation.dy);
result = Matrix3.makeTrans((float) -this._origin.dx, (float) -this._origin.dy) *
result;
result.preTranslate((float) -this._origin.dx, (float) -this._origin.dy);
}
return result;

}
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
transform = this._effectiveTransform * transform;
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
transform.preConcat(this._effectiveTransform);
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {

2
Runtime/rendering/proxy_box.mixin.gen.cs


return false;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
}
public override void paint(PaintingContext context, Offset offset) {

2
Runtime/rendering/proxy_box.mixin.njk


return false;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
}
public override void paint(PaintingContext context, Offset offset) {

16
Runtime/rendering/sliver.cs


public class SliverPhysicalParentData : ParentData {
public Offset paintOffset = Offset.zero;
public void applyPaintTransform(ref Matrix3 transform) {
transform = Matrix3.makeTrans(this.paintOffset) * transform;
public void applyPaintTransform(Matrix3 transform) {
transform.preTranslate((float) this.paintOffset.dx, (float) this.paintOffset.dy);
}
public override string ToString() {

return 0.0;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
D.assert(() => { throw new UIWidgetsError(this.GetType() + " does not implement applyPaintTransform."); });
}

}
public static void applyPaintTransformForBoxChild(this RenderSliver it, RenderBox child,
ref Matrix3 transform) {
Matrix3 transform) {
bool rightWayUp = _getRightWayUp(it.constraints);
double delta = it.childMainAxisPosition(child);
double crossAxisDelta = it.childCrossAxisPosition(child);

delta = it.geometry.paintExtent - child.size.width - delta;
}
transform = Matrix3.makeTrans((float) delta, (float) crossAxisDelta) * transform;
transform.preTranslate((float) delta, (float) crossAxisDelta);
break;
case Axis.vertical:
if (!rightWayUp) {

transform = Matrix3.makeTrans((float) crossAxisDelta, (float) delta) * transform;
transform.preTranslate((float) crossAxisDelta, (float) delta);
break;
}
}

return -this.constraints.scrollOffset;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
childParentData.applyPaintTransform(ref transform);
childParentData.applyPaintTransform(transform);
}
public override void paint(PaintingContext context, Offset offset) {

4
Runtime/rendering/sliver_multi_box_adaptor.cs


return childParentData.layoutOffset;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
this.applyPaintTransformForBoxChild((RenderBox) child, ref transform);
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
this.applyPaintTransformForBoxChild((RenderBox) child, transform);
}
public override void paint(PaintingContext context, Offset offset) {

4
Runtime/rendering/sliver_padding.cs


return this.beforePadding;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
childParentData.applyPaintTransform(ref transform);
childParentData.applyPaintTransform(transform);
}
public override void paint(PaintingContext context, Offset offset) {

6
Runtime/rendering/view.cs


}
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
transform *= this._rootTransform;
base.applyPaintTransform(child, ref transform);
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
transform.preConcat(this._rootTransform);
base.applyPaintTransform(child, transform);
}
public void compositeFrame() {

10
Runtime/rendering/viewport.cs


double offsetDifference = this.offset.pixels - targetOffset;
transform = target.getTransformTo(this);
this.applyPaintTransform(child, ref transform);
this.applyPaintTransform(child, transform);
Rect targetRect = transform.mapRect(rect);
switch (this.axisDirection) {

return 0.0;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
childParentData.applyPaintTransform(ref transform);
childParentData.applyPaintTransform(transform);
}
protected override double computeChildMainAxisPosition(RenderSliver child, double parentMainAxisPosition) {

return pinnedExtent;
}
public override void applyPaintTransform(RenderObject child, ref Matrix3 transform) {
public override void applyPaintTransform(RenderObject child, Matrix3 transform) {
transform = Matrix3.makeTrans(offset) * transform;
transform.preTranslate((float) offset.dx, (float) offset.dy);
}
protected override double computeChildMainAxisPosition(RenderSliver child, double parentMainAxisPosition) {

14
Runtime/ui/matrix.cs


return m;
}
public static Matrix3 makeRotate(float degree, float px, float py) {
var m = new Matrix3();
m.setRotate(degree, px, py);
return m;
}
public static Matrix3 makeTrans(Offset offset) {
var m = new Matrix3();
m.setTranslate((float) offset.dx, (float) offset.dy);

for (int i = 1; i < 4; ++i) {
minX = Math.Min(minX, points[i].dx);
minY = Math.Min(minY, points[i].dy);
maxX = Math.Min(maxX, points[i].dx);
maxY = Math.Min(maxY, points[i].dy);
maxX = Math.Max(maxX, points[i].dx);
maxY = Math.Max(maxY, points[i].dy);
}
dst = Rect.fromLTRB(minX, minY, maxX, maxY);

return hash;
}
}
public static Matrix3 operator *(Matrix3 a, Matrix3 b) {
return concat(a, b);
}
public override string ToString() {

12
Runtime/ui/painting/canvas_clip.cs


namespace Unity.UIWidgets.ui {
class ClipElement {
public readonly int saveCount;
public readonly Mesh mesh;
public readonly MeshMesh mesh;
public readonly bool convex;
public readonly bool isRect;
public Rect rect { get; private set; }

this.mesh = pathCache.getFillMesh(out this.convex);
var vertices = this.mesh.vertices;
if (this.convex && vertices.Length == 4 &&
if (this.convex && vertices.Count == 4 &&
(Mathf.Abs(vertices[0].x - vertices[1].x) < 1e-6 && Mathf.Abs(vertices[1].y - vertices[2].y) < 1e-6 &&
Mathf.Abs(vertices[2].x - vertices[3].x) < 1e-6 && Mathf.Abs(vertices[3].y - vertices[0].y) < 1e-6 ||
Mathf.Abs(vertices[0].y - vertices[1].y) < 1e-6 && Mathf.Abs(vertices[1].x - vertices[2].x) < 1e-6 &&

this._isIntersectionOfRects = true;
}
} else {
this._bound = this.mesh.getBounds();
this._bound = this.mesh.bounds;
}
if (prior != null) {

}
bool _convexContains(float x, float y) {
if (this.mesh.vertexCount <= 2) {
if (this.mesh.vertices.Count <= 2) {
for (var i = 0; i < this.mesh.vertexCount; i++) {
for (var i = 0; i < this.mesh.vertices.Count; i++) {
var p1 = this.mesh.vertices[i == this.mesh.vertexCount - 1 ? 0 : i + 1];
var p1 = this.mesh.vertices[i == this.mesh.vertices.Count - 1 ? 0 : i + 1];
if (PathUtils.triarea2(p0.x, p0.y, p1.x, p1.y, x, y) < 0.0f) {
return false;

136
Runtime/ui/painting/canvas_impl.cs


readonly RenderTexture _renderTexture;
readonly float _fringeWidth;
readonly float _devicePixelRatio;
readonly MeshPool _meshPool;
static readonly List<int> _imageTriangles = new List<int>(12) {
0, 1, 2, 0, 2, 1,
0, 2, 3, 0, 3, 2,
};
static readonly List<int> _imageNineTriangles = new List<int>(12 * 9) {
0, 4, 1, 1, 4, 5,
0, 1, 4, 1, 5, 4,
1, 5, 2, 2, 5, 6,
1, 2, 5, 2, 6, 5,
2, 6, 3, 3, 6, 7,
2, 3, 6, 3, 7, 6,
4, 8, 5, 5, 8, 9,
4, 5, 8, 5, 9, 8,
5, 9, 6, 6, 9, 10,
5, 6, 9, 6, 10, 9,
6, 10, 7, 7, 10, 11,
6, 7, 10, 7, 11, 10,
8, 12, 9, 9, 12, 13,
8, 9, 12, 9, 13, 12,
9, 13, 10, 10, 13, 14,
9, 10, 13, 10, 14, 13,
10, 14, 11, 11, 14, 15,
10, 11, 14, 11, 15, 14,
};
public CommandBufferCanvas(RenderTexture renderTexture, float devicePixelRatio) {
public CommandBufferCanvas(RenderTexture renderTexture, float devicePixelRatio, MeshPool meshPool) {
this._meshPool = meshPool;
this.reset();
}

(float) bounds.right, (float) bounds.top);
vertices.Add(new Vector2(x, y));
uv.Add(new Vector2(uvx1, uvy0));
var mesh = new Mesh();
mesh.SetVertices(vertices);
mesh.SetUVs(0, uv);
mesh.SetIndices(new[] {
0, 1, 2, 0, 2, 1,
0, 2, 3, 0, 3, 2,
}, MeshTopology.Triangles, 0);
var mesh = new MeshMesh(vertices, _imageTriangles, uv);
if (!this._applyClip(mesh.getBounds())) {
if (!this._applyClip(mesh.bounds)) {
return;
}

var properties = new MaterialPropertyBlock();
properties.SetVector("_viewSize", this._getViewSize());
var boundsMesh = reducedClip.scissor.getBoundsMesh();
var boundsMesh = new MeshMesh(reducedClip.scissor);
this._getLayer().draws.Add(new RenderDraw {
mesh = boundsMesh,
pass = CanvasShaderPass.stencilClear,

bool convex;
var mesh = cache.getFillMesh(out convex);
if (!this._applyClip(mesh.getBounds())) {
if (!this._applyClip(mesh.bounds)) {
return;
}

properties = properties,
});
this._getLayer().draws.Add(new RenderDraw {
mesh = mesh.getBoundsMesh(),
mesh = mesh.boundsMesh,
pass = CanvasShaderPass.fillPass1,
material = mat,
properties = properties,

paint.strokeJoin,
(float) paint.strokeMiterLimit);
if (!this._applyClip(mesh.getBounds())) {
if (!this._applyClip(mesh.bounds)) {
return;
}

vertices.Add(new Vector2(x, y));
uv.Add(new Vector2(uvx1, uvy0));
var mesh = new Mesh();
mesh.SetVertices(vertices);
mesh.SetUVs(0, uv);
mesh.SetIndices(new[] {
0, 1, 2, 0, 2, 1,
0, 2, 3, 0, 3, 2,
}, MeshTopology.Triangles, 0);
if (!this._applyClip(mesh.getBounds())) {
var mesh = new MeshMesh(vertices, _imageTriangles, uv);
if (!this._applyClip(mesh.bounds)) {
return;
}

vertices.Add(new Vector2(x, y));
uv.Add(new Vector2(tx3, ty3));
var mesh = new Mesh();
mesh.SetVertices(vertices);
mesh.SetUVs(0, uv);
mesh.SetIndices(new[] {
0, 4, 1, 1, 4, 5,
0, 1, 4, 1, 5, 4,
1, 5, 2, 2, 5, 6,
1, 2, 5, 2, 6, 5,
2, 6, 3, 3, 6, 7,
2, 3, 6, 3, 7, 6,
4, 8, 5, 5, 8, 9,
4, 5, 8, 5, 9, 8,
5, 9, 6, 6, 9, 10,
5, 6, 9, 6, 10, 9,
6, 10, 7, 7, 10, 11,
6, 7, 10, 7, 11, 10,
8, 12, 9, 9, 12, 13,
8, 9, 12, 9, 13, 12,
9, 13, 10, 10, 13, 14,
9, 10, 13, 10, 14, 13,
10, 14, 11, 11, 14, 15,
10, 11, 14, 11, 15, 14,
}, MeshTopology.Triangles, 0);
if (!this._applyClip(mesh.getBounds())) {
var mesh = new MeshMesh(vertices, _imageNineTriangles, uv);
if (!this._applyClip(mesh.bounds)) {
return;
}

var xform = new float[6];
XformUtils.transformTranslate(xform, (float) offset.dx, (float) offset.dy);
XformUtils.transformPremultiply(xform, state.xform);
XformUtils.transformMultiply(xform, state.xform); // xform = state.xform * xform
var mesh = MeshGenrator.generateMesh(textBlob, xform, this._devicePixelRatio);
var scale = XformUtils.getAverageScale(xform) * this._devicePixelRatio;
var mesh = MeshGenerator.generateMesh(textBlob, scale).transform(xform);
if (!this._applyClip(mesh.getBounds())) {
if (!this._applyClip(mesh.bounds)) {
return;
}

this._layers.Clear();
this._layers.Add(firstLayer);
}
void _drawLayer(RenderLayer layer, CommandBuffer cmdBuf) {
foreach (var subLayer in layer.layers) {
cmdBuf.GetTemporaryRT(subLayer.rtID, new RenderTextureDescriptor(

}
foreach (var draw in layer.draws) {
draw.onExecute(cmdBuf);
draw.onExecute(this, cmdBuf);
}
foreach (var subLayer in layer.layers) {

void _clearLayer(RenderLayer layer) {
foreach (var draw in layer.draws) {
draw.onDestroy();
draw.onDestroy(this);
}
layer.draws.Clear();

}
interface RenderCmd {
void onExecute(CommandBuffer cmdBuf);
void onDestroy();
void onExecute(CommandBufferCanvas canvas, CommandBuffer cmdBuf);
void onDestroy(CommandBufferCanvas canvas);
public Mesh mesh;
public MeshMesh mesh;
public Mesh meshObj;
public void onExecute(CommandBuffer cmdBuf) {
public void onExecute(CommandBufferCanvas canvas, CommandBuffer cmdBuf) {
cmdBuf.DrawMesh(this.mesh, Matrix4x4.identity, this.material, 0, this.pass, this.properties);
if (!this.meshObj) {
this.meshObj = canvas._meshPool.getMesh();
// clear triangles first in order to bypass validation in SetVertices.
this.meshObj.SetTriangles((int[]) null, 0, false);
this.meshObj.SetVertices(this.mesh.vertices);
this.meshObj.SetTriangles(this.mesh.triangles, 0, false);
this.meshObj.SetUVs(0, this.mesh.uv);
}
cmdBuf.DrawMesh(this.meshObj, Matrix4x4.identity, this.material, 0, this.pass, this.properties);
public void onDestroy() {
this.mesh = ObjectUtils.SafeDestroy(this.mesh);
public void onDestroy(CommandBufferCanvas canvas) {
if (this.meshObj) {
canvas._meshPool.returnMesh(this.meshObj);
this.meshObj = null;
}
}
}

public void onExecute(CommandBuffer cmdBuf) {
public void onExecute(CommandBufferCanvas canvas, CommandBuffer cmdBuf) {
public void onDestroy() {
public void onDestroy(CommandBufferCanvas canvas) {
}
}
}

t[5] = 0.0f;
}
// t = s * t;
public static void transformMultiply(float[] t, float[] s) {
float t0 = t[0] * s[0] + t[1] * s[2];
float t2 = t[2] * s[0] + t[3] * s[2];

22
Runtime/ui/painting/painting.cs


};
}
public static Matrix3 toMatrix3(this Matrix4x4 matrix4x4) {
return Matrix3.makeAll(
matrix4x4[0], matrix4x4[4], matrix4x4[12],
matrix4x4[1], matrix4x4[5], matrix4x4[13],
matrix4x4[3], matrix4x4[7], matrix4x4[15]
);
}
public static Matrix4x4 toMatrix4x4(this Matrix3 matrix3) {
var result = Matrix4x4.identity;
result[0] = matrix3[0];
result[1] = matrix3[1];
result[3] = matrix3[2];
result[4] = matrix3[3];
result[5] = matrix3[4];
result[7] = matrix3[5];
result[12] = matrix3[6];
result[13] = matrix3[7];
result[14] = matrix3[8];
return result;
}
public static float alignToPixel(this float v, float devicePixelRatio) {
return Mathf.Round(v * devicePixelRatio) / devicePixelRatio;
}

259
Runtime/ui/painting/path.cs


i += 3;
break;
case PathCommand.bezierTo:
this._cache.tesselateBezier(
this._cache.tessellateBezier(
this._commands[i + 1], this._commands[i + 2],
this._commands[i + 3], this._commands[i + 4],
this._commands[i + 5], this._commands[i + 6], PointFlags.corner);

readonly float _distTol;
readonly float _tessTol;
internal readonly List<PathPath> _paths = new List<PathPath>();
internal readonly List<PathPoint> _points = new List<PathPoint>();
internal readonly List<Vector3> _vertices = new List<Vector3>();
readonly List<PathPath> _paths = new List<PathPath>();
readonly List<PathPoint> _points = new List<PathPoint>();
readonly List<Vector3> _vertices = new List<Vector3>();
Mesh _fillMesh;
MeshMesh _fillMesh;
Mesh _strokeMesh;
MeshMesh _strokeMesh;
float _strokeWidth;
StrokeCap _lineCap;
StrokeJoin _lineJoin;

public void addPoint(float x, float y, PointFlags flags) {
PathUtils.transformPoint(out x, out y, this._xform, x, y);
this._addPoint(x, y, flags);
this._addPoint(new PathPoint{x = x, y = y, flags = flags});
void _addPoint(float x, float y, PointFlags flags) {
void _addPoint(PathPoint point) {
if (this._paths.Count == 0) {
this.addPath();
}

var pt = this._points.Last();
if (PathUtils.ptEquals(pt.x, pt.y, x, y, this._distTol)) {
pt.flags |= flags;
if (PathUtils.ptEquals(pt.x, pt.y, point.x, point.y, this._distTol)) {
pt.flags |= point.flags;
this._points.Add(new PathPoint {x = x, y = y, flags = flags});
this._points.Add(point);
public void tesselateBezier(
public void tessellateBezier(
float x2, float y2,
float x3, float y3, float x4, float y4,
PointFlags flags) {

PathUtils.transformPoint(out x3, out y3, this._xform, x3, y3);
PathUtils.transformPoint(out x4, out y4, this._xform, x4, y4);
this._tesselateBezier(x1, y1, x2, y2, x3, y3, x4, y4, 0, flags);
}
void _tesselateBezier(
float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
int level, PointFlags flags) {
if (level > 10) {
return;
var points = TessellationGenerator.tessellateBezier(x1, y1, x2, y2, x3, y3, x4, y4, this._tessTol);
points[points.Count - 1].flags = flags;
foreach (var point in points) {
this._addPoint(point);
float x12, y12, x23, y23, x34, y34, x123, y123, x234, y234, x1234, y1234;
float dx, dy, d2, d3;
x12 = (x1 + x2) * 0.5f;
y12 = (y1 + y2) * 0.5f;
x23 = (x2 + x3) * 0.5f;
y23 = (y2 + y3) * 0.5f;
x34 = (x3 + x4) * 0.5f;
y34 = (y3 + y4) * 0.5f;
x123 = (x12 + x23) * 0.5f;
y123 = (y12 + y23) * 0.5f;
dx = x4 - x1;
dy = y4 - y1;
d2 = Mathf.Abs((x2 - x4) * dy - (y2 - y4) * dx);
d3 = Mathf.Abs((x3 - x4) * dy - (y3 - y4) * dx);
if ((d2 + d3) * (d2 + d3) < this._tessTol * (dx * dx + dy * dy)) {
this._addPoint(x4, y4, flags);
return;
}
x234 = (x23 + x34) * 0.5f;
y234 = (y23 + y34) * 0.5f;
x1234 = (x123 + x234) * 0.5f;
y1234 = (y123 + y234) * 0.5f;
this._tesselateBezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1, 0);
this._tesselateBezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1, flags);
}
public void closePath() {

}
}
public Mesh getFillMesh(out bool convex) {
if (this._fillMesh) {
public MeshMesh getFillMesh(out bool convex) {
if (this._fillMesh != null) {
var mesh = new Mesh();
this._fillMesh = mesh;
mesh.SetVertices(this._vertices);
var cindices = 0;
for (var i = 0; i < this._paths.Count; i++) {

}
}
var indices = new int[cindices];
var k = 0;
var indices = new List<int>(cindices);
for (var i = 0; i < this._paths.Count; i++) {
var path = this._paths[i];
if (path.count <= 2) {

if (path.nfill > 0) {
for (var j = 2; j < path.nfill; j++) {
indices[k++] = path.ifill;
indices[k++] = path.ifill + j;
indices[k++] = path.ifill + j - 1;
indices.Add(path.ifill);
indices.Add(path.ifill + j);
indices.Add(path.ifill + j - 1);
D.assert(k == cindices);
mesh.SetIndices(indices, MeshTopology.Triangles, 0);
D.assert(indices.Count == cindices);
var mesh = new MeshMesh(this._vertices, indices);
this._fillMesh = mesh;
this._fillConvex = false;
for (var i = 0; i < this._paths.Count; i++) {
var path = this._paths[i];

}
convex = this._fillConvex;
return mesh;
return this._fillMesh;
}
void _calculateJoins(float w, StrokeJoin lineJoin, float miterLimit) {

}
}
public Mesh getStrokeMesh(float strokeWidth, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
if (this._strokeMesh &&
public MeshMesh getStrokeMesh(float strokeWidth, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
if (this._strokeMesh != null &&
this._strokeWidth == strokeWidth &&
this._lineCap == lineCap &&
this._lineJoin == lineJoin &&

this._expandStroke(strokeWidth, lineCap, lineJoin, miterLimit);
var mesh = new Mesh();
this._strokeMesh = mesh;
this._strokeWidth = strokeWidth;
this._lineCap = lineCap;
this._lineJoin = lineJoin;
this._miterLimit = miterLimit;
mesh.SetVertices(this._vertices);
var cindices = 0;
for (var i = 0; i < this._paths.Count; i++) {
var path = this._paths[i];

}
}
var indices = new int[cindices];
var k = 0;
var indices = new List<int>(cindices);
for (var i = 0; i < this._paths.Count; i++) {
var path = this._paths[i];
if (path.count <= 1) {

if (path.nstroke > 0) {
for (var j = 2; j < path.nstroke; j++) {
if ((j & 1) == 0) {
indices[k++] = path.istroke + j - 1;
indices[k++] = path.istroke + j - 2;
indices[k++] = path.istroke + j;
indices.Add(path.istroke + j - 1);
indices.Add(path.istroke + j - 2);
indices.Add(path.istroke + j);
indices[k++] = path.istroke + j - 2;
indices[k++] = path.istroke + j - 1;
indices[k++] = path.istroke + j;
indices.Add(path.istroke + j - 2);
indices.Add(path.istroke + j - 1);
indices.Add(path.istroke + j);
D.assert(k == cindices);
D.assert(indices.Count == cindices);
mesh.SetIndices(indices, MeshTopology.Triangles, 0);
return mesh;
this._strokeMesh = new MeshMesh(this._vertices, indices);
this._strokeWidth = strokeWidth;
this._lineCap = lineCap;
this._lineJoin = lineJoin;
this._miterLimit = miterLimit;
return this._strokeMesh;
}
}

dst.Add(new Vector2(rx1, ry1));
}
}
}
public static Rect getBounds(this Mesh mesh) {
var bounds = mesh.bounds;
var min = bounds.min;
var size = bounds.size;
return Rect.fromLTWH(min.x, min.y, size.x, size.y);
class MeshMesh {
public readonly List<Vector3> vertices;
public readonly List<int> triangles;
public readonly List<Vector2> uv;
public readonly Rect bounds;
MeshMesh _boundsMesh;
static readonly List<int> _boundsTriangles = new List<int>(6) {0, 2, 1, 1, 2, 3};
public MeshMesh boundsMesh {
get {
if (this._boundsMesh != null) {
return this._boundsMesh;
}
this._boundsMesh = new MeshMesh(this.bounds);
return this._boundsMesh;
}
public static Mesh getBoundsMesh(this Mesh mesh) {
var bounds = mesh.bounds;
var boundsMesh = new Mesh();
public MeshMesh(Rect rect) {
this.vertices = new List<Vector3>(4) {
new Vector3((float) rect.right, (float) rect.bottom),
new Vector3((float) rect.right, (float) rect.top),
new Vector3((float) rect.left, (float) rect.bottom),
new Vector3((float) rect.left, (float) rect.top)
};
var min = bounds.min;
var max = bounds.max;
this.triangles = _boundsTriangles;
this.bounds = rect;
this._boundsMesh = this;
}
var vertices = new List<Vector3>(4);
vertices.Add(new Vector2(max.x, max.y));
vertices.Add(new Vector2(max.x, min.y));
vertices.Add(new Vector2(min.x, max.y));
vertices.Add(new Vector2(min.x, min.y));
boundsMesh.SetVertices(vertices);
public MeshMesh(List<Vector3> vertices, List<int> triangles, List<Vector2> uv = null) {
D.assert(vertices != null);
D.assert(vertices.Count > 0);
D.assert(triangles != null);
D.assert(triangles.Count > 0);
D.assert(uv == null || uv.Count == vertices.Count);
var indices = new[] {0, 2, 1, 1, 2, 3};
boundsMesh.SetIndices(indices, MeshTopology.Triangles, 0);
this.vertices = vertices;
this.triangles = triangles;
this.uv = uv;
double minX = vertices[0].x;
double maxX = vertices[0].x;
double minY = vertices[0].y;
double maxY = vertices[0].y;
return boundsMesh;
for (int i = 1; i < vertices.Count; i++) {
var vertex = vertices[i];
if (vertex.x < minX) {
minX = vertex.x;
}
if (vertex.x > maxX) {
maxX = vertex.x;
}
if (vertex.y < minY) {
minY = vertex.y;
}
if (vertex.y > maxY) {
maxY = vertex.y;
}
}
this.bounds = Rect.fromLTRB(minX, minY, maxX, maxY);
public static Mesh getBoundsMesh(this Rect rect) {
var boundsMesh = new Mesh();
public MeshMesh transform(float[] xform) {
var transVertices = new List<Vector3>(this.vertices.Count);
foreach (var vertex in this.vertices) {
float x, y;
PathUtils.transformPoint(out x, out y, xform, vertex.x, vertex.y);
transVertices.Add(new Vector3(x, y));
}
return new MeshMesh(transVertices, this.triangles, this.uv);
}
}
public class MeshPool : IDisposable {
readonly Queue<Mesh> _pool = new Queue<Mesh>();
var vertices = new List<Vector3>(4);
vertices.Add(new Vector2((float) rect.right, (float) rect.bottom));
vertices.Add(new Vector2((float) rect.right, (float) rect.top));
vertices.Add(new Vector2((float) rect.left, (float) rect.bottom));
vertices.Add(new Vector2((float) rect.left, (float) rect.top));
boundsMesh.SetVertices(vertices);
public Mesh getMesh() {
if (this._pool.Count > 0) {
var mesh = this._pool.Dequeue();
D.assert(mesh);
return mesh;
} else {
var mesh = new Mesh();
mesh.hideFlags = HideFlags.HideAndDontSave;
return mesh;
}
}
var indices = new[] {0, 2, 1, 1, 2, 3};
boundsMesh.SetIndices(indices, MeshTopology.Triangles, 0);
public void returnMesh(Mesh mesh) {
D.assert(mesh.hideFlags == HideFlags.HideAndDontSave);
this._pool.Enqueue(mesh);
}
return boundsMesh;
public void Dispose() {
foreach (var mesh in this._pool) {
ObjectUtils.SafeDestroy(mesh);
}
this._pool.Clear();
}
}
}

6
Runtime/ui/painting/picture.cs


bool convex;
var rect = drawClipPath.path.flatten(
XformUtils.fromMatrix3(state.xform), (float) Window.instance.devicePixelRatio
).getFillMesh(out convex).getBounds();
).getFillMesh(out convex).bounds;
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
} else if (drawCmd is DrawPath) {
var drawPath = (DrawPath) drawCmd;

var paint = drawPath.paint;
var devicePixelRatio = (float) Window.instance.devicePixelRatio;
Mesh mesh;
MeshMesh mesh;
if (paint.style == PaintingStyle.fill) {
var cache = path.flatten(xform, devicePixelRatio);

(float) paint.strokeMiterLimit);
}
this._addPaintBounds(mesh.getBounds());
this._addPaintBounds(mesh.bounds);
} else if (drawCmd is DrawImage) {
var drawImage = (DrawImage) drawCmd;
var state = this._getState();

14
Runtime/ui/painting/txt/font_manager.cs


}
public class FontManager {
List<FontInfo> _fonts = new List<FontInfo>();
readonly List<FontInfo> _fonts = new List<FontInfo>();
static readonly int defaultFontSize = 14;
public static readonly FontManager instance = new FontManager();

return true;
}
internal FontInfo getOrCreate(string[] names) {
this._fonts = this._fonts.FindAll(info => info.font != null); // filter out destroyed fonts
internal FontInfo getOrCreate(string name) {
names == info.font.fontNames ||
names != null && names.SequenceEqual(info.font.fontNames));
info.font && info.font.fontNames.Contains(name));
var osFont = Font.CreateDynamicFontFromOSFont(names, defaultFontSize);
var osFont = Font.CreateDynamicFontFromOSFont(name, defaultFontSize);
osFont.hideFlags = HideFlags.DontSave;
osFont.material.hideFlags = HideFlags.DontSave;
osFont.material.mainTexture.hideFlags = HideFlags.DontSave;

return newFont;
}
internal FontInfo getOrCreate(string name) {
return this.getOrCreate(new[] {name});
}
void onFontTextureRebuilt(Font font) {

82
Runtime/ui/painting/txt/mesh_generator.cs


using UnityEngine;
namespace Unity.UIWidgets.ui {
// TODO: probably we don't need this cache.
public class MeshKey : IEquatable<MeshKey> {
class MeshKey : IEquatable<MeshKey> {
public readonly int fontSize;
public readonly int fontSizeToLoad;
public readonly float pixelPerPoint;
public readonly UnityEngine.Color color;
public readonly float scale;
public MeshKey(string text, int fontId, int textureVersion, int fontSize,
UnityEngine.FontStyle fontStyle, float pixelPerPoint, UnityEngine.Color color) {
public MeshKey(string text, int fontId, int textureVersion, int fontSizeToLoad,
UnityEngine.FontStyle fontStyle, float scale) {
this.fontSize = fontSize;
this.fontSizeToLoad = fontSizeToLoad;
this.pixelPerPoint = pixelPerPoint;
this.color = color;
this.scale = scale;
}
public bool Equals(MeshKey other) {

return true;
}
return string.Equals(this.text, other.text) && this.fontId == other.fontId &&
this.textureVersion == other.textureVersion && this.fontSize == other.fontSize &&
this.fontStyle == other.fontStyle && this.pixelPerPoint.Equals(other.pixelPerPoint) &&
this.color.Equals(other.color);
this.textureVersion == other.textureVersion && this.fontSizeToLoad == other.fontSizeToLoad &&
this.fontStyle == other.fontStyle && this.scale.Equals(other.scale);
}
public override bool Equals(object obj) {

var hashCode = (this.text != null ? this.text.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.fontId;
hashCode = (hashCode * 397) ^ this.textureVersion;
hashCode = (hashCode * 397) ^ this.fontSize;
hashCode = (hashCode * 397) ^ this.fontSizeToLoad;
hashCode = (hashCode * 397) ^ this.pixelPerPoint.GetHashCode();
hashCode = (hashCode * 397) ^ this.color.GetHashCode();
hashCode = (hashCode * 397) ^ this.scale.GetHashCode();
return hashCode;
}
}

public override string ToString() {
return
$"Text: {this.text}, FontId: {this.fontId}, TextureVersion: {this.textureVersion}, FontSize: {this.fontSize}, FontStyle: {this.fontStyle}, PixelPerPoint: {this.pixelPerPoint}, Color: {this.color}";
$"MeshKey(text: {this.text}, " +
$"fontId: {this.fontId}, " +
$"textureVersion: {this.textureVersion}, " +
$"fontSizeToLoad: {this.fontSizeToLoad}, " +
$"fontStyle: {this.fontStyle}, " +
$"scale: {this.scale})";
public class MeshInfo {
public readonly Mesh mesh;
class MeshInfo {
public long _timeToLive;
public readonly MeshMesh mesh;
long _timeToLive;
public MeshInfo(MeshKey key, Mesh mesh, int timeToLive = 5) {
public MeshInfo(MeshKey key, MeshMesh mesh, int timeToLive = 5) {
this.mesh = mesh;
this.key = key;
this.touch(timeToLive);

}
public void touch(long timeTolive = 5) {
this._timeToLive = timeTolive + MeshGenrator.frameCount;
this._timeToLive = timeTolive + MeshGenerator.frameCount;
public static class MeshGenrator {
static Dictionary<MeshKey, MeshInfo> _meshes = new Dictionary<MeshKey, MeshInfo>();
static class MeshGenerator {
static readonly Dictionary<MeshKey, MeshInfo> _meshes = new Dictionary<MeshKey, MeshInfo>();
static long _frameCount = 0;

}
}
public static Mesh generateMesh(TextBlob textBlob, float[] xform, float devicePixelRatio) {
public static MeshMesh generateMesh(TextBlob textBlob, float scale) {
var style = textBlob.style;
var fontInfo = FontManager.instance.getOrCreate(style.fontFamily);
var font = fontInfo.font;

var scale = XformUtils.getAverageScale(xform) * devicePixelRatio;
var key = new MeshKey(subText, font.GetInstanceID(), fontInfo.textureVersion, fontSizeToLoad,
style.UnityFontStyle, scale);
_meshes.TryGetValue(key, out var meshInfo);
if (meshInfo != null) {
meshInfo.touch();
return meshInfo.mesh;
}
Mesh mesh = new Mesh();
for (int charIndex = 0; charIndex < length; ++charIndex) {
var ch = text[charIndex + textBlob.start];
// first char as origin for mesh position

var baseIndex = vertices.Count;
float x, y;
PathUtils.transformPoint(out x, out y, xform, (float) (position.x + minX), (float) (position.y - maxY));
vertices.Add(new Vector3(x, y, 0));
PathUtils.transformPoint(out x, out y, xform, (float) (position.x + maxX), (float) (position.y - maxY));
vertices.Add(new Vector3(x, y, 0));
PathUtils.transformPoint(out x, out y, xform, (float) (position.x + maxX), (float) (position.y - minY));
vertices.Add(new Vector3(x, y, 0));
PathUtils.transformPoint(out x, out y, xform, (float) (position.x + minX), (float) (position.y - minY));
vertices.Add(new Vector3(x, y, 0));
vertices.Add(new Vector3((float) (position.x + minX), (float) (position.y - maxY), 0));
vertices.Add(new Vector3((float) (position.x + maxX), (float) (position.y - maxY), 0));
vertices.Add(new Vector3((float) (position.x + maxX), (float) (position.y - minY), 0));
vertices.Add(new Vector3((float) (position.x + minX), (float) (position.y - minY), 0));
triangles.Add(baseIndex);
triangles.Add(baseIndex + 1);

uv.Add(charInfo.uvBottomLeft);
}
mesh.SetVertices(vertices);
mesh.SetIndices(triangles.ToArray(), MeshTopology.Triangles, 0);
mesh.SetUVs(0, uv);
MeshMesh mesh = new MeshMesh(vertices, triangles, uv);
_meshes[key] = new MeshInfo(key, mesh);
return mesh;
}
}

5
Runtime/widgets/binding.cs


this.buildOwner.onBuildScheduled = this._handleBuildScheduled;
Window.instance.onLocaleChanged += this.handleLocaleChanged;
this.widgetInspectorService = new WidgetInspectorService(this);
this.addPersistentFrameCallback((duration) => { MeshGenrator.tickNextFrame(); });
this.addPersistentFrameCallback((duration) => {
MeshGenerator.tickNextFrame();
TessellationGenerator.tickNextFrame();
});
}
public BuildOwner buildOwner {

2
Runtime/widgets/scroll_position_with_single_context.cs


base.debugFillDescription(description);
description.Add(this.context.GetType().ToString());
description.Add(this.physics.ToString());
description.Add(this.activity.ToString());
description.Add(this.activity?.ToString());
description.Add(this.userScrollDirection.ToString());
}
}

4
Runtime/widgets/widget_inspector.cs


continue;
}
var childTransform = transform;
renderObject.applyPaintTransform(child, ref childTransform);
var childTransform = new Matrix3(transform);
renderObject.applyPaintTransform(child, childTransform);
if (this._hitTestHelper(hits, edgeHits, position, child, childTransform)) {
hit = true;
}

24
Tests/Editor/CanvasAndLayers.cs


WindowAdapter _windowAdapter;
MeshPool _meshPool;
CanvasAndLayers() {
this._options = new Action[] {
this.drawPloygon4,

void OnEnable() {
this._windowAdapter = new EditorWindowAdapter(this);
this._windowAdapter.OnEnable();
this._meshPool = new MeshPool();
}
void OnDisable() {
this._meshPool.Dispose();
this._meshPool = null;
}
void createRenderTexture() {

}
void drawPloygon4() {
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
var paint = new Paint {
color = new Color(0xFFFF0000),

}
void drawLine() {
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
var paint = new Paint {
color = new Color(0xFFFF0000),

}
void drawRect() {
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
var paint = new Paint {
color = new Color(0xFFFF0000),

var picture = pictureRecorder.endRecording();
Debug.Log("picture.paintBounds: " + picture.paintBounds);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
editorCanvas.drawPicture(picture);
editorCanvas.rotate(-15 * Mathf.PI / 180);

return;
}
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
var paint = new Paint {
color = new Color(0x7FFF0000),

var picture = pictureRecorder.endRecording();
Debug.Log("picture.paintBounds: " + picture.paintBounds);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
editorCanvas.rotate(-5 * Mathf.PI / 180);
editorCanvas.clipRect(Unity.UIWidgets.ui.Rect.fromLTWH(25, 15, 250, 250));
editorCanvas.rotate(5 * Mathf.PI / 180);

var picture = pictureRecorder.endRecording();
Debug.Log("picture.paintBounds: " + picture.paintBounds);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
editorCanvas.rotate(-5 * Mathf.PI / 180);
editorCanvas.clipRRect(RRect.fromRectAndRadius(Unity.UIWidgets.ui.Rect.fromLTWH(25, 15, 250, 250), 50));
editorCanvas.rotate(5 * Mathf.PI / 180);

var picture = pictureRecorder.endRecording();
Debug.Log("picture.paintBounds: " + picture.paintBounds);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio);
var editorCanvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
editorCanvas.saveLayer(picture.paintBounds, new Paint {color = new Color(0x7FFFFFFF)});
editorCanvas.drawPicture(picture);

35
Tests/Editor/Widgets.cs


using Color = Unity.UIWidgets.ui.Color;
using Image = Unity.UIWidgets.widgets.Image;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
using Transform = Unity.UIWidgets.widgets.Transform;
namespace UIWidgets.Tests {
public class Widgets : EditorWindow {

const double headerHeight = 50.0;
Widget _buildHeader(BuildContext context) {
return new Container(
var container = new Container(
padding: EdgeInsets.only(left: 16.0, right: 8.0),
height: headerHeight,
color: CLColors.header,

}
)
);
return container;
}
Widget _buildFooter(BuildContext context) {

}
public override Widget build(BuildContext context) {
var mediaQueryData = MediaQuery.of(context);
var px = mediaQueryData.size.width / 2;
var py = mediaQueryData.size.width / 2;
child: new Column(
children: new List<Widget> {
this._buildHeader(context),
this._buildContentList(context),
}
child: new Transform(
transform: Matrix3.makeRotate(0, (float) px, (float) py),
child:
new Column(
children: new List<Widget> {
this._buildHeader(context),
this._buildContentList(context),
}
)
)
)
);

this.imageSrc = imageSrc;
}
public string name;
public string category;
public double price;
public double priceDiscount;
public bool showBadge;
public string imageSrc;
public readonly string name;
public readonly string category;
public readonly double price;
public readonly double priceDiscount;
public readonly bool showBadge;
public readonly string imageSrc;
public override Widget build(BuildContext context) {
var card = new Container(

238
Runtime/ui/painting/tessellation_generator.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Unity.UIWidgets.ui {
class TessellationKey : IEquatable<TessellationKey> {
public readonly float x2;
public readonly float y2;
public readonly float x3;
public readonly float y3;
public readonly float x4;
public readonly float y4;
public readonly float tessTol;
public TessellationKey(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
float tessTol) {
this.x2 = x2 - x1;
this.y2 = y2 - y1;
this.x3 = x3 - x1;
this.y3 = y3 - y1;
this.x4 = x4 - x1;
this.y4 = y4 - y1;
this.tessTol = tessTol;
}
public bool Equals(TessellationKey other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.x2.Equals(other.x2) && this.y2.Equals(other.y2) && this.x3.Equals(other.x3) &&
this.y3.Equals(other.y3) && this.x4.Equals(other.x4) && this.y4.Equals(other.y4) &&
this.tessTol.Equals(other.tessTol);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((TessellationKey) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = this.x2.GetHashCode();
hashCode = (hashCode * 397) ^ this.y2.GetHashCode();
hashCode = (hashCode * 397) ^ this.x3.GetHashCode();
hashCode = (hashCode * 397) ^ this.y3.GetHashCode();
hashCode = (hashCode * 397) ^ this.x4.GetHashCode();
hashCode = (hashCode * 397) ^ this.y4.GetHashCode();
hashCode = (hashCode * 397) ^ this.tessTol.GetHashCode();
return hashCode;
}
}
public static bool operator ==(TessellationKey left, TessellationKey right) {
return Equals(left, right);
}
public static bool operator !=(TessellationKey left, TessellationKey right) {
return !Equals(left, right);
}
public override string ToString() {
return $"TessellationKey(" +
$"x2: {this.x2}, " +
$"y2: {this.y2}, " +
$"x3: {this.x3}, " +
$"y3: {this.y3}, " +
$"x4: {this.x4}, " +
$"y4: {this.y4}, " +
$"tessTol: {this.tessTol})";
}
}
class TessellationInfo {
public readonly TessellationKey key;
public readonly List<Vector2> points;
long _timeToLive;
public TessellationInfo(TessellationKey key, List<Vector2> points, int timeToLive = 5) {
this.points = points;
this.key = key;
this.touch(timeToLive);
}
public long timeToLive {
get { return this._timeToLive; }
}
public void touch(long timeTolive = 5) {
this._timeToLive = timeTolive + MeshGenerator.frameCount;
}
}
static class TessellationGenerator {
static readonly Dictionary<TessellationKey, TessellationInfo> _tessellations =
new Dictionary<TessellationKey, TessellationInfo>();
static long _frameCount = 0;
public static long frameCount {
get { return _frameCount; }
}
public static int tessellationCount {
get { return _tessellations.Count; }
}
public static void tickNextFrame() {
_frameCount++;
var keysToRemove = _tessellations.Values.Where(info => info.timeToLive < _frameCount)
.Select(info => info.key).ToList();
foreach (var key in keysToRemove) {
_tessellations.Remove(key);
}
}
public static List<PathPoint> tessellateBezier(float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4, float tessTol) {
var key = new TessellationKey(x1, y1, x2, y2, x3, y3, x4, y4, tessTol);
_tessellations.TryGetValue(key, out var tessellationInfo);
if (tessellationInfo != null) {
tessellationInfo.touch();
return _toPathPoints(tessellationInfo.points, x1, y1);
}
var points = _tessellateBezier(x1, y1, x2, y2, x3, y3, x4, y4, tessTol);
_tessellations[key] = new TessellationInfo(key, points);
return _toPathPoints(points, x1, y1);
}
static List<PathPoint> _toPathPoints(List<Vector2> points, float x1, float y1) {
var pathPoints = new List<PathPoint>(points.Count);
foreach (var point in points) {
pathPoints.Add(new PathPoint {
x = point.x + x1,
y = point.y + y1,
});
}
return pathPoints;
}
struct _StackData {
public float x1;
public float y1;
public float x2;
public float y2;
public float x3;
public float y3;
public float x4;
public float y4;
public int level;
}
static List<Vector2> _tessellateBezier(
float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
float tessTol) {
x2 = x2 - x1;
y2 = y2 - y1;
x3 = x3 - x1;
y3 = y3 - y1;
x4 = x4 - x1;
y4 = y4 - y1;
var points = new List<Vector2>();
var stack = new Stack<_StackData>();
stack.Push(new _StackData {
x1 = 0, y1 = 0, x2 = x2, y2 = y2, x3 = x3, y3 = y3, x4 = x4, y4 = y4, level = 0,
});
while (stack.Count > 0) {
var stackData = stack.Pop();
x1 = stackData.x1;
y1 = stackData.y1;
x2 = stackData.x2;
y2 = stackData.y2;
x3 = stackData.x3;
y3 = stackData.y3;
x4 = stackData.x4;
y4 = stackData.y4;
int level = stackData.level;
float dx = x4 - x1;
float dy = y4 - y1;
float d2 = Mathf.Abs((x2 - x4) * dy - (y2 - y4) * dx);
float d3 = Mathf.Abs((x3 - x4) * dy - (y3 - y4) * dx);
if ((d2 + d3) * (d2 + d3) <= tessTol * (dx * dx + dy * dy)) {
points.Add(new Vector2(x4, y4));
continue;
}
float x12 = (x1 + x2) * 0.5f;
float y12 = (y1 + y2) * 0.5f;
float x23 = (x2 + x3) * 0.5f;
float y23 = (y2 + y3) * 0.5f;
float x34 = (x3 + x4) * 0.5f;
float y34 = (y3 + y4) * 0.5f;
float x123 = (x12 + x23) * 0.5f;
float y123 = (y12 + y23) * 0.5f;
float x234 = (x23 + x34) * 0.5f;
float y234 = (y23 + y34) * 0.5f;
float x1234 = (x123 + x234) * 0.5f;
float y1234 = (y123 + y234) * 0.5f;
if (level < 10) {
stack.Push(new _StackData {
x1 = x1234, y1 = y1234, x2 = x234, y2 = y234, x3 = x34, y3 = y34, x4 = x4, y4 = y4,
level = level + 1,
});
stack.Push(new _StackData {
x1 = x1, y1 = y1, x2 = x12, y2 = y12, x3 = x123, y3 = y123, x4 = x1234, y4 = y1234,
level = level + 1,
});
}
}
return points;
}
}
}

11
Runtime/ui/painting/tessellation_generator.cs.meta


fileFormatVersion: 2
guid: 93b0b0a1a1a7840468752a0ff8aac9dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存