您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

245 行
9.2 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.ui {
public class Picture {
public Picture(List<DrawCmd> drawCmds, Rect paintBounds) {
this.drawCmds = drawCmds;
this.paintBounds = paintBounds;
}
public readonly List<DrawCmd> drawCmds;
public readonly Rect paintBounds;
}
public class PictureRecorder {
readonly List<DrawCmd> _drawCmds = new List<DrawCmd>();
readonly List<CanvasState> _states = new List<CanvasState>();
public PictureRecorder() {
this._states.Add(new CanvasState {
xform = Matrix3.I(),
scissor = null,
saveLayer = false,
layerOffset = null,
paintBounds = Rect.zero,
});
}
CanvasState _getState() {
D.assert(this._states.Count > 0);
return this._states.Last();
}
public Picture endRecording() {
if (this._states.Count > 1) {
throw new Exception("unmatched save/restore commands");
}
var state = this._getState();
return new Picture(this._drawCmds, state.paintBounds);
}
public void addDrawCmd(DrawCmd drawCmd) {
this._drawCmds.Add(drawCmd);
switch (drawCmd) {
case DrawSave _:
this._states.Add(this._getState().copy());
break;
case DrawSaveLayer cmd: {
this._states.Add(new CanvasState {
xform = Matrix3.I(),
scissor = cmd.rect.shift(-cmd.rect.topLeft),
saveLayer = true,
layerOffset = cmd.rect.topLeft,
paintBounds = Rect.zero,
});
break;
}
case DrawRestore _: {
var stateToRestore = this._getState();
this._states.RemoveAt(this._states.Count - 1);
var state = this._getState();
if (!stateToRestore.saveLayer) {
state.paintBounds = stateToRestore.paintBounds;
}
else {
var paintBounds = stateToRestore.paintBounds.shift(stateToRestore.layerOffset);
paintBounds = state.xform.mapRect(paintBounds);
this._addPaintBounds(paintBounds);
}
break;
}
case DrawTranslate cmd: {
var state = this._getState();
state.xform.preTranslate((float) cmd.dx, (float) cmd.dy);
break;
}
case DrawScale cmd: {
var state = this._getState();
state.xform.preScale((float) cmd.sx, (float) (cmd.sy ?? cmd.sx));
break;
}
case DrawRotate cmd: {
var state = this._getState();
if (cmd.offset == null) {
state.xform.preRotate((float) cmd.radians);
}
else {
state.xform.preRotate((float) cmd.radians,
(float) cmd.offset.dx,
(float) cmd.offset.dy);
}
break;
}
case DrawSkew cmd: {
var state = this._getState();
state.xform.preSkew((float) cmd.sx, (float) cmd.sy);
break;
}
case DrawConcat cmd: {
var state = this._getState();
state.xform.preConcat(cmd.matrix);
break;
}
case DrawResetMatrix _: {
var state = this._getState();
state.xform.reset();
break;
}
case DrawSetMatrix cmd: {
var state = this._getState();
state.xform = new Matrix3(cmd.matrix);
break;
}
case DrawClipRect cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.rect);
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
break;
}
case DrawClipRRect cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.rrect.outerRect);
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
break;
}
case DrawClipPath cmd: {
var state = this._getState();
var scale = XformUtils.getScale(state.xform);
var rect = cmd.path.flatten(
scale * (float) Window.instance.devicePixelRatio
).getFillMesh(out _).transform(state.xform).bounds;
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
break;
}
case DrawPath cmd: {
var state = this._getState();
var scale = XformUtils.getScale(state.xform);
var path = cmd.path;
var paint = cmd.paint;
var devicePixelRatio = (float) Window.instance.devicePixelRatio;
MeshMesh mesh;
if (paint.style == PaintingStyle.fill) {
var cache = path.flatten(scale * devicePixelRatio);
mesh = cache.getFillMesh(out _).transform(state.xform);
}
else {
float strokeWidth = ((float) paint.strokeWidth * scale).clamp(0, 200.0f);
float fringeWidth = 1 / devicePixelRatio;
if (strokeWidth < fringeWidth) {
strokeWidth = fringeWidth;
}
var cache = path.flatten(scale * devicePixelRatio);
mesh = cache.getStrokeMesh(
strokeWidth / scale * 0.5f,
paint.strokeCap,
paint.strokeJoin,
(float) paint.strokeMiterLimit).transform(state.xform);
}
this._addPaintBounds(mesh.bounds);
break;
}
case DrawImage cmd: {
var state = this._getState();
var rect = Rect.fromLTWH(cmd.offset.dx, cmd.offset.dy,
cmd.image.width, cmd.image.height);
rect = state.xform.mapRect(rect);
this._addPaintBounds(rect);
break;
}
case DrawImageRect cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.dst);
this._addPaintBounds(rect);
break;
}
case DrawImageNine cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.dst);
this._addPaintBounds(rect);
break;
}
case DrawPicture cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.picture.paintBounds);
this._addPaintBounds(rect);
break;
}
case DrawTextBlob cmd: {
var state = this._getState();
var rect = cmd.textBlob.boundsInText.shift(cmd.offset);
rect = state.xform.mapRect(rect);
this._addPaintBounds(rect);
break;
}
default:
throw new Exception("unknown drawCmd: " + drawCmd);
}
}
void _addPaintBounds(Rect paintBounds) {
var state = this._getState();
if (state.scissor != null) {
paintBounds = paintBounds.intersect(state.scissor);
}
if (state.paintBounds.isEmpty) {
state.paintBounds = paintBounds;
}
else {
state.paintBounds = state.paintBounds.expandToInclude(paintBounds);
}
}
class CanvasState {
public Matrix3 xform;
public Rect scissor;
public bool saveLayer;
public Offset layerOffset;
public Rect paintBounds;
public CanvasState copy() {
return new CanvasState {
xform = this.xform,
scissor = this.scissor,
saveLayer = false,
layerOffset = null,
paintBounds = this.paintBounds,
};
}
}
}
}