您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
1532 行
50 KiB
1532 行
50 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using Unity.UIWidgets.animation;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.gestures;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.ui;
|
|
using Canvas = Unity.UIWidgets.ui.Canvas;
|
|
using Color = Unity.UIWidgets.ui.Color;
|
|
using Debug = UnityEngine.Debug;
|
|
using Rect = Unity.UIWidgets.ui.Rect;
|
|
|
|
namespace Unity.UIWidgets.rendering {
|
|
public interface IParentData {
|
|
void detach();
|
|
}
|
|
|
|
public class ParentData : IParentData {
|
|
public virtual void detach() {
|
|
}
|
|
|
|
public override string ToString() {
|
|
return "<none>";
|
|
}
|
|
}
|
|
|
|
public delegate void PaintingContextCallback(PaintingContext context, Offset offset);
|
|
|
|
public class PaintingContext : ClipContext {
|
|
public PaintingContext(
|
|
ContainerLayer containerLayer = null,
|
|
Rect estimatedBounds = null
|
|
) {
|
|
D.assert(containerLayer != null);
|
|
D.assert(estimatedBounds != null);
|
|
_containerLayer = containerLayer;
|
|
this.estimatedBounds = estimatedBounds;
|
|
}
|
|
|
|
readonly ContainerLayer _containerLayer;
|
|
|
|
public readonly Rect estimatedBounds;
|
|
|
|
public static void repaintCompositedChild(RenderObject child, bool debugAlsoPaintedParent = false) {
|
|
D.assert(child._needsPaint);
|
|
|
|
_repaintCompositedChild(
|
|
child,
|
|
debugAlsoPaintedParent: debugAlsoPaintedParent
|
|
);
|
|
}
|
|
|
|
static void _repaintCompositedChild(
|
|
RenderObject child,
|
|
bool debugAlsoPaintedParent = false,
|
|
PaintingContext childContext = null
|
|
) {
|
|
D.assert(child.isRepaintBoundary);
|
|
D.assert(() => {
|
|
child.debugRegisterRepaintBoundaryPaint(
|
|
includedParent: debugAlsoPaintedParent,
|
|
includedChild: true
|
|
);
|
|
return true;
|
|
});
|
|
if (child._layer == null) {
|
|
D.assert(debugAlsoPaintedParent);
|
|
child._layer = new OffsetLayer();
|
|
}
|
|
else {
|
|
D.assert(debugAlsoPaintedParent || child._layer.attached);
|
|
child._layer.removeAllChildren();
|
|
}
|
|
D.assert(child._layer is OffsetLayer);
|
|
D.assert(() => {
|
|
child._layer.debugCreator = child.debugCreator ?? child.GetType().ToString();
|
|
return true;
|
|
});
|
|
childContext = childContext ?? new PaintingContext(child._layer, child.paintBounds);
|
|
child._paintWithContext(childContext, Offset.zero);
|
|
childContext.stopRecordingIfNeeded();
|
|
}
|
|
|
|
public static void debugInstrumentRepaintCompositedChild(
|
|
RenderObject child,
|
|
bool debugAlsoPaintedParent = false,
|
|
PaintingContext customContext = null
|
|
) {
|
|
D.assert(() => {
|
|
_repaintCompositedChild(
|
|
child,
|
|
debugAlsoPaintedParent: debugAlsoPaintedParent,
|
|
childContext: customContext
|
|
);
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public virtual void paintChild(RenderObject child, Offset offset) {
|
|
if (child.isRepaintBoundary) {
|
|
stopRecordingIfNeeded();
|
|
_compositeChild(child, offset);
|
|
}
|
|
else {
|
|
child._paintWithContext(this, offset);
|
|
}
|
|
}
|
|
|
|
void _compositeChild(RenderObject child, Offset offset) {
|
|
D.assert(!_isRecording);
|
|
D.assert(child.isRepaintBoundary);
|
|
D.assert(_canvas == null || _canvas.getSaveCount() == 1);
|
|
|
|
if (child._needsPaint) {
|
|
repaintCompositedChild(child, debugAlsoPaintedParent: true);
|
|
}
|
|
else {
|
|
D.assert(child._layer != null);
|
|
D.assert(() => {
|
|
child.debugRegisterRepaintBoundaryPaint(
|
|
includedParent: true,
|
|
includedChild: false
|
|
);
|
|
child._layer.debugCreator = child.debugCreator ?? child;
|
|
return true;
|
|
});
|
|
}
|
|
D.assert(child._layer is OffsetLayer);
|
|
((OffsetLayer)child._layer).offset = offset;
|
|
appendLayer(child._layer);
|
|
}
|
|
|
|
protected virtual void appendLayer(Layer layer) {
|
|
D.assert(!_isRecording);
|
|
|
|
layer.remove();
|
|
_containerLayer.append(layer);
|
|
}
|
|
|
|
bool _isRecording {
|
|
get {
|
|
bool hasCanvas = _canvas != null;
|
|
D.assert(() => {
|
|
if (hasCanvas) {
|
|
D.assert(_currentLayer != null);
|
|
D.assert(_recorder != null);
|
|
D.assert(_canvas != null);
|
|
}
|
|
else {
|
|
D.assert(_currentLayer == null);
|
|
D.assert(_recorder == null);
|
|
D.assert(_canvas == null);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
return hasCanvas;
|
|
}
|
|
}
|
|
|
|
PictureLayer _currentLayer;
|
|
PictureRecorder _recorder;
|
|
Canvas _canvas;
|
|
|
|
public override Canvas canvas {
|
|
get {
|
|
if (_canvas == null) {
|
|
_startRecording();
|
|
}
|
|
|
|
return _canvas;
|
|
}
|
|
}
|
|
|
|
void _startRecording() {
|
|
D.assert(!_isRecording);
|
|
|
|
_currentLayer = new PictureLayer(estimatedBounds);
|
|
_recorder = new PictureRecorder();
|
|
_canvas = new Canvas(_recorder);
|
|
_containerLayer.append(_currentLayer);
|
|
}
|
|
|
|
protected virtual void stopRecordingIfNeeded() {
|
|
if (!_isRecording) {
|
|
return;
|
|
}
|
|
|
|
D.assert(() => {
|
|
if (D.debugRepaintRainbowEnabled) {
|
|
var paint = new Paint {
|
|
style = PaintingStyle.stroke,
|
|
strokeWidth = 6.0f,
|
|
color = D.debugCurrentRepaintColor.toColor()
|
|
};
|
|
canvas.drawRect(estimatedBounds.deflate(3.0f), paint);
|
|
}
|
|
|
|
if (D.debugPaintLayerBordersEnabled) {
|
|
Paint paint = new Paint {
|
|
style = PaintingStyle.stroke,
|
|
strokeWidth = 1.0f,
|
|
color = new Color(0xFFFF9800),
|
|
};
|
|
canvas.drawRect(estimatedBounds, paint);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
_currentLayer.picture = _recorder.endRecording();
|
|
_currentLayer = null;
|
|
_recorder = null;
|
|
_canvas = null;
|
|
}
|
|
|
|
public void setIsComplexHint() {
|
|
if (_currentLayer != null) {
|
|
_currentLayer.isComplexHint = true;
|
|
}
|
|
}
|
|
|
|
public void setWillChangeHint() {
|
|
if (_currentLayer != null) {
|
|
_currentLayer.willChangeHint = true;
|
|
}
|
|
}
|
|
|
|
public void addLayer(Layer layer) {
|
|
stopRecordingIfNeeded();
|
|
appendLayer(layer);
|
|
}
|
|
|
|
public void pushLayer(ContainerLayer childLayer, PaintingContextCallback painter, Offset offset,
|
|
Rect childPaintBounds = null) {
|
|
D.assert(painter != null);
|
|
if (childLayer.hasChildren) {
|
|
childLayer.removeAllChildren();
|
|
}
|
|
stopRecordingIfNeeded();
|
|
appendLayer(childLayer);
|
|
|
|
var childContext = createChildContext(childLayer, childPaintBounds ?? estimatedBounds);
|
|
painter(childContext, offset);
|
|
childContext.stopRecordingIfNeeded();
|
|
}
|
|
|
|
public virtual PaintingContext createChildContext(ContainerLayer childLayer, Rect bounds) {
|
|
return new PaintingContext(childLayer, bounds);
|
|
}
|
|
|
|
public ClipRectLayer pushClipRect(
|
|
bool needsCompositing,
|
|
Offset offset,
|
|
Rect clipRect,
|
|
PaintingContextCallback painter,
|
|
Clip clipBehavior = Clip.hardEdge,
|
|
ClipRectLayer oldLayer = null) {
|
|
Rect offsetClipRect = clipRect.shift(offset);
|
|
if (needsCompositing) {
|
|
ClipRectLayer layer = oldLayer ?? new ClipRectLayer();
|
|
layer.clipRect = offsetClipRect;
|
|
layer.clipBehavior = clipBehavior;
|
|
pushLayer(layer, painter, offset, childPaintBounds: offsetClipRect);
|
|
return layer;
|
|
}
|
|
else {
|
|
clipRectAndPaint(offsetClipRect, clipBehavior, offsetClipRect, () => painter(this, offset));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public ClipRRectLayer pushClipRRect(
|
|
bool needsCompositing,
|
|
Offset offset,
|
|
Rect bounds,
|
|
RRect clipRRect,
|
|
PaintingContextCallback painter,
|
|
Clip clipBehavior = Clip.antiAlias,
|
|
ClipRRectLayer oldLayer = null) {
|
|
Rect offsetBounds = bounds.shift(offset);
|
|
RRect offsetClipRRect = clipRRect.shift(offset);
|
|
if (needsCompositing) {
|
|
ClipRRectLayer layer = oldLayer ?? new ClipRRectLayer();
|
|
layer.clipRRect = offsetClipRRect;
|
|
layer.clipBehavior = clipBehavior;
|
|
pushLayer(layer, painter, offset, childPaintBounds: offsetBounds);
|
|
return layer;
|
|
}
|
|
else {
|
|
clipRRectAndPaint(offsetClipRRect, clipBehavior, offsetBounds, () => painter(this, offset));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public ClipPathLayer pushClipPath(
|
|
bool needsCompositing,
|
|
Offset offset,
|
|
Rect bounds,
|
|
Path clipPath,
|
|
PaintingContextCallback painter,
|
|
Clip clipBehavior = Clip.antiAlias,
|
|
ClipPathLayer oldLayer = null) {
|
|
Rect offsetBounds = bounds.shift(offset);
|
|
Path offsetClipPath = clipPath.shift(offset);
|
|
if (needsCompositing) {
|
|
ClipPathLayer layer = oldLayer ?? new ClipPathLayer();
|
|
layer.clipPath = offsetClipPath;
|
|
layer.clipBehavior = clipBehavior;
|
|
pushLayer(layer, painter, offset, childPaintBounds: offsetBounds);
|
|
return layer;
|
|
}
|
|
else {
|
|
clipPathAndPaint(offsetClipPath, clipBehavior, offsetBounds, () => painter(this, offset));
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public ColorFilterLayer pushColorFilter(Offset offset, ColorFilter colorFilter, PaintingContextCallback painter, ColorFilterLayer oldLayer = null) {
|
|
D.assert(colorFilter != null);
|
|
ColorFilterLayer layer = oldLayer ?? new ColorFilterLayer();
|
|
layer.colorFilter = colorFilter;
|
|
pushLayer(layer, painter, offset);
|
|
return layer;
|
|
}
|
|
|
|
public TransformLayer pushTransform(
|
|
bool needsCompositing,
|
|
Offset offset,
|
|
Matrix4 transform,
|
|
PaintingContextCallback painter,
|
|
TransformLayer oldLayer = null) {
|
|
Matrix4 effectiveTransform;
|
|
if (offset == null || offset == Offset.zero) {
|
|
effectiveTransform = transform;
|
|
}
|
|
else {
|
|
effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0);
|
|
effectiveTransform.multiply(transform);
|
|
effectiveTransform.translate(-offset.dx, -offset.dy);
|
|
}
|
|
|
|
if (needsCompositing) {
|
|
TransformLayer layer = oldLayer ?? new TransformLayer();
|
|
layer.transform = effectiveTransform;
|
|
|
|
pushLayer(
|
|
layer,
|
|
painter,
|
|
offset,
|
|
childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, estimatedBounds)
|
|
);
|
|
return layer;
|
|
}
|
|
else {
|
|
canvas.save();
|
|
canvas.transform(effectiveTransform._m4storage);
|
|
painter(this, offset);
|
|
canvas.restore();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public OpacityLayer pushOpacity(Offset offset, int alpha, PaintingContextCallback painter, OpacityLayer oldLayer = null) {
|
|
OpacityLayer layer = oldLayer ?? new OpacityLayer();
|
|
layer.alpha = alpha;
|
|
layer.offset = offset;
|
|
pushLayer(layer, painter, Offset.zero);
|
|
return layer;
|
|
}
|
|
|
|
public override string ToString() {
|
|
return
|
|
$"{GetType()}#{GetHashCode()}(layer: {_containerLayer}, canvas bounds: {estimatedBounds}";
|
|
}
|
|
|
|
}
|
|
|
|
public abstract class Constraints {
|
|
|
|
protected Constraints(){}
|
|
public abstract bool isTight { get; }
|
|
|
|
public abstract bool isNormalized { get; }
|
|
|
|
public virtual bool debugAssertIsValid(
|
|
bool isAppliedConstraint = false,
|
|
InformationCollector informationCollector = null
|
|
) {
|
|
D.assert(isNormalized);
|
|
return isNormalized;
|
|
}
|
|
}
|
|
|
|
public delegate void RenderObjectVisitor(RenderObject child);
|
|
|
|
public delegate void LayoutCallback<T>(T constraints) where T : Constraints;
|
|
|
|
public class PipelineOwner {
|
|
public PipelineOwner(
|
|
VoidCallback onNeedVisualUpdate = null) {
|
|
this.onNeedVisualUpdate = onNeedVisualUpdate;
|
|
}
|
|
|
|
public readonly VoidCallback onNeedVisualUpdate;
|
|
|
|
public void requestVisualUpdate() {
|
|
if (onNeedVisualUpdate != null) {
|
|
onNeedVisualUpdate();
|
|
}
|
|
}
|
|
|
|
public AbstractNodeMixinDiagnosticableTree rootNode {
|
|
get { return _rootNode; }
|
|
set {
|
|
if (_rootNode == value) {
|
|
return;
|
|
}
|
|
|
|
if (_rootNode != null) {
|
|
_rootNode.detach();
|
|
}
|
|
|
|
_rootNode = value;
|
|
if (_rootNode != null) {
|
|
_rootNode.attach(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
AbstractNodeMixinDiagnosticableTree _rootNode;
|
|
|
|
internal List<RenderObject> _nodesNeedingLayout = new List<RenderObject>();
|
|
|
|
public bool debugDoingLayout {
|
|
get { return _debugDoingLayout; }
|
|
}
|
|
|
|
internal bool _debugDoingLayout = false;
|
|
|
|
public void flushLayout() {
|
|
D.assert(() => {
|
|
_debugDoingLayout = true;
|
|
return true;
|
|
});
|
|
|
|
try {
|
|
while (_nodesNeedingLayout.isNotEmpty()) {
|
|
var dirtyNodes = _nodesNeedingLayout;
|
|
_nodesNeedingLayout = new List<RenderObject>();
|
|
dirtyNodes.Sort((a, b) => a.depth - b.depth);
|
|
foreach (var node in dirtyNodes) {
|
|
if (node._needsLayout && node.owner == this) {
|
|
node._layoutWithoutResize();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
D.assert(() => {
|
|
_debugDoingLayout = false;
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
|
|
internal bool _debugAllowMutationsToDirtySubtrees = false;
|
|
|
|
internal void _enableMutationsToDirtySubtrees(VoidCallback callback) {
|
|
D.assert(_debugDoingLayout);
|
|
bool oldState = false;
|
|
D.assert(() => {
|
|
oldState = _debugAllowMutationsToDirtySubtrees;
|
|
_debugAllowMutationsToDirtySubtrees = true;
|
|
return true;
|
|
});
|
|
try {
|
|
callback();
|
|
}
|
|
finally {
|
|
D.assert(() => {
|
|
_debugAllowMutationsToDirtySubtrees = oldState;
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
|
|
internal List<RenderObject> _nodesNeedingCompositingBitsUpdate = new List<RenderObject>();
|
|
|
|
public void flushCompositingBits() {
|
|
_nodesNeedingCompositingBitsUpdate.Sort((a, b) => a.depth - b.depth);
|
|
foreach (RenderObject node in _nodesNeedingCompositingBitsUpdate) {
|
|
if (node._needsCompositingBitsUpdate && node.owner == this) {
|
|
node._updateCompositingBits();
|
|
}
|
|
}
|
|
|
|
_nodesNeedingCompositingBitsUpdate.Clear();
|
|
}
|
|
|
|
internal List<RenderObject> _nodesNeedingPaint = new List<RenderObject>();
|
|
|
|
public bool debugDoingPaint {
|
|
get { return _debugDoingPaint; }
|
|
}
|
|
|
|
internal bool _debugDoingPaint = false;
|
|
|
|
public void flushPaint() {
|
|
D.assert(() => {
|
|
_debugDoingPaint = true;
|
|
return true;
|
|
});
|
|
|
|
try {
|
|
var dirtyNodes = _nodesNeedingPaint;
|
|
_nodesNeedingPaint = new List<RenderObject>();
|
|
dirtyNodes.Sort((a, b) => a.depth - b.depth);
|
|
foreach (var node in dirtyNodes) {
|
|
D.assert(node._layer != null);
|
|
if (node._needsPaint && node.owner == this) {
|
|
if (node._layer.attached) {
|
|
PaintingContext.repaintCompositedChild(node);
|
|
}
|
|
else {
|
|
node._skippedPaintingOnLayer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
D.assert(() => {
|
|
_debugDoingPaint = false;
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public abstract class RenderObject : AbstractNodeMixinDiagnosticableTree, HitTestTarget {
|
|
protected RenderObject() {
|
|
_needsCompositing = isRepaintBoundary || alwaysNeedsCompositing;
|
|
}
|
|
|
|
void reassemble() {
|
|
markNeedsLayout();
|
|
markNeedsCompositingBitsUpdate();
|
|
markNeedsPaint();
|
|
visitChildren((RenderObject child) =>{
|
|
child.reassemble();
|
|
});
|
|
}
|
|
|
|
public ParentData parentData;
|
|
|
|
public virtual void setupParentData(RenderObject child) {
|
|
D.assert(_debugCanPerformMutations);
|
|
|
|
if (!(child.parentData is ParentData)) {
|
|
child.parentData = new ParentData();
|
|
}
|
|
}
|
|
|
|
protected override void adoptChild(AbstractNodeMixinDiagnosticableTree childNode) {
|
|
var child = (RenderObject) childNode;
|
|
|
|
D.assert(_debugCanPerformMutations);
|
|
D.assert(child != null);
|
|
setupParentData(child);
|
|
markNeedsLayout();
|
|
markNeedsCompositingBitsUpdate();
|
|
base.adoptChild(child);
|
|
}
|
|
|
|
protected override void dropChild(AbstractNodeMixinDiagnosticableTree childNode) {
|
|
var child = (RenderObject) childNode;
|
|
|
|
D.assert(_debugCanPerformMutations);
|
|
D.assert(child != null);
|
|
D.assert(child.parentData != null);
|
|
child._cleanRelayoutBoundary();
|
|
child.parentData.detach();
|
|
child.parentData = null;
|
|
base.dropChild(child);
|
|
markNeedsLayout();
|
|
markNeedsCompositingBitsUpdate();
|
|
}
|
|
|
|
public virtual void visitChildren(RenderObjectVisitor visitor) {
|
|
}
|
|
|
|
public object debugCreator;
|
|
|
|
void _debugReportException(string method, Exception exception) {
|
|
IEnumerable<DiagnosticsNode> infoCollector() {
|
|
yield return new DiagnosticsDebugCreator(debugCreator);
|
|
yield return describeForError("The following RenderObject was being processed when the exception was fired");
|
|
yield return describeForError("RenderObject", style: DiagnosticsTreeStyle.truncateChildren);
|
|
}
|
|
|
|
UIWidgetsError.reportError(new UIWidgetsErrorDetailsForRendering(
|
|
exception: exception,
|
|
library: "rendering library",
|
|
context: new ErrorDescription("during " + method),
|
|
renderObject: this,
|
|
informationCollector: infoCollector
|
|
));
|
|
}
|
|
|
|
public bool debugDoingThisResize {
|
|
get { return _debugDoingThisResize; }
|
|
}
|
|
|
|
bool _debugDoingThisResize = false;
|
|
|
|
public bool debugDoingThisLayout {
|
|
get { return _debugDoingThisLayout; }
|
|
}
|
|
|
|
bool _debugDoingThisLayout = false;
|
|
|
|
public static RenderObject debugActiveLayout {
|
|
get { return _debugActiveLayout; }
|
|
}
|
|
|
|
static RenderObject _debugActiveLayout;
|
|
|
|
public bool debugCanParentUseSize {
|
|
get { return _debugCanParentUseSize; }
|
|
}
|
|
|
|
bool _debugCanParentUseSize;
|
|
|
|
bool _debugMutationsLocked = false;
|
|
|
|
bool _debugCanPerformMutations {
|
|
get {
|
|
bool result = true;
|
|
D.assert(() => {
|
|
RenderObject node = this;
|
|
while (true) {
|
|
if (node._doingThisLayoutWithCallback) {
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
if (owner != null && owner._debugAllowMutationsToDirtySubtrees && node._needsLayout) {
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
if (node._debugMutationsLocked) {
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
if (!(node.parent is RenderObject)) {
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
node = (RenderObject) node.parent;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public new PipelineOwner owner {
|
|
get { return (PipelineOwner) base.owner; }
|
|
}
|
|
|
|
public override void attach(object ownerObject) {
|
|
var owner = (PipelineOwner) ownerObject;
|
|
|
|
base.attach(owner);
|
|
if (_needsLayout && _relayoutBoundary != null) {
|
|
_needsLayout = false;
|
|
markNeedsLayout();
|
|
}
|
|
|
|
if (_needsCompositingBitsUpdate) {
|
|
_needsCompositingBitsUpdate = false;
|
|
markNeedsCompositingBitsUpdate();
|
|
}
|
|
|
|
if (_needsPaint && _layer != null) {
|
|
_needsPaint = false;
|
|
markNeedsPaint();
|
|
}
|
|
}
|
|
|
|
public bool debugNeedsLayout {
|
|
get {
|
|
bool result = false;
|
|
D.assert(() => {
|
|
result = _needsLayout;
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|
|
internal bool _needsLayout = true;
|
|
|
|
public RenderObject _relayoutBoundary;
|
|
bool _doingThisLayoutWithCallback = false;
|
|
|
|
public Constraints constraints {
|
|
get { return _constraints; }
|
|
}
|
|
|
|
Constraints _constraints;
|
|
|
|
protected abstract void debugAssertDoesMeetConstraints();
|
|
|
|
internal static bool debugCheckingIntrinsics = false;
|
|
|
|
bool _debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout() {
|
|
if (_relayoutBoundary == null) {
|
|
return true;
|
|
}
|
|
|
|
RenderObject node = this;
|
|
while (node != _relayoutBoundary) {
|
|
D.assert(node._relayoutBoundary == _relayoutBoundary);
|
|
D.assert(node.parent != null);
|
|
node = (RenderObject) node.parent;
|
|
if ((!node._needsLayout) && (!node._debugDoingThisLayout)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
D.assert(node._relayoutBoundary == node);
|
|
return true;
|
|
}
|
|
|
|
public virtual void markNeedsLayout() {
|
|
D.assert(_debugCanPerformMutations);
|
|
if (_needsLayout) {
|
|
D.assert(_debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout());
|
|
return;
|
|
}
|
|
|
|
D.assert(_relayoutBoundary != null);
|
|
if (_relayoutBoundary != this) {
|
|
markParentNeedsLayout();
|
|
}
|
|
else {
|
|
_needsLayout = true;
|
|
if (owner != null) {
|
|
D.assert(() => {
|
|
if (D.debugPrintMarkNeedsLayoutStacks) {
|
|
Debug.Log("markNeedsLayout() called for " + this);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
owner._nodesNeedingLayout.Add(this);
|
|
owner.requestVisualUpdate();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void markParentNeedsLayout() {
|
|
_needsLayout = true;
|
|
|
|
RenderObject parent = (RenderObject) this.parent;
|
|
if (!_doingThisLayoutWithCallback) {
|
|
parent.markNeedsLayout();
|
|
}
|
|
else {
|
|
D.assert(parent._debugDoingThisLayout);
|
|
}
|
|
}
|
|
|
|
public void markNeedsLayoutForSizedByParentChange() {
|
|
markNeedsLayout();
|
|
markParentNeedsLayout();
|
|
}
|
|
|
|
void _cleanRelayoutBoundary() {
|
|
if (_relayoutBoundary != this) {
|
|
_relayoutBoundary = null;
|
|
_needsLayout = true;
|
|
visitChildren(_cleanChildRelayoutBoundary);
|
|
}
|
|
}
|
|
|
|
static void _cleanChildRelayoutBoundary(RenderObject child) {
|
|
child._cleanRelayoutBoundary();
|
|
}
|
|
|
|
public void scheduleInitialLayout() {
|
|
D.assert(attached);
|
|
D.assert(!(parent is RenderObject));
|
|
D.assert(!owner._debugDoingLayout);
|
|
D.assert(_relayoutBoundary == null);
|
|
|
|
_relayoutBoundary = this;
|
|
D.assert(() => {
|
|
_debugCanParentUseSize = false;
|
|
return true;
|
|
});
|
|
owner._nodesNeedingLayout.Add(this);
|
|
}
|
|
|
|
internal void _layoutWithoutResize() {
|
|
D.assert(_relayoutBoundary == this);
|
|
RenderObject debugPreviousActiveLayout = null;
|
|
D.assert(!_debugMutationsLocked);
|
|
D.assert(!_doingThisLayoutWithCallback);
|
|
D.assert(() => {
|
|
_debugMutationsLocked = true;
|
|
_debugDoingThisLayout = true;
|
|
debugPreviousActiveLayout = _debugActiveLayout;
|
|
_debugActiveLayout = this;
|
|
if (D.debugPrintLayouts) {
|
|
Debug.Log("Laying out (without resize) " + this);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
try {
|
|
performLayout();
|
|
}
|
|
catch (Exception ex) {
|
|
_debugReportException("performLayout", ex);
|
|
}
|
|
|
|
D.assert(() => {
|
|
_debugActiveLayout = debugPreviousActiveLayout;
|
|
_debugDoingThisLayout = false;
|
|
_debugMutationsLocked = false;
|
|
return true;
|
|
});
|
|
|
|
_needsLayout = false;
|
|
markNeedsPaint();
|
|
}
|
|
|
|
public void layout(Constraints constraints, bool parentUsesSize = false) {
|
|
D.assert(constraints != null);
|
|
D.assert(
|
|
() => {
|
|
IEnumerable<DiagnosticsNode> infoCollector() {
|
|
yield return new ErrorDescription(
|
|
$"These invalid constraints were provided to {GetType()}'s layout() " +
|
|
"function by the following function, which probably computed the " +
|
|
"invalid constraints in question:\n" +
|
|
" unknown");
|
|
}
|
|
return constraints.debugAssertIsValid(
|
|
isAppliedConstraint: true,
|
|
informationCollector: infoCollector);
|
|
}
|
|
);
|
|
D.assert(!_debugDoingThisResize);
|
|
D.assert(!_debugDoingThisLayout);
|
|
|
|
RenderObject relayoutBoundary;
|
|
if (!parentUsesSize || sizedByParent || constraints.isTight || !(parent is RenderObject)) {
|
|
relayoutBoundary = this;
|
|
}
|
|
else {
|
|
relayoutBoundary = (parent as RenderObject)._relayoutBoundary;
|
|
}
|
|
|
|
D.assert(() => {
|
|
_debugCanParentUseSize = parentUsesSize;
|
|
return true;
|
|
});
|
|
|
|
if (!_needsLayout && Equals(constraints, _constraints) &&
|
|
relayoutBoundary == _relayoutBoundary) {
|
|
D.assert(() => {
|
|
_debugDoingThisResize = sizedByParent;
|
|
_debugDoingThisLayout = !sizedByParent;
|
|
RenderObject debugPreviousActiveLayout1 = _debugActiveLayout;
|
|
_debugActiveLayout = this;
|
|
debugResetSize();
|
|
_debugActiveLayout = debugPreviousActiveLayout1;
|
|
_debugDoingThisLayout = false;
|
|
_debugDoingThisResize = false;
|
|
return true;
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
_constraints = constraints;
|
|
if (_relayoutBoundary != null && relayoutBoundary != _relayoutBoundary) {
|
|
visitChildren(_cleanChildRelayoutBoundary);
|
|
}
|
|
_relayoutBoundary = relayoutBoundary;
|
|
|
|
D.assert(!_debugMutationsLocked);
|
|
D.assert(!_doingThisLayoutWithCallback);
|
|
D.assert(() => {
|
|
_debugMutationsLocked = true;
|
|
if (D.debugPrintLayouts) {
|
|
Debug.Log("Laying out (" + (sizedByParent ? "with separate resize" : "with resize allowed") +
|
|
") " + this);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
if (sizedByParent) {
|
|
D.assert(() => {
|
|
_debugDoingThisResize = true;
|
|
return true;
|
|
});
|
|
|
|
try {
|
|
performResize();
|
|
D.assert(() => {
|
|
debugAssertDoesMeetConstraints();
|
|
return true;
|
|
});
|
|
}
|
|
catch (Exception ex) {
|
|
_debugReportException("performResize", ex);
|
|
}
|
|
|
|
D.assert(() => {
|
|
_debugDoingThisResize = false;
|
|
return true;
|
|
});
|
|
}
|
|
|
|
RenderObject debugPreviousActiveLayout = null;
|
|
D.assert(() => {
|
|
_debugDoingThisLayout = true;
|
|
debugPreviousActiveLayout = _debugActiveLayout;
|
|
_debugActiveLayout = this;
|
|
return true;
|
|
});
|
|
|
|
try {
|
|
performLayout();
|
|
D.assert(() => {
|
|
debugAssertDoesMeetConstraints();
|
|
return true;
|
|
});
|
|
}
|
|
catch (Exception ex) {
|
|
_debugReportException("performLayout", ex);
|
|
}
|
|
|
|
D.assert(() => {
|
|
_debugActiveLayout = debugPreviousActiveLayout;
|
|
_debugDoingThisLayout = false;
|
|
_debugMutationsLocked = false;
|
|
return true;
|
|
});
|
|
|
|
_needsLayout = false;
|
|
markNeedsPaint();
|
|
}
|
|
|
|
protected virtual void debugResetSize() {
|
|
}
|
|
|
|
protected virtual bool sizedByParent {
|
|
get { return false; }
|
|
}
|
|
|
|
protected abstract void performResize();
|
|
|
|
protected abstract void performLayout();
|
|
|
|
protected void invokeLayoutCallback<T>(LayoutCallback<T> callback) where T : Constraints {
|
|
D.assert(_debugMutationsLocked);
|
|
D.assert(_debugDoingThisLayout);
|
|
D.assert(!_doingThisLayoutWithCallback);
|
|
|
|
_doingThisLayoutWithCallback = true;
|
|
try {
|
|
owner._enableMutationsToDirtySubtrees(() => { callback((T) constraints); });
|
|
}
|
|
finally {
|
|
_doingThisLayoutWithCallback = false;
|
|
}
|
|
}
|
|
|
|
/// Rotate this render object (not yet implemented).
|
|
void rotate(
|
|
int oldAngle, // 0..3
|
|
int newAngle, // 0..3
|
|
TimeSpan time
|
|
) { }
|
|
|
|
public bool debugDoingThisPaint {
|
|
get { return _debugDoingThisPaint; }
|
|
}
|
|
|
|
bool _debugDoingThisPaint = false;
|
|
|
|
public static RenderObject debugActivePaint {
|
|
get { return _debugActivePaint; }
|
|
}
|
|
|
|
static RenderObject _debugActivePaint;
|
|
|
|
public virtual bool isRepaintBoundary {
|
|
get { return false; }
|
|
}
|
|
|
|
public virtual void debugRegisterRepaintBoundaryPaint(bool includedParent = true, bool includedChild = false) {
|
|
}
|
|
|
|
protected virtual bool alwaysNeedsCompositing {
|
|
get { return false; }
|
|
}
|
|
|
|
internal ContainerLayer _layer;
|
|
|
|
public ContainerLayer layer {
|
|
get {
|
|
D.assert(!isRepaintBoundary || (_layer == null || _layer is OffsetLayer));
|
|
return _layer;
|
|
}
|
|
set {
|
|
D.assert(
|
|
!isRepaintBoundary,
|
|
() => "Attempted to set a layer to a repaint boundary render object.\n" +
|
|
"The framework creates and assigns an OffsetLayer to a repaint " +
|
|
"boundary automatically."
|
|
);
|
|
_layer = value;
|
|
}
|
|
}
|
|
|
|
public ContainerLayer debugLayer {
|
|
get {
|
|
ContainerLayer result = null;
|
|
D.assert(() => {
|
|
result = _layer;
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|
|
internal bool _needsCompositingBitsUpdate = false;
|
|
|
|
public void markNeedsCompositingBitsUpdate() {
|
|
if (_needsCompositingBitsUpdate) {
|
|
return;
|
|
}
|
|
|
|
_needsCompositingBitsUpdate = true;
|
|
|
|
if (this.parent is RenderObject) {
|
|
var parent = (RenderObject) this.parent;
|
|
if (parent._needsCompositingBitsUpdate) {
|
|
return;
|
|
}
|
|
|
|
if (!isRepaintBoundary && !parent.isRepaintBoundary) {
|
|
parent.markNeedsCompositingBitsUpdate();
|
|
return;
|
|
}
|
|
}
|
|
|
|
D.assert(() => {
|
|
var parent = this.parent;
|
|
if (parent is RenderObject) {
|
|
return ((RenderObject) parent)._needsCompositing;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
if (owner != null) {
|
|
owner._nodesNeedingCompositingBitsUpdate.Add(this);
|
|
}
|
|
}
|
|
|
|
bool _needsCompositing;
|
|
|
|
public bool needsCompositing {
|
|
get {
|
|
D.assert(!_needsCompositingBitsUpdate);
|
|
return _needsCompositing;
|
|
}
|
|
}
|
|
|
|
public void _updateCompositingBits() {
|
|
if (!_needsCompositingBitsUpdate) {
|
|
return;
|
|
}
|
|
|
|
bool oldNeedsCompositing = _needsCompositing;
|
|
_needsCompositing = false;
|
|
visitChildren(child => {
|
|
child._updateCompositingBits();
|
|
if (child.needsCompositing) {
|
|
_needsCompositing = true;
|
|
}
|
|
});
|
|
|
|
if (isRepaintBoundary || alwaysNeedsCompositing) {
|
|
_needsCompositing = true;
|
|
}
|
|
|
|
if (oldNeedsCompositing != _needsCompositing) {
|
|
markNeedsPaint();
|
|
}
|
|
|
|
_needsCompositingBitsUpdate = false;
|
|
}
|
|
|
|
public bool debugNeedsPaint {
|
|
get {
|
|
bool result = false;
|
|
D.assert(() => {
|
|
result = _needsPaint;
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|
|
internal bool _needsPaint = true;
|
|
|
|
public void markNeedsPaint() {
|
|
D.assert(owner == null || !owner.debugDoingPaint);
|
|
|
|
if (_needsPaint) {
|
|
return;
|
|
}
|
|
|
|
_needsPaint = true;
|
|
if (isRepaintBoundary) {
|
|
D.assert(() => {
|
|
if (D.debugPrintMarkNeedsPaintStacks) {
|
|
Debug.Log("markNeedsPaint() called for " + this);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
D.assert(_layer is OffsetLayer);
|
|
|
|
if (owner != null) {
|
|
owner._nodesNeedingPaint.Add(this);
|
|
owner.requestVisualUpdate();
|
|
}
|
|
}
|
|
else if (this.parent is RenderObject) {
|
|
RenderObject parent = this.parent as RenderObject;
|
|
parent.markNeedsPaint();
|
|
D.assert(parent == this.parent);
|
|
}
|
|
else {
|
|
D.assert(() => {
|
|
if (D.debugPrintMarkNeedsPaintStacks) {
|
|
Debug.Log("markNeedsPaint() called for " + this + " (root of render tree)");
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
if (owner != null) {
|
|
owner.requestVisualUpdate();
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void _skippedPaintingOnLayer() {
|
|
D.assert(attached);
|
|
D.assert(isRepaintBoundary);
|
|
D.assert(_needsPaint);
|
|
D.assert(_layer != null);
|
|
D.assert(!_layer.attached);
|
|
|
|
var ancestor = parent;
|
|
while (ancestor is RenderObject) {
|
|
var node = (RenderObject) ancestor;
|
|
if (node.isRepaintBoundary) {
|
|
if (node._layer == null) {
|
|
break;
|
|
}
|
|
|
|
if (node._layer.attached) {
|
|
break;
|
|
}
|
|
|
|
node._needsPaint = true;
|
|
}
|
|
|
|
ancestor = ancestor.parent;
|
|
}
|
|
}
|
|
|
|
public void scheduleInitialPaint(ContainerLayer rootLayer) {
|
|
D.assert(rootLayer.attached);
|
|
D.assert(attached);
|
|
D.assert(!(parent is RenderObject));
|
|
D.assert(!owner._debugDoingPaint);
|
|
D.assert(isRepaintBoundary);
|
|
D.assert(_layer == null);
|
|
|
|
_layer = (OffsetLayer) rootLayer;
|
|
D.assert(_needsPaint);
|
|
owner._nodesNeedingPaint.Add(this);
|
|
}
|
|
|
|
public void replaceRootLayer(OffsetLayer rootLayer) {
|
|
D.assert(rootLayer.attached);
|
|
D.assert(attached);
|
|
D.assert(!(parent is RenderObject));
|
|
D.assert(!owner._debugDoingPaint);
|
|
D.assert(isRepaintBoundary);
|
|
D.assert(_layer != null);
|
|
|
|
|
|
_layer.detach();
|
|
_layer = rootLayer;
|
|
markNeedsPaint();
|
|
}
|
|
|
|
internal void _paintWithContext(PaintingContext context, Offset offset) {
|
|
D.assert(() => {
|
|
if (_debugDoingThisPaint) {
|
|
throw new UIWidgetsError(new List<DiagnosticsNode>{
|
|
new ErrorSummary("Tried to paint a RenderObject reentrantly."),
|
|
describeForError(
|
|
"The following RenderObject was already being painted when it was " +
|
|
"painted again"
|
|
),
|
|
new ErrorDescription(
|
|
"Since this typically indicates an infinite recursion, it is " +
|
|
"disallowed."
|
|
)
|
|
});
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
if (_needsLayout) {
|
|
return;
|
|
}
|
|
|
|
D.assert(() => {
|
|
if (_needsCompositingBitsUpdate) {
|
|
throw new UIWidgetsError(new List<DiagnosticsNode>{
|
|
new ErrorSummary(
|
|
"Tried to paint a RenderObject before its compositing bits were " +
|
|
"updated."
|
|
),
|
|
describeForError(
|
|
"The following RenderObject was marked as having dirty compositing " +
|
|
"bits at the time that it was painted"
|
|
),
|
|
new ErrorDescription(
|
|
"A RenderObject that still has dirty compositing bits cannot be " +
|
|
"painted because this indicates that the tree has not yet been " +
|
|
"properly configured for creating the layer tree."
|
|
),
|
|
new ErrorHint(
|
|
"This usually indicates an error in the Flutter framework itself."
|
|
)
|
|
});
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
RenderObject debugLastActivePaint = null;
|
|
D.assert(() => {
|
|
_debugDoingThisPaint = true;
|
|
debugLastActivePaint = _debugActivePaint;
|
|
_debugActivePaint = this;
|
|
D.assert(!isRepaintBoundary || _layer != null);
|
|
return true;
|
|
});
|
|
|
|
_needsPaint = false;
|
|
try {
|
|
paint(context, offset);
|
|
D.assert(!_needsLayout);
|
|
D.assert(!_needsPaint);
|
|
}
|
|
catch (Exception ex) {
|
|
_debugReportException("paint", ex);
|
|
}
|
|
|
|
D.assert(() => {
|
|
debugPaint(context, offset);
|
|
_debugActivePaint = debugLastActivePaint;
|
|
_debugDoingThisPaint = false;
|
|
return true;
|
|
});
|
|
}
|
|
|
|
public abstract Rect paintBounds { get; }
|
|
|
|
public virtual void debugPaint(PaintingContext context, Offset offset) {
|
|
}
|
|
|
|
public virtual void paint(PaintingContext context, Offset offset) {
|
|
}
|
|
|
|
public virtual void applyPaintTransform(RenderObject child, Matrix4 transform) {
|
|
D.assert(child.parent == this);
|
|
}
|
|
|
|
public Matrix4 getTransformTo(RenderObject ancestor) {
|
|
bool ancestorSpecified = ancestor != null;
|
|
D.assert(attached);
|
|
|
|
if (ancestor == null) {
|
|
var rootNode = owner.rootNode;
|
|
if (rootNode is RenderObject) {
|
|
ancestor = (RenderObject) rootNode;
|
|
}
|
|
}
|
|
|
|
var renderers = new List<RenderObject>();
|
|
for (RenderObject renderer = this; renderer != ancestor; renderer = (RenderObject) renderer.parent) {
|
|
D.assert(renderer != null);
|
|
renderers.Add(renderer);
|
|
}
|
|
if (ancestorSpecified)
|
|
renderers.Add(ancestor);
|
|
var transform = Matrix4.identity();
|
|
for (int index = renderers.Count - 1; index > 0; index -= 1) {
|
|
renderers[index].applyPaintTransform(renderers[index - 1], transform);
|
|
}
|
|
|
|
return transform;
|
|
}
|
|
|
|
public virtual Rect describeApproximatePaintClip(RenderObject child) {
|
|
return null;
|
|
}
|
|
|
|
public abstract Rect semanticBounds { get; }
|
|
|
|
public virtual void handleEvent(PointerEvent evt, HitTestEntry entry) {
|
|
}
|
|
|
|
public override string toStringShort() {
|
|
string header = foundation_.describeIdentity(this);
|
|
if (_relayoutBoundary != null && _relayoutBoundary != this) {
|
|
int count = 1;
|
|
RenderObject target = (RenderObject) parent;
|
|
while (target != null && target != _relayoutBoundary) {
|
|
target = (RenderObject) target.parent;
|
|
count += 1;
|
|
}
|
|
|
|
header += " relayoutBoundary=up" + count;
|
|
}
|
|
|
|
if (_needsLayout) {
|
|
header += " NEEDS-LAYOUT";
|
|
}
|
|
|
|
if (_needsPaint) {
|
|
header += " NEEDS-PAINT";
|
|
}
|
|
|
|
if (_needsCompositingBitsUpdate)
|
|
header += " NEEDS-COMPOSITING-BITS-UPDATE";
|
|
|
|
if (!attached) {
|
|
header += " DETACHED";
|
|
}
|
|
|
|
return header;
|
|
}
|
|
|
|
public override string toString(DiagnosticLevel minLevel = DiagnosticLevel.info) {
|
|
return toStringShort();
|
|
}
|
|
|
|
public override string toStringDeep(
|
|
string prefixLineOne = "",
|
|
string prefixOtherLines = "",
|
|
DiagnosticLevel minLevel = DiagnosticLevel.debug
|
|
) {
|
|
RenderObject debugPreviousActiveLayout = null;
|
|
D.assert(() => {
|
|
debugPreviousActiveLayout = _debugActiveLayout;
|
|
_debugActiveLayout = null;
|
|
return true;
|
|
});
|
|
string result = base.toStringDeep(
|
|
prefixLineOne: prefixLineOne,
|
|
prefixOtherLines: prefixOtherLines,
|
|
minLevel: minLevel
|
|
);
|
|
D.assert(() => {
|
|
_debugActiveLayout = debugPreviousActiveLayout;
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public override string toStringShallow(
|
|
string joiner = ", ",
|
|
DiagnosticLevel minLevel = DiagnosticLevel.debug
|
|
) {
|
|
RenderObject debugPreviousActiveLayout = null;
|
|
D.assert(() => {
|
|
debugPreviousActiveLayout = _debugActiveLayout;
|
|
_debugActiveLayout = null;
|
|
return true;
|
|
});
|
|
string result = base.toStringShallow(joiner: joiner, minLevel: minLevel);
|
|
D.assert(() => {
|
|
_debugActiveLayout = debugPreviousActiveLayout;
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
|
base.debugFillProperties(properties);
|
|
properties.add(new FlagProperty("needsCompositing", value: _needsCompositing, ifTrue: "needs compositing"));
|
|
properties.add(new DiagnosticsProperty<object>(
|
|
"creator", debugCreator, defaultValue: foundation_.kNullDefaultValue,
|
|
level: DiagnosticLevel.debug));
|
|
properties.add(new DiagnosticsProperty<ParentData>("parentData", parentData,
|
|
tooltip: _debugCanParentUseSize ? "can use size" : null, missingIfNull: true));
|
|
properties.add(new DiagnosticsProperty<Constraints>("constraints", constraints, missingIfNull: true));
|
|
properties.add(new DiagnosticsProperty<ContainerLayer>("layer", _layer,
|
|
defaultValue: foundation_.kNullDefaultValue));
|
|
}
|
|
|
|
public override List<DiagnosticsNode> debugDescribeChildren() => new List<DiagnosticsNode>();
|
|
|
|
public virtual void showOnScreen(
|
|
RenderObject descendant = null,
|
|
Rect rect = null,
|
|
TimeSpan? duration = null,
|
|
Curve curve = null
|
|
) {
|
|
duration = duration ?? TimeSpan.Zero;
|
|
curve = curve ?? Curves.ease;
|
|
|
|
if (parent is RenderObject) {
|
|
RenderObject renderParent = (RenderObject) parent;
|
|
renderParent.showOnScreen(
|
|
descendant: descendant ?? this,
|
|
rect: rect,
|
|
duration: duration,
|
|
curve: curve
|
|
);
|
|
}
|
|
}
|
|
public DiagnosticsNode describeForError(string name, DiagnosticsTreeStyle style = DiagnosticsTreeStyle.shallow) {
|
|
return toDiagnosticsNode(name: name, style: style);
|
|
}
|
|
}
|
|
|
|
public interface RenderObjectWithChildMixin {
|
|
bool debugValidateChild(RenderObject child);
|
|
RenderObject child { get; set; }
|
|
}
|
|
|
|
public interface RenderObjectWithChildMixin<ChildType> : RenderObjectWithChildMixin where ChildType : RenderObject {
|
|
ChildType child { get; set; }
|
|
}
|
|
|
|
public interface ContainerParentDataMixin<ChildType> : IParentData where ChildType : RenderObject {
|
|
ChildType previousSibling { get; set; }
|
|
ChildType nextSibling { get; set; }
|
|
}
|
|
|
|
public interface ContainerRenderObjectMixin {
|
|
int childCount { get; }
|
|
bool debugValidateChild(RenderObject child);
|
|
void insert(RenderObject child, RenderObject after = null);
|
|
void remove(RenderObject child);
|
|
void move(RenderObject child, RenderObject after = null);
|
|
RenderObject firstChild { get; }
|
|
RenderObject lastChild { get; }
|
|
RenderObject childBefore(RenderObject child);
|
|
RenderObject childAfter(RenderObject child);
|
|
}
|
|
|
|
public interface RelayoutWhenSystemFontsChangeMixin {
|
|
void systemFontsDidChange();
|
|
void attach(object owner);
|
|
void detach();
|
|
}
|
|
|
|
public class UIWidgetsErrorDetailsForRendering : UIWidgetsErrorDetails {
|
|
public UIWidgetsErrorDetailsForRendering(
|
|
Exception exception = null,
|
|
StackTrace stack = null,
|
|
string library = null,
|
|
DiagnosticsNode context = null,
|
|
RenderObject renderObject = null,
|
|
InformationCollector informationCollector = null,
|
|
bool silent = false
|
|
) : base(
|
|
exception: exception,
|
|
library: library,
|
|
context: context,
|
|
informationCollector: informationCollector,
|
|
silent: silent
|
|
) {
|
|
this.renderObject = renderObject;
|
|
}
|
|
|
|
public readonly RenderObject renderObject;
|
|
}
|
|
|
|
public class DiagnosticsDebugCreator : DiagnosticsProperty<object> {
|
|
public DiagnosticsDebugCreator(object value)
|
|
: base(
|
|
"debugCreator",
|
|
value,
|
|
level: DiagnosticLevel.hidden
|
|
) {
|
|
D.assert(value != null);
|
|
}
|
|
}
|
|
}
|