1// Copyright 2015 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'dart:developer'; 6import 'dart:ui' as ui show PictureRecorder; 7 8import 'package:flutter/animation.dart'; 9import 'package:flutter/foundation.dart'; 10import 'package:flutter/gestures.dart'; 11import 'package:flutter/painting.dart'; 12import 'package:flutter/semantics.dart'; 13import 'package:vector_math/vector_math_64.dart'; 14 15import 'binding.dart'; 16import 'debug.dart'; 17import 'layer.dart'; 18 19export 'package:flutter/foundation.dart' show FlutterError, InformationCollector, DiagnosticsNode, ErrorSummary, ErrorDescription, ErrorHint, DiagnosticsProperty, StringProperty, DoubleProperty, EnumProperty, FlagProperty, IntProperty, DiagnosticPropertiesBuilder; 20export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult; 21export 'package:flutter/painting.dart'; 22 23/// Base class for data associated with a [RenderObject] by its parent. 24/// 25/// Some render objects wish to store data on their children, such as their 26/// input parameters to the parent's layout algorithm or their position relative 27/// to other children. 28class ParentData { 29 /// Called when the RenderObject is removed from the tree. 30 @protected 31 @mustCallSuper 32 void detach() { } 33 34 @override 35 String toString() => '<none>'; 36} 37 38/// Signature for painting into a [PaintingContext]. 39/// 40/// The `offset` argument is the offset from the origin of the coordinate system 41/// of the [PaintingContext.canvas] to the coordinate system of the callee. 42/// 43/// Used by many of the methods of [PaintingContext]. 44typedef PaintingContextCallback = void Function(PaintingContext context, Offset offset); 45 46/// A place to paint. 47/// 48/// Rather than holding a canvas directly, [RenderObject]s paint using a painting 49/// context. The painting context has a [Canvas], which receives the 50/// individual draw operations, and also has functions for painting child 51/// render objects. 52/// 53/// When painting a child render object, the canvas held by the painting context 54/// can change because the draw operations issued before and after painting the 55/// child might be recorded in separate compositing layers. For this reason, do 56/// not hold a reference to the canvas across operations that might paint 57/// child render objects. 58/// 59/// New [PaintingContext] objects are created automatically when using 60/// [PaintingContext.repaintCompositedChild] and [pushLayer]. 61class PaintingContext extends ClipContext { 62 63 /// Creates a painting context. 64 /// 65 /// Typically only called by [PaintingContext.repaintCompositedChild] 66 /// and [pushLayer]. 67 @protected 68 PaintingContext(this._containerLayer, this.estimatedBounds) 69 : assert(_containerLayer != null), 70 assert(estimatedBounds != null); 71 72 final ContainerLayer _containerLayer; 73 74 /// An estimate of the bounds within which the painting context's [canvas] 75 /// will record painting commands. This can be useful for debugging. 76 /// 77 /// The canvas will allow painting outside these bounds. 78 /// 79 /// The [estimatedBounds] rectangle is in the [canvas] coordinate system. 80 final Rect estimatedBounds; 81 82 /// Repaint the given render object. 83 /// 84 /// The render object must be attached to a [PipelineOwner], must have a 85 /// composited layer, and must be in need of painting. The render object's 86 /// layer, if any, is re-used, along with any layers in the subtree that don't 87 /// need to be repainted. 88 /// 89 /// See also: 90 /// 91 /// * [RenderObject.isRepaintBoundary], which determines if a [RenderObject] 92 /// has a composited layer. 93 static void repaintCompositedChild(RenderObject child, { bool debugAlsoPaintedParent = false }) { 94 assert(child._needsPaint); 95 _repaintCompositedChild( 96 child, 97 debugAlsoPaintedParent: debugAlsoPaintedParent, 98 ); 99 } 100 101 static void _repaintCompositedChild( 102 RenderObject child, { 103 bool debugAlsoPaintedParent = false, 104 PaintingContext childContext, 105 }) { 106 assert(child.isRepaintBoundary); 107 assert(() { 108 // register the call for RepaintBoundary metrics 109 child.debugRegisterRepaintBoundaryPaint( 110 includedParent: debugAlsoPaintedParent, 111 includedChild: true, 112 ); 113 return true; 114 }()); 115 OffsetLayer childLayer = child._layer; 116 if (childLayer == null) { 117 assert(debugAlsoPaintedParent); 118 // Not using the `layer` setter because the setter asserts that we not 119 // replace the layer for repaint boundaries. That assertion does not 120 // apply here because this is exactly the place designed to create a 121 // layer for repaint boundaries. 122 child._layer = childLayer = OffsetLayer(); 123 } else { 124 assert(childLayer is OffsetLayer); 125 assert(debugAlsoPaintedParent || childLayer.attached); 126 childLayer.removeAllChildren(); 127 } 128 assert(identical(childLayer, child._layer)); 129 assert(child._layer is OffsetLayer); 130 assert(() { 131 child._layer.debugCreator = child.debugCreator ?? child.runtimeType; 132 return true; 133 }()); 134 childContext ??= PaintingContext(child._layer, child.paintBounds); 135 child._paintWithContext(childContext, Offset.zero); 136 137 // Double-check that the paint method did not replace the layer (the first 138 // check is done in the [layer] setter itself). 139 assert(identical(childLayer, child._layer)); 140 childContext.stopRecordingIfNeeded(); 141 } 142 143 /// In debug mode, repaint the given render object using a custom painting 144 /// context that can record the results of the painting operation in addition 145 /// to performing the regular paint of the child. 146 /// 147 /// See also: 148 /// 149 /// * [repaintCompositedChild], for repainting a composited child without 150 /// instrumentation. 151 static void debugInstrumentRepaintCompositedChild( 152 RenderObject child, { 153 bool debugAlsoPaintedParent = false, 154 @required PaintingContext customContext, 155 }) { 156 assert(() { 157 _repaintCompositedChild( 158 child, 159 debugAlsoPaintedParent: debugAlsoPaintedParent, 160 childContext: customContext, 161 ); 162 return true; 163 }()); 164 } 165 166 /// Paint a child [RenderObject]. 167 /// 168 /// If the child has its own composited layer, the child will be composited 169 /// into the layer subtree associated with this painting context. Otherwise, 170 /// the child will be painted into the current PictureLayer for this context. 171 void paintChild(RenderObject child, Offset offset) { 172 assert(() { 173 if (debugProfilePaintsEnabled) 174 Timeline.startSync('${child.runtimeType}', arguments: timelineWhitelistArguments); 175 if (debugOnProfilePaint != null) 176 debugOnProfilePaint(child); 177 return true; 178 }()); 179 180 if (child.isRepaintBoundary) { 181 stopRecordingIfNeeded(); 182 _compositeChild(child, offset); 183 } else { 184 child._paintWithContext(this, offset); 185 } 186 187 assert(() { 188 if (debugProfilePaintsEnabled) 189 Timeline.finishSync(); 190 return true; 191 }()); 192 } 193 194 void _compositeChild(RenderObject child, Offset offset) { 195 assert(!_isRecording); 196 assert(child.isRepaintBoundary); 197 assert(_canvas == null || _canvas.getSaveCount() == 1); 198 199 // Create a layer for our child, and paint the child into it. 200 if (child._needsPaint) { 201 repaintCompositedChild(child, debugAlsoPaintedParent: true); 202 } else { 203 assert(() { 204 // register the call for RepaintBoundary metrics 205 child.debugRegisterRepaintBoundaryPaint( 206 includedParent: true, 207 includedChild: false, 208 ); 209 child._layer.debugCreator = child.debugCreator ?? child; 210 return true; 211 }()); 212 } 213 assert(child._layer is OffsetLayer); 214 final OffsetLayer childOffsetLayer = child._layer; 215 childOffsetLayer.offset = offset; 216 appendLayer(child._layer); 217 } 218 219 /// Adds a layer to the recording requiring that the recording is already 220 /// stopped. 221 /// 222 /// Do not call this function directly: call [addLayer] or [pushLayer] 223 /// instead. This function is called internally when all layers not 224 /// generated from the [canvas] are added. 225 /// 226 /// Subclasses that need to customize how layers are added should override 227 /// this method. 228 @protected 229 void appendLayer(Layer layer) { 230 assert(!_isRecording); 231 layer.remove(); 232 _containerLayer.append(layer); 233 } 234 235 bool get _isRecording { 236 final bool hasCanvas = _canvas != null; 237 assert(() { 238 if (hasCanvas) { 239 assert(_currentLayer != null); 240 assert(_recorder != null); 241 assert(_canvas != null); 242 } else { 243 assert(_currentLayer == null); 244 assert(_recorder == null); 245 assert(_canvas == null); 246 } 247 return true; 248 }()); 249 return hasCanvas; 250 } 251 252 // Recording state 253 PictureLayer _currentLayer; 254 ui.PictureRecorder _recorder; 255 Canvas _canvas; 256 257 /// The canvas on which to paint. 258 /// 259 /// The current canvas can change whenever you paint a child using this 260 /// context, which means it's fragile to hold a reference to the canvas 261 /// returned by this getter. 262 @override 263 Canvas get canvas { 264 if (_canvas == null) 265 _startRecording(); 266 return _canvas; 267 } 268 269 void _startRecording() { 270 assert(!_isRecording); 271 _currentLayer = PictureLayer(estimatedBounds); 272 _recorder = ui.PictureRecorder(); 273 _canvas = Canvas(_recorder); 274 _containerLayer.append(_currentLayer); 275 } 276 277 /// Stop recording to a canvas if recording has started. 278 /// 279 /// Do not call this function directly: functions in this class will call 280 /// this method as needed. This function is called internally to ensure that 281 /// recording is stopped before adding layers or finalizing the results of a 282 /// paint. 283 /// 284 /// Subclasses that need to customize how recording to a canvas is performed 285 /// should override this method to save the results of the custom canvas 286 /// recordings. 287 @protected 288 @mustCallSuper 289 void stopRecordingIfNeeded() { 290 if (!_isRecording) 291 return; 292 assert(() { 293 if (debugRepaintRainbowEnabled) { 294 final Paint paint = Paint() 295 ..style = PaintingStyle.stroke 296 ..strokeWidth = 6.0 297 ..color = debugCurrentRepaintColor.toColor(); 298 canvas.drawRect(estimatedBounds.deflate(3.0), paint); 299 } 300 if (debugPaintLayerBordersEnabled) { 301 final Paint paint = Paint() 302 ..style = PaintingStyle.stroke 303 ..strokeWidth = 1.0 304 ..color = const Color(0xFFFF9800); 305 canvas.drawRect(estimatedBounds, paint); 306 } 307 return true; 308 }()); 309 _currentLayer.picture = _recorder.endRecording(); 310 _currentLayer = null; 311 _recorder = null; 312 _canvas = null; 313 } 314 315 /// Hints that the painting in the current layer is complex and would benefit 316 /// from caching. 317 /// 318 /// If this hint is not set, the compositor will apply its own heuristics to 319 /// decide whether the current layer is complex enough to benefit from 320 /// caching. 321 void setIsComplexHint() { 322 _currentLayer?.isComplexHint = true; 323 } 324 325 /// Hints that the painting in the current layer is likely to change next frame. 326 /// 327 /// This hint tells the compositor not to cache the current layer because the 328 /// cache will not be used in the future. If this hint is not set, the 329 /// compositor will apply its own heuristics to decide whether the current 330 /// layer is likely to be reused in the future. 331 void setWillChangeHint() { 332 _currentLayer?.willChangeHint = true; 333 } 334 335 /// Adds a composited leaf layer to the recording. 336 /// 337 /// After calling this function, the [canvas] property will change to refer to 338 /// a new [Canvas] that draws on top of the given layer. 339 /// 340 /// A [RenderObject] that uses this function is very likely to require its 341 /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs 342 /// ancestor render objects that this render object will include a composited 343 /// layer, which, for example, causes them to use composited clips. 344 /// 345 /// See also: 346 /// 347 /// * [pushLayer], for adding a layer and using its canvas to paint with that 348 /// layer. 349 void addLayer(Layer layer) { 350 stopRecordingIfNeeded(); 351 appendLayer(layer); 352 } 353 354 /// Appends the given layer to the recording, and calls the `painter` callback 355 /// with that layer, providing the `childPaintBounds` as the estimated paint 356 /// bounds of the child. The `childPaintBounds` can be used for debugging but 357 /// have no effect on painting. 358 /// 359 /// The given layer must be an unattached orphan. (Providing a newly created 360 /// object, rather than reusing an existing layer, satisfies that 361 /// requirement.) 362 /// 363 /// The `offset` is the offset to pass to the `painter`. 364 /// 365 /// If the `childPaintBounds` are not specified then the current layer's paint 366 /// bounds are used. This is appropriate if the child layer does not apply any 367 /// transformation or clipping to its contents. The `childPaintBounds`, if 368 /// specified, must be in the coordinate system of the new layer, and should 369 /// not go outside the current layer's paint bounds. 370 /// 371 /// See also: 372 /// 373 /// * [addLayer], for pushing a leaf layer whose canvas is not used. 374 void pushLayer(ContainerLayer childLayer, PaintingContextCallback painter, Offset offset, { Rect childPaintBounds }) { 375 assert(painter != null); 376 // If a layer is being reused, it may already contain children. We remove 377 // them so that `painter` can add children that are relevant for this frame. 378 if (childLayer.hasChildren) { 379 childLayer.removeAllChildren(); 380 } 381 stopRecordingIfNeeded(); 382 appendLayer(childLayer); 383 final PaintingContext childContext = createChildContext(childLayer, childPaintBounds ?? estimatedBounds); 384 painter(childContext, offset); 385 childContext.stopRecordingIfNeeded(); 386 } 387 388 /// Creates a compatible painting context to paint onto [childLayer]. 389 @protected 390 PaintingContext createChildContext(ContainerLayer childLayer, Rect bounds) { 391 return PaintingContext(childLayer, bounds); 392 } 393 394 /// Clip further painting using a rectangle. 395 /// 396 /// {@template flutter.rendering.object.needsCompositing} 397 /// * `needsCompositing` is whether the child needs compositing. Typically 398 /// matches the value of [RenderObject.needsCompositing] for the caller. If 399 /// false, this method returns null, indicating that a layer is no longer 400 /// necessary. If a render object calling this method stores the `oldLayer` 401 /// in its [RenderObject.layer] field, it should set that field to null. 402 /// {@end template} 403 /// * `offset` is the offset from the origin of the canvas' coordinate system 404 /// to the origin of the caller's coordinate system. 405 /// * `clipRect` is rectangle (in the caller's coordinate system) to use to 406 /// clip the painting done by [painter]. 407 /// * `painter` is a callback that will paint with the [clipRect] applied. This 408 /// function calls the [painter] synchronously. 409 /// * `clipBehavior` controls how the rectangle is clipped. 410 /// {@template flutter.rendering.object.oldLayer} 411 /// * `oldLayer` is the layer created in the previous frame. Specifying the 412 /// old layer gives the engine more information for performance 413 /// optimizations. Typically this is the value of [RenderObject.layer] that 414 /// a render object creates once, then reuses for all subsequent frames 415 /// until a layer is no longer needed (e.g. the render object no longer 416 /// needs compositing) or until the render object changes the type of the 417 /// layer (e.g. from opacity layer to a clip rect layer). 418 /// {@end template} 419 ClipRectLayer pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter, { Clip clipBehavior = Clip.hardEdge, ClipRectLayer oldLayer }) { 420 final Rect offsetClipRect = clipRect.shift(offset); 421 if (needsCompositing) { 422 final ClipRectLayer layer = oldLayer ?? ClipRectLayer(); 423 layer 424 ..clipRect = offsetClipRect 425 ..clipBehavior = clipBehavior; 426 pushLayer(layer, painter, offset, childPaintBounds: offsetClipRect); 427 return layer; 428 } else { 429 clipRectAndPaint(offsetClipRect, clipBehavior, offsetClipRect, () => painter(this, offset)); 430 return null; 431 } 432 } 433 434 /// Clip further painting using a rounded rectangle. 435 /// 436 /// {@macro flutter.rendering.object.needsCompositing} 437 /// * `offset` is the offset from the origin of the canvas' coordinate system 438 /// to the origin of the caller's coordinate system. 439 /// * `bounds` is the region of the canvas (in the caller's coordinate system) 440 /// into which `painter` will paint in. 441 /// * `clipRRect` is the rounded-rectangle (in the caller's coordinate system) 442 /// to use to clip the painting done by `painter`. 443 /// * `painter` is a callback that will paint with the `clipRRect` applied. This 444 /// function calls the `painter` synchronously. 445 /// * `clipBehavior` controls how the path is clipped. 446 /// {@macro flutter.rendering.object.oldLayer} 447 ClipRRectLayer pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter, { Clip clipBehavior = Clip.antiAlias, ClipRRectLayer oldLayer }) { 448 assert(clipBehavior != null); 449 final Rect offsetBounds = bounds.shift(offset); 450 final RRect offsetClipRRect = clipRRect.shift(offset); 451 if (needsCompositing) { 452 final ClipRRectLayer layer = oldLayer ?? ClipRRectLayer(); 453 layer 454 ..clipRRect = offsetClipRRect 455 ..clipBehavior = clipBehavior; 456 pushLayer(layer, painter, offset, childPaintBounds: offsetBounds); 457 return layer; 458 } else { 459 clipRRectAndPaint(offsetClipRRect, clipBehavior, offsetBounds, () => painter(this, offset)); 460 return null; 461 } 462 } 463 464 /// Clip further painting using a path. 465 /// 466 /// {@macro flutter.rendering.object.needsCompositing} 467 /// * `offset` is the offset from the origin of the canvas' coordinate system 468 /// to the origin of the caller's coordinate system. 469 /// * `bounds` is the region of the canvas (in the caller's coordinate system) 470 /// into which `painter` will paint in. 471 /// * `clipPath` is the path (in the coordinate system of the caller) to use to 472 /// clip the painting done by `painter`. 473 /// * `painter` is a callback that will paint with the `clipPath` applied. This 474 /// function calls the `painter` synchronously. 475 /// * `clipBehavior` controls how the rounded rectangle is clipped. 476 /// {@macro flutter.rendering.object.oldLayer} 477 ClipPathLayer pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter, { Clip clipBehavior = Clip.antiAlias, ClipPathLayer oldLayer }) { 478 assert(clipBehavior != null); 479 final Rect offsetBounds = bounds.shift(offset); 480 final Path offsetClipPath = clipPath.shift(offset); 481 if (needsCompositing) { 482 final ClipPathLayer layer = oldLayer ?? ClipPathLayer(); 483 layer 484 ..clipPath = offsetClipPath 485 ..clipBehavior = clipBehavior; 486 pushLayer(layer, painter, offset, childPaintBounds: offsetBounds); 487 return layer; 488 } else { 489 clipPathAndPaint(offsetClipPath, clipBehavior, offsetBounds, () => painter(this, offset)); 490 return null; 491 } 492 } 493 494 /// Blend further painting with a color filter. 495 /// 496 /// * `offset` is the offset from the origin of the canvas' coordinate system 497 /// to the origin of the caller's coordinate system. 498 /// * `colorFilter` is the [ColorFilter] value to use when blending the 499 /// painting done by `painter`. 500 /// * `painter` is a callback that will paint with the `colorFilter` applied. 501 /// This function calls the `painter` synchronously. 502 /// {@macro flutter.rendering.object.oldLayer} 503 /// 504 /// A [RenderObject] that uses this function is very likely to require its 505 /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs 506 /// ancestor render objects that this render object will include a composited 507 /// layer, which, for example, causes them to use composited clips. 508 ColorFilterLayer pushColorFilter(Offset offset, ColorFilter colorFilter, PaintingContextCallback painter, { ColorFilterLayer oldLayer }) { 509 assert(colorFilter != null); 510 final ColorFilterLayer layer = oldLayer ?? ColorFilterLayer(); 511 layer.colorFilter = colorFilter; 512 pushLayer(layer, painter, offset); 513 return layer; 514 } 515 516 /// Transform further painting using a matrix. 517 /// 518 /// {@macro flutter.rendering.object.needsCompositing} 519 /// * `offset` is the offset from the origin of the canvas' coordinate system 520 /// to the origin of the caller's coordinate system. 521 /// * `transform` is the matrix to apply to the painting done by `painter`. 522 /// * `painter` is a callback that will paint with the `transform` applied. This 523 /// function calls the `painter` synchronously. 524 /// {@macro flutter.rendering.object.oldLayer} 525 TransformLayer pushTransform(bool needsCompositing, Offset offset, Matrix4 transform, PaintingContextCallback painter, { TransformLayer oldLayer }) { 526 final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0) 527 ..multiply(transform)..translate(-offset.dx, -offset.dy); 528 if (needsCompositing) { 529 final TransformLayer layer = oldLayer ?? TransformLayer(); 530 layer.transform = effectiveTransform; 531 pushLayer( 532 layer, 533 painter, 534 offset, 535 childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, estimatedBounds), 536 ); 537 return layer; 538 } else { 539 canvas 540 ..save() 541 ..transform(effectiveTransform.storage); 542 painter(this, offset); 543 canvas 544 ..restore(); 545 return null; 546 } 547 } 548 549 /// Blend further painting with an alpha value. 550 /// 551 /// * `offset` is the offset from the origin of the canvas' coordinate system 552 /// to the origin of the caller's coordinate system. 553 /// * `alpha` is the alpha value to use when blending the painting done by 554 /// `painter`. An alpha value of 0 means the painting is fully transparent 555 /// and an alpha value of 255 means the painting is fully opaque. 556 /// * `painter` is a callback that will paint with the `alpha` applied. This 557 /// function calls the `painter` synchronously. 558 /// {@macro flutter.rendering.object.oldLayer} 559 /// 560 /// A [RenderObject] that uses this function is very likely to require its 561 /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs 562 /// ancestor render objects that this render object will include a composited 563 /// layer, which, for example, causes them to use composited clips. 564 OpacityLayer pushOpacity(Offset offset, int alpha, PaintingContextCallback painter, { OpacityLayer oldLayer }) { 565 final OpacityLayer layer = oldLayer ?? OpacityLayer(); 566 layer 567 ..alpha = alpha 568 ..offset = offset; 569 pushLayer(layer, painter, Offset.zero); 570 return layer; 571 } 572 573 @override 574 String toString() => '$runtimeType#$hashCode(layer: $_containerLayer, canvas bounds: $estimatedBounds)'; 575} 576 577/// An abstract set of layout constraints. 578/// 579/// Concrete layout models (such as box) will create concrete subclasses to 580/// communicate layout constraints between parents and children. 581/// 582/// ## Writing a Constraints subclass 583/// 584/// When creating a new [RenderObject] subclass with a new layout protocol, one 585/// will usually need to create a new [Constraints] subclass to express the 586/// input to the layout algorithms. 587/// 588/// A [Constraints] subclass should be immutable (all fields final). There are 589/// several members to implement, in addition to whatever fields, constructors, 590/// and helper methods one may find useful for a particular layout protocol: 591/// 592/// * The [isTight] getter, which should return true if the object represents a 593/// case where the [RenderObject] class has no choice for how to lay itself 594/// out. For example, [BoxConstraints] returns true for [isTight] when both 595/// the minimum and maximum widths and the minimum and maximum heights are 596/// equal. 597/// 598/// * The [isNormalized] getter, which should return true if the object 599/// represents its data in its canonical form. Sometimes, it is possible for 600/// fields to be redundant with each other, such that several different 601/// representations have the same implications. For example, a 602/// [BoxConstraints] instance with its minimum width greater than its maximum 603/// width is equivalent to one where the maximum width is set to that minimum 604/// width (`2<w<1` is equivalent to `2<w<2`, since minimum constraints have 605/// priority). This getter is used by the default implementation of 606/// [debugAssertIsValid]. 607/// 608/// * The [debugAssertIsValid] method, which should assert if there's anything 609/// wrong with the constraints object. (We use this approach rather than 610/// asserting in constructors so that our constructors can be `const` and so 611/// that it is possible to create invalid constraints temporarily while 612/// building valid ones.) See the implementation of 613/// [BoxConstraints.debugAssertIsValid] for an example of the detailed checks 614/// that can be made. 615/// 616/// * The [==] operator and the [hashCode] getter, so that constraints can be 617/// compared for equality. If a render object is given constraints that are 618/// equal, then the rendering library will avoid laying the object out again 619/// if it is not dirty. 620/// 621/// * The [toString] method, which should describe the constraints so that they 622/// appear in a usefully readable form in the output of [debugDumpRenderTree]. 623@immutable 624abstract class Constraints { 625 /// Abstract const constructor. This constructor enables subclasses to provide 626 /// const constructors so that they can be used in const expressions. 627 const Constraints(); 628 629 /// Whether there is exactly one size possible given these constraints 630 bool get isTight; 631 632 /// Whether the constraint is expressed in a consistent manner. 633 bool get isNormalized; 634 635 /// Asserts that the constraints are valid. 636 /// 637 /// This might involve checks more detailed than [isNormalized]. 638 /// 639 /// For example, the [BoxConstraints] subclass verifies that the constraints 640 /// are not [double.nan]. 641 /// 642 /// If the `isAppliedConstraint` argument is true, then even stricter rules 643 /// are enforced. This argument is set to true when checking constraints that 644 /// are about to be applied to a [RenderObject] during layout, as opposed to 645 /// constraints that may be further affected by other constraints. For 646 /// example, the asserts for verifying the validity of 647 /// [RenderConstrainedBox.additionalConstraints] do not set this argument, but 648 /// the asserts for verifying the argument passed to the [RenderObject.layout] 649 /// method do. 650 /// 651 /// The `informationCollector` argument takes an optional callback which is 652 /// called when an exception is to be thrown. The collected information is 653 /// then included in the message after the error line. 654 /// 655 /// Returns the same as [isNormalized] if asserts are disabled. 656 bool debugAssertIsValid({ 657 bool isAppliedConstraint = false, 658 InformationCollector informationCollector, 659 }) { 660 assert(isNormalized); 661 return isNormalized; 662 } 663} 664 665/// Signature for a function that is called for each [RenderObject]. 666/// 667/// Used by [RenderObject.visitChildren] and [RenderObject.visitChildrenForSemantics]. 668typedef RenderObjectVisitor = void Function(RenderObject child); 669 670/// Signature for a function that is called during layout. 671/// 672/// Used by [RenderObject.invokeLayoutCallback]. 673typedef LayoutCallback<T extends Constraints> = void Function(T constraints); 674 675/// A reference to the semantics tree. 676/// 677/// The framework maintains the semantics tree (used for accessibility and 678/// indexing) only when there is at least one client holding an open 679/// [SemanticsHandle]. 680/// 681/// The framework notifies the client that it has updated the semantics tree by 682/// calling the [listener] callback. When the client no longer needs the 683/// semantics tree, the client can call [dispose] on the [SemanticsHandle], 684/// which stops these callbacks and closes the [SemanticsHandle]. When all the 685/// outstanding [SemanticsHandle] objects are closed, the framework stops 686/// updating the semantics tree. 687/// 688/// To obtain a [SemanticsHandle], call [PipelineOwner.ensureSemantics] on the 689/// [PipelineOwner] for the render tree from which you wish to read semantics. 690/// You can obtain the [PipelineOwner] using the [RenderObject.owner] property. 691class SemanticsHandle { 692 SemanticsHandle._(this._owner, this.listener) 693 : assert(_owner != null) { 694 if (listener != null) 695 _owner.semanticsOwner.addListener(listener); 696 } 697 698 PipelineOwner _owner; 699 700 /// The callback that will be notified when the semantics tree updates. 701 final VoidCallback listener; 702 703 /// Closes the semantics handle and stops calling [listener] when the 704 /// semantics updates. 705 /// 706 /// When all the outstanding [SemanticsHandle] objects for a given 707 /// [PipelineOwner] are closed, the [PipelineOwner] will stop updating the 708 /// semantics tree. 709 @mustCallSuper 710 void dispose() { 711 assert(() { 712 if (_owner == null) { 713 throw FlutterError( 714 'SemanticsHandle has already been disposed.\n' 715 'Each SemanticsHandle should be disposed exactly once.' 716 ); 717 } 718 return true; 719 }()); 720 if (_owner != null) { 721 if (listener != null) 722 _owner.semanticsOwner.removeListener(listener); 723 _owner._didDisposeSemanticsHandle(); 724 _owner = null; 725 } 726 } 727} 728 729/// The pipeline owner manages the rendering pipeline. 730/// 731/// The pipeline owner provides an interface for driving the rendering pipeline 732/// and stores the state about which render objects have requested to be visited 733/// in each stage of the pipeline. To flush the pipeline, call the following 734/// functions in order: 735/// 736/// 1. [flushLayout] updates any render objects that need to compute their 737/// layout. During this phase, the size and position of each render 738/// object is calculated. Render objects might dirty their painting or 739/// compositing state during this phase. 740/// 2. [flushCompositingBits] updates any render objects that have dirty 741/// compositing bits. During this phase, each render object learns whether 742/// any of its children require compositing. This information is used during 743/// the painting phase when selecting how to implement visual effects such as 744/// clipping. If a render object has a composited child, its needs to use a 745/// [Layer] to create the clip in order for the clip to apply to the 746/// composited child (which will be painted into its own [Layer]). 747/// 3. [flushPaint] visits any render objects that need to paint. During this 748/// phase, render objects get a chance to record painting commands into 749/// [PictureLayer]s and construct other composited [Layer]s. 750/// 4. Finally, if semantics are enabled, [flushSemantics] will compile the 751/// semantics for the render objects. This semantic information is used by 752/// assistive technology to improve the accessibility of the render tree. 753/// 754/// The [RendererBinding] holds the pipeline owner for the render objects that 755/// are visible on screen. You can create other pipeline owners to manage 756/// off-screen objects, which can flush their pipelines independently of the 757/// on-screen render objects. 758class PipelineOwner { 759 /// Creates a pipeline owner. 760 /// 761 /// Typically created by the binding (e.g., [RendererBinding]), but can be 762 /// created separately from the binding to drive off-screen render objects 763 /// through the rendering pipeline. 764 PipelineOwner({ 765 this.onNeedVisualUpdate, 766 this.onSemanticsOwnerCreated, 767 this.onSemanticsOwnerDisposed, 768 }); 769 770 /// Called when a render object associated with this pipeline owner wishes to 771 /// update its visual appearance. 772 /// 773 /// Typical implementations of this function will schedule a task to flush the 774 /// various stages of the pipeline. This function might be called multiple 775 /// times in quick succession. Implementations should take care to discard 776 /// duplicate calls quickly. 777 final VoidCallback onNeedVisualUpdate; 778 779 /// Called whenever this pipeline owner creates a semantics object. 780 /// 781 /// Typical implementations will schedule the creation of the initial 782 /// semantics tree. 783 final VoidCallback onSemanticsOwnerCreated; 784 785 /// Called whenever this pipeline owner disposes its semantics owner. 786 /// 787 /// Typical implementations will tear down the semantics tree. 788 final VoidCallback onSemanticsOwnerDisposed; 789 790 /// Calls [onNeedVisualUpdate] if [onNeedVisualUpdate] is not null. 791 /// 792 /// Used to notify the pipeline owner that an associated render object wishes 793 /// to update its visual appearance. 794 void requestVisualUpdate() { 795 if (onNeedVisualUpdate != null) 796 onNeedVisualUpdate(); 797 } 798 799 /// The unique object managed by this pipeline that has no parent. 800 /// 801 /// This object does not have to be a [RenderObject]. 802 AbstractNode get rootNode => _rootNode; 803 AbstractNode _rootNode; 804 set rootNode(AbstractNode value) { 805 if (_rootNode == value) 806 return; 807 _rootNode?.detach(); 808 _rootNode = value; 809 _rootNode?.attach(this); 810 } 811 812 List<RenderObject> _nodesNeedingLayout = <RenderObject>[]; 813 814 /// Whether this pipeline is currently in the layout phase. 815 /// 816 /// Specifically, whether [flushLayout] is currently running. 817 /// 818 /// Only valid when asserts are enabled. 819 bool get debugDoingLayout => _debugDoingLayout; 820 bool _debugDoingLayout = false; 821 822 /// Update the layout information for all dirty render objects. 823 /// 824 /// This function is one of the core stages of the rendering pipeline. Layout 825 /// information is cleaned prior to painting so that render objects will 826 /// appear on screen in their up-to-date locations. 827 /// 828 /// See [RendererBinding] for an example of how this function is used. 829 void flushLayout() { 830 if (!kReleaseMode) { 831 Timeline.startSync('Layout', arguments: timelineWhitelistArguments); 832 } 833 assert(() { 834 _debugDoingLayout = true; 835 return true; 836 }()); 837 try { 838 // TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themselves 839 while (_nodesNeedingLayout.isNotEmpty) { 840 final List<RenderObject> dirtyNodes = _nodesNeedingLayout; 841 _nodesNeedingLayout = <RenderObject>[]; 842 for (RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) { 843 if (node._needsLayout && node.owner == this) 844 node._layoutWithoutResize(); 845 } 846 } 847 } finally { 848 assert(() { 849 _debugDoingLayout = false; 850 return true; 851 }()); 852 if (!kReleaseMode) { 853 Timeline.finishSync(); 854 } 855 } 856 } 857 858 // This flag is used to allow the kinds of mutations performed by GlobalKey 859 // reparenting while a LayoutBuilder is being rebuilt and in so doing tries to 860 // move a node from another LayoutBuilder subtree that hasn't been updated 861 // yet. To set this, call [_enableMutationsToDirtySubtrees], which is called 862 // by [RenderObject.invokeLayoutCallback]. 863 bool _debugAllowMutationsToDirtySubtrees = false; 864 865 // See [RenderObject.invokeLayoutCallback]. 866 void _enableMutationsToDirtySubtrees(VoidCallback callback) { 867 assert(_debugDoingLayout); 868 bool oldState; 869 assert(() { 870 oldState = _debugAllowMutationsToDirtySubtrees; 871 _debugAllowMutationsToDirtySubtrees = true; 872 return true; 873 }()); 874 try { 875 callback(); 876 } finally { 877 assert(() { 878 _debugAllowMutationsToDirtySubtrees = oldState; 879 return true; 880 }()); 881 } 882 } 883 884 final List<RenderObject> _nodesNeedingCompositingBitsUpdate = <RenderObject>[]; 885 /// Updates the [RenderObject.needsCompositing] bits. 886 /// 887 /// Called as part of the rendering pipeline after [flushLayout] and before 888 /// [flushPaint]. 889 void flushCompositingBits() { 890 if (!kReleaseMode) { 891 Timeline.startSync('Compositing bits'); 892 } 893 _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth); 894 for (RenderObject node in _nodesNeedingCompositingBitsUpdate) { 895 if (node._needsCompositingBitsUpdate && node.owner == this) 896 node._updateCompositingBits(); 897 } 898 _nodesNeedingCompositingBitsUpdate.clear(); 899 if (!kReleaseMode) { 900 Timeline.finishSync(); 901 } 902 } 903 904 List<RenderObject> _nodesNeedingPaint = <RenderObject>[]; 905 906 /// Whether this pipeline is currently in the paint phase. 907 /// 908 /// Specifically, whether [flushPaint] is currently running. 909 /// 910 /// Only valid when asserts are enabled. 911 bool get debugDoingPaint => _debugDoingPaint; 912 bool _debugDoingPaint = false; 913 914 /// Update the display lists for all render objects. 915 /// 916 /// This function is one of the core stages of the rendering pipeline. 917 /// Painting occurs after layout and before the scene is recomposited so that 918 /// scene is composited with up-to-date display lists for every render object. 919 /// 920 /// See [RendererBinding] for an example of how this function is used. 921 void flushPaint() { 922 if (!kReleaseMode) { 923 Timeline.startSync('Paint', arguments: timelineWhitelistArguments); 924 } 925 assert(() { 926 _debugDoingPaint = true; 927 return true; 928 }()); 929 try { 930 final List<RenderObject> dirtyNodes = _nodesNeedingPaint; 931 _nodesNeedingPaint = <RenderObject>[]; 932 // Sort the dirty nodes in reverse order (deepest first). 933 for (RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) { 934 assert(node._layer != null); 935 if (node._needsPaint && node.owner == this) { 936 if (node._layer.attached) { 937 PaintingContext.repaintCompositedChild(node); 938 } else { 939 node._skippedPaintingOnLayer(); 940 } 941 } 942 } 943 assert(_nodesNeedingPaint.isEmpty); 944 } finally { 945 assert(() { 946 _debugDoingPaint = false; 947 return true; 948 }()); 949 if (!kReleaseMode) { 950 Timeline.finishSync(); 951 } 952 } 953 } 954 955 /// The object that is managing semantics for this pipeline owner, if any. 956 /// 957 /// An owner is created by [ensureSemantics]. The owner is valid for as long 958 /// there are [SemanticsHandle]s returned by [ensureSemantics] that have not 959 /// yet been disposed. Once the last handle has been disposed, the 960 /// [semanticsOwner] field will revert to null, and the previous owner will be 961 /// disposed. 962 /// 963 /// When [semanticsOwner] is null, the [PipelineOwner] skips all steps 964 /// relating to semantics. 965 SemanticsOwner get semanticsOwner => _semanticsOwner; 966 SemanticsOwner _semanticsOwner; 967 968 /// The number of clients registered to listen for semantics. 969 /// 970 /// The number is increased whenever [ensureSemantics] is called and decreased 971 /// when [SemanticsHandle.dispose] is called. 972 int get debugOutstandingSemanticsHandles => _outstandingSemanticsHandles; 973 int _outstandingSemanticsHandles = 0; 974 975 /// Opens a [SemanticsHandle] and calls [listener] whenever the semantics tree 976 /// updates. 977 /// 978 /// The [PipelineOwner] updates the semantics tree only when there are clients 979 /// that wish to use the semantics tree. These clients express their interest 980 /// by holding [SemanticsHandle] objects that notify them whenever the 981 /// semantics tree updates. 982 /// 983 /// Clients can close their [SemanticsHandle] by calling 984 /// [SemanticsHandle.dispose]. Once all the outstanding [SemanticsHandle] 985 /// objects for a given [PipelineOwner] are closed, the [PipelineOwner] stops 986 /// maintaining the semantics tree. 987 SemanticsHandle ensureSemantics({ VoidCallback listener }) { 988 _outstandingSemanticsHandles += 1; 989 if (_outstandingSemanticsHandles == 1) { 990 assert(_semanticsOwner == null); 991 _semanticsOwner = SemanticsOwner(); 992 if (onSemanticsOwnerCreated != null) 993 onSemanticsOwnerCreated(); 994 } 995 return SemanticsHandle._(this, listener); 996 } 997 998 void _didDisposeSemanticsHandle() { 999 assert(_semanticsOwner != null); 1000 _outstandingSemanticsHandles -= 1; 1001 if (_outstandingSemanticsHandles == 0) { 1002 _semanticsOwner.dispose(); 1003 _semanticsOwner = null; 1004 if (onSemanticsOwnerDisposed != null) 1005 onSemanticsOwnerDisposed(); 1006 } 1007 } 1008 1009 bool _debugDoingSemantics = false; 1010 final Set<RenderObject> _nodesNeedingSemantics = <RenderObject>{}; 1011 1012 /// Update the semantics for render objects marked as needing a semantics 1013 /// update. 1014 /// 1015 /// Initially, only the root node, as scheduled by 1016 /// [RenderObject.scheduleInitialSemantics], needs a semantics update. 1017 /// 1018 /// This function is one of the core stages of the rendering pipeline. The 1019 /// semantics are compiled after painting and only after 1020 /// [RenderObject.scheduleInitialSemantics] has been called. 1021 /// 1022 /// See [RendererBinding] for an example of how this function is used. 1023 void flushSemantics() { 1024 if (_semanticsOwner == null) 1025 return; 1026 if (!kReleaseMode) { 1027 Timeline.startSync('Semantics'); 1028 } 1029 assert(_semanticsOwner != null); 1030 assert(() { _debugDoingSemantics = true; return true; }()); 1031 try { 1032 final List<RenderObject> nodesToProcess = _nodesNeedingSemantics.toList() 1033 ..sort((RenderObject a, RenderObject b) => a.depth - b.depth); 1034 _nodesNeedingSemantics.clear(); 1035 for (RenderObject node in nodesToProcess) { 1036 if (node._needsSemanticsUpdate && node.owner == this) 1037 node._updateSemantics(); 1038 } 1039 _semanticsOwner.sendSemanticsUpdate(); 1040 } finally { 1041 assert(_nodesNeedingSemantics.isEmpty); 1042 assert(() { _debugDoingSemantics = false; return true; }()); 1043 if (!kReleaseMode) { 1044 Timeline.finishSync(); 1045 } 1046 } 1047 } 1048} 1049 1050/// An object in the render tree. 1051/// 1052/// The [RenderObject] class hierarchy is the core of the rendering 1053/// library's reason for being. 1054/// 1055/// [RenderObject]s have a [parent], and have a slot called [parentData] in 1056/// which the parent [RenderObject] can store child-specific data, for example, 1057/// the child position. The [RenderObject] class also implements the basic 1058/// layout and paint protocols. 1059/// 1060/// The [RenderObject] class, however, does not define a child model (e.g. 1061/// whether a node has zero, one, or more children). It also doesn't define a 1062/// coordinate system (e.g. whether children are positioned in Cartesian 1063/// coordinates, in polar coordinates, etc) or a specific layout protocol (e.g. 1064/// whether the layout is width-in-height-out, or constraint-in-size-out, or 1065/// whether the parent sets the size and position of the child before or after 1066/// the child lays out, etc; or indeed whether the children are allowed to read 1067/// their parent's [parentData] slot). 1068/// 1069/// The [RenderBox] subclass introduces the opinion that the layout 1070/// system uses Cartesian coordinates. 1071/// 1072/// ## Writing a RenderObject subclass 1073/// 1074/// In most cases, subclassing [RenderObject] itself is overkill, and 1075/// [RenderBox] would be a better starting point. However, if a render object 1076/// doesn't want to use a Cartesian coordinate system, then it should indeed 1077/// inherit from [RenderObject] directly. This allows it to define its own 1078/// layout protocol by using a new subclass of [Constraints] rather than using 1079/// [BoxConstraints], and by potentially using an entirely new set of objects 1080/// and values to represent the result of the output rather than just a [Size]. 1081/// This increased flexibility comes at the cost of not being able to rely on 1082/// the features of [RenderBox]. For example, [RenderBox] implements an 1083/// intrinsic sizing protocol that allows you to measure a child without fully 1084/// laying it out, in such a way that if that child changes size, the parent 1085/// will be laid out again (to take into account the new dimensions of the 1086/// child). This is a subtle and bug-prone feature to get right. 1087/// 1088/// Most aspects of writing a [RenderBox] apply to writing a [RenderObject] as 1089/// well, and therefore the discussion at [RenderBox] is recommended background 1090/// reading. The main differences are around layout and hit testing, since those 1091/// are the aspects that [RenderBox] primarily specializes. 1092/// 1093/// ### Layout 1094/// 1095/// A layout protocol begins with a subclass of [Constraints]. See the 1096/// discussion at [Constraints] for more information on how to write a 1097/// [Constraints] subclass. 1098/// 1099/// The [performLayout] method should take the [constraints], and apply them. 1100/// The output of the layout algorithm is fields set on the object that describe 1101/// the geometry of the object for the purposes of the parent's layout. For 1102/// example, with [RenderBox] the output is the [RenderBox.size] field. This 1103/// output should only be read by the parent if the parent specified 1104/// `parentUsesSize` as true when calling [layout] on the child. 1105/// 1106/// Anytime anything changes on a render object that would affect the layout of 1107/// that object, it should call [markNeedsLayout]. 1108/// 1109/// ### Hit Testing 1110/// 1111/// Hit testing is even more open-ended than layout. There is no method to 1112/// override, you are expected to provide one. 1113/// 1114/// The general behavior of your hit-testing method should be similar to the 1115/// behavior described for [RenderBox]. The main difference is that the input 1116/// need not be an [Offset]. You are also allowed to use a different subclass of 1117/// [HitTestEntry] when adding entries to the [HitTestResult]. When the 1118/// [handleEvent] method is called, the same object that was added to the 1119/// [HitTestResult] will be passed in, so it can be used to track information 1120/// like the precise coordinate of the hit, in whatever coordinate system is 1121/// used by the new layout protocol. 1122/// 1123/// ### Adapting from one protocol to another 1124/// 1125/// In general, the root of a Flutter render object tree is a [RenderView]. This 1126/// object has a single child, which must be a [RenderBox]. Thus, if you want to 1127/// have a custom [RenderObject] subclass in the render tree, you have two 1128/// choices: you either need to replace the [RenderView] itself, or you need to 1129/// have a [RenderBox] that has your class as its child. (The latter is the much 1130/// more common case.) 1131/// 1132/// This [RenderBox] subclass converts from the box protocol to the protocol of 1133/// your class. 1134/// 1135/// In particular, this means that for hit testing it overrides 1136/// [RenderBox.hitTest], and calls whatever method you have in your class for 1137/// hit testing. 1138/// 1139/// Similarly, it overrides [performLayout] to create a [Constraints] object 1140/// appropriate for your class and passes that to the child's [layout] method. 1141/// 1142/// ### Layout interactions between render objects 1143/// 1144/// In general, the layout of a render object should only depend on the output of 1145/// its child's layout, and then only if `parentUsesSize` is set to true in the 1146/// [layout] call. Furthermore, if it is set to true, the parent must call the 1147/// child's [layout] if the child is to be rendered, because otherwise the 1148/// parent will not be notified when the child changes its layout outputs. 1149/// 1150/// It is possible to set up render object protocols that transfer additional 1151/// information. For example, in the [RenderBox] protocol you can query your 1152/// children's intrinsic dimensions and baseline geometry. However, if this is 1153/// done then it is imperative that the child call [markNeedsLayout] on the 1154/// parent any time that additional information changes, if the parent used it 1155/// in the last layout phase. For an example of how to implement this, see the 1156/// [RenderBox.markNeedsLayout] method. It overrides 1157/// [RenderObject.markNeedsLayout] so that if a parent has queried the intrinsic 1158/// or baseline information, it gets marked dirty whenever the child's geometry 1159/// changes. 1160abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget { 1161 /// Initializes internal fields for subclasses. 1162 RenderObject() { 1163 _needsCompositing = isRepaintBoundary || alwaysNeedsCompositing; 1164 } 1165 1166 /// Cause the entire subtree rooted at the given [RenderObject] to be marked 1167 /// dirty for layout, paint, etc, so that the effects of a hot reload can be 1168 /// seen, or so that the effect of changing a global debug flag (such as 1169 /// [debugPaintSizeEnabled]) can be applied. 1170 /// 1171 /// This is called by the [RendererBinding] in response to the 1172 /// `ext.flutter.reassemble` hook, which is used by development tools when the 1173 /// application code has changed, to cause the widget tree to pick up any 1174 /// changed implementations. 1175 /// 1176 /// This is expensive and should not be called except during development. 1177 /// 1178 /// See also: 1179 /// 1180 /// * [BindingBase.reassembleApplication] 1181 void reassemble() { 1182 markNeedsLayout(); 1183 markNeedsCompositingBitsUpdate(); 1184 markNeedsPaint(); 1185 markNeedsSemanticsUpdate(); 1186 visitChildren((RenderObject child) { 1187 child.reassemble(); 1188 }); 1189 } 1190 1191 // LAYOUT 1192 1193 /// Data for use by the parent render object. 1194 /// 1195 /// The parent data is used by the render object that lays out this object 1196 /// (typically this object's parent in the render tree) to store information 1197 /// relevant to itself and to any other nodes who happen to know exactly what 1198 /// the data means. The parent data is opaque to the child. 1199 /// 1200 /// * The parent data field must not be directly set, except by calling 1201 /// [setupParentData] on the parent node. 1202 /// * The parent data can be set before the child is added to the parent, by 1203 /// calling [setupParentData] on the future parent node. 1204 /// * The conventions for using the parent data depend on the layout protocol 1205 /// used between the parent and child. For example, in box layout, the 1206 /// parent data is completely opaque but in sector layout the child is 1207 /// permitted to read some fields of the parent data. 1208 ParentData parentData; 1209 1210 /// Override to setup parent data correctly for your children. 1211 /// 1212 /// You can call this function to set up the parent data for child before the 1213 /// child is added to the parent's child list. 1214 void setupParentData(covariant RenderObject child) { 1215 assert(_debugCanPerformMutations); 1216 if (child.parentData is! ParentData) 1217 child.parentData = ParentData(); 1218 } 1219 1220 /// Called by subclasses when they decide a render object is a child. 1221 /// 1222 /// Only for use by subclasses when changing their child lists. Calling this 1223 /// in other cases will lead to an inconsistent tree and probably cause crashes. 1224 @override 1225 void adoptChild(RenderObject child) { 1226 assert(_debugCanPerformMutations); 1227 assert(child != null); 1228 setupParentData(child); 1229 markNeedsLayout(); 1230 markNeedsCompositingBitsUpdate(); 1231 markNeedsSemanticsUpdate(); 1232 super.adoptChild(child); 1233 } 1234 1235 /// Called by subclasses when they decide a render object is no longer a child. 1236 /// 1237 /// Only for use by subclasses when changing their child lists. Calling this 1238 /// in other cases will lead to an inconsistent tree and probably cause crashes. 1239 @override 1240 void dropChild(RenderObject child) { 1241 assert(_debugCanPerformMutations); 1242 assert(child != null); 1243 assert(child.parentData != null); 1244 child._cleanRelayoutBoundary(); 1245 child.parentData.detach(); 1246 child.parentData = null; 1247 super.dropChild(child); 1248 markNeedsLayout(); 1249 markNeedsCompositingBitsUpdate(); 1250 markNeedsSemanticsUpdate(); 1251 } 1252 1253 /// Calls visitor for each immediate child of this render object. 1254 /// 1255 /// Override in subclasses with children and call the visitor for each child. 1256 void visitChildren(RenderObjectVisitor visitor) { } 1257 1258 /// The object responsible for creating this render object. 1259 /// 1260 /// Used in debug messages. 1261 dynamic debugCreator; 1262 1263 void _debugReportException(String method, dynamic exception, StackTrace stack) { 1264 FlutterError.reportError(FlutterErrorDetailsForRendering( 1265 exception: exception, 1266 stack: stack, 1267 library: 'rendering library', 1268 context: ErrorDescription('during $method()'), 1269 renderObject: this, 1270 informationCollector: () sync* { 1271 if (debugCreator != null) 1272 yield DiagnosticsDebugCreator(debugCreator); 1273 yield describeForError('The following RenderObject was being processed when the exception was fired'); 1274 // TODO(jacobr): this error message has a code smell. Consider whether 1275 // displaying the truncated children is really useful for command line 1276 // users. Inspector users can see the full tree by clicking on the 1277 // render object so this may not be that useful. 1278 yield describeForError('RenderObject', style: DiagnosticsTreeStyle.truncateChildren); 1279 } 1280 )); 1281 } 1282 1283 /// Whether [performResize] for this render object is currently running. 1284 /// 1285 /// Only valid when asserts are enabled. In release builds, always returns 1286 /// false. 1287 bool get debugDoingThisResize => _debugDoingThisResize; 1288 bool _debugDoingThisResize = false; 1289 1290 /// Whether [performLayout] for this render object is currently running. 1291 /// 1292 /// Only valid when asserts are enabled. In release builds, always returns 1293 /// false. 1294 bool get debugDoingThisLayout => _debugDoingThisLayout; 1295 bool _debugDoingThisLayout = false; 1296 1297 /// The render object that is actively computing layout. 1298 /// 1299 /// Only valid when asserts are enabled. In release builds, always returns 1300 /// null. 1301 static RenderObject get debugActiveLayout => _debugActiveLayout; 1302 static RenderObject _debugActiveLayout; 1303 1304 /// Whether the parent render object is permitted to use this render object's 1305 /// size. 1306 /// 1307 /// Determined by the `parentUsesSize` parameter to [layout]. 1308 /// 1309 /// Only valid when asserts are enabled. In release builds, always returns 1310 /// null. 1311 bool get debugCanParentUseSize => _debugCanParentUseSize; 1312 bool _debugCanParentUseSize; 1313 1314 bool _debugMutationsLocked = false; 1315 1316 /// Whether tree mutations are currently permitted. 1317 /// 1318 /// Only valid when asserts are enabled. In release builds, always returns 1319 /// null. 1320 bool get _debugCanPerformMutations { 1321 bool result; 1322 assert(() { 1323 RenderObject node = this; 1324 while (true) { 1325 if (node._doingThisLayoutWithCallback) { 1326 result = true; 1327 break; 1328 } 1329 if (owner != null && owner._debugAllowMutationsToDirtySubtrees && node._needsLayout) { 1330 result = true; 1331 break; 1332 } 1333 if (node._debugMutationsLocked) { 1334 result = false; 1335 break; 1336 } 1337 if (node.parent is! RenderObject) { 1338 result = true; 1339 break; 1340 } 1341 node = node.parent; 1342 } 1343 return true; 1344 }()); 1345 return result; 1346 } 1347 1348 @override 1349 PipelineOwner get owner => super.owner; 1350 1351 @override 1352 void attach(PipelineOwner owner) { 1353 super.attach(owner); 1354 // If the node was dirtied in some way while unattached, make sure to add 1355 // it to the appropriate dirty list now that an owner is available 1356 if (_needsLayout && _relayoutBoundary != null) { 1357 // Don't enter this block if we've never laid out at all; 1358 // scheduleInitialLayout() will handle it 1359 _needsLayout = false; 1360 markNeedsLayout(); 1361 } 1362 if (_needsCompositingBitsUpdate) { 1363 _needsCompositingBitsUpdate = false; 1364 markNeedsCompositingBitsUpdate(); 1365 } 1366 if (_needsPaint && _layer != null) { 1367 // Don't enter this block if we've never painted at all; 1368 // scheduleInitialPaint() will handle it 1369 _needsPaint = false; 1370 markNeedsPaint(); 1371 } 1372 if (_needsSemanticsUpdate && _semanticsConfiguration.isSemanticBoundary) { 1373 // Don't enter this block if we've never updated semantics at all; 1374 // scheduleInitialSemantics() will handle it 1375 _needsSemanticsUpdate = false; 1376 markNeedsSemanticsUpdate(); 1377 } 1378 } 1379 1380 /// Whether this render object's layout information is dirty. 1381 /// 1382 /// This is only set in debug mode. In general, render objects should not need 1383 /// to condition their runtime behavior on whether they are dirty or not, 1384 /// since they should only be marked dirty immediately prior to being laid 1385 /// out and painted. 1386 /// 1387 /// It is intended to be used by tests and asserts. 1388 bool get debugNeedsLayout { 1389 bool result; 1390 assert(() { 1391 result = _needsLayout; 1392 return true; 1393 }()); 1394 return result; 1395 } 1396 bool _needsLayout = true; 1397 1398 RenderObject _relayoutBoundary; 1399 bool _doingThisLayoutWithCallback = false; 1400 1401 /// The layout constraints most recently supplied by the parent. 1402 @protected 1403 Constraints get constraints => _constraints; 1404 Constraints _constraints; 1405 1406 /// Verify that the object's constraints are being met. Override 1407 /// this function in a subclass to verify that your state matches 1408 /// the constraints object. This function is only called in checked 1409 /// mode and only when needsLayout is false. If the constraints are 1410 /// not met, it should assert or throw an exception. 1411 @protected 1412 void debugAssertDoesMeetConstraints(); 1413 1414 /// When true, debugAssertDoesMeetConstraints() is currently 1415 /// executing asserts for verifying the consistent behavior of 1416 /// intrinsic dimensions methods. 1417 /// 1418 /// This should only be set by debugAssertDoesMeetConstraints() 1419 /// implementations. It is used by tests to selectively ignore 1420 /// custom layout callbacks. It should not be set outside of 1421 /// debugAssertDoesMeetConstraints(), and should not be checked in 1422 /// release mode (where it will always be false). 1423 static bool debugCheckingIntrinsics = false; 1424 bool _debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout() { 1425 if (_relayoutBoundary == null) 1426 return true; // we haven't yet done layout even once, so there's nothing for us to do 1427 RenderObject node = this; 1428 while (node != _relayoutBoundary) { 1429 assert(node._relayoutBoundary == _relayoutBoundary); 1430 assert(node.parent != null); 1431 node = node.parent; 1432 if ((!node._needsLayout) && (!node._debugDoingThisLayout)) 1433 return false; 1434 } 1435 assert(node._relayoutBoundary == node); 1436 return true; 1437 } 1438 1439 /// Mark this render object's layout information as dirty, and either register 1440 /// this object with its [PipelineOwner], or defer to the parent, depending on 1441 /// whether this object is a relayout boundary or not respectively. 1442 /// 1443 /// ## Background 1444 /// 1445 /// Rather than eagerly updating layout information in response to writes into 1446 /// a render object, we instead mark the layout information as dirty, which 1447 /// schedules a visual update. As part of the visual update, the rendering 1448 /// pipeline updates the render object's layout information. 1449 /// 1450 /// This mechanism batches the layout work so that multiple sequential writes 1451 /// are coalesced, removing redundant computation. 1452 /// 1453 /// If a render object's parent indicates that it uses the size of one of its 1454 /// render object children when computing its layout information, this 1455 /// function, when called for the child, will also mark the parent as needing 1456 /// layout. In that case, since both the parent and the child need to have 1457 /// their layout recomputed, the pipeline owner is only notified about the 1458 /// parent; when the parent is laid out, it will call the child's [layout] 1459 /// method and thus the child will be laid out as well. 1460 /// 1461 /// Once [markNeedsLayout] has been called on a render object, 1462 /// [debugNeedsLayout] returns true for that render object until just after 1463 /// the pipeline owner has called [layout] on the render object. 1464 /// 1465 /// ## Special cases 1466 /// 1467 /// Some subclasses of [RenderObject], notably [RenderBox], have other 1468 /// situations in which the parent needs to be notified if the child is 1469 /// dirtied (e.g., if the child's intrinsic dimensions or baseline changes). 1470 /// Such subclasses override markNeedsLayout and either call 1471 /// `super.markNeedsLayout()`, in the normal case, or call 1472 /// [markParentNeedsLayout], in the case where the parent needs to be laid out 1473 /// as well as the child. 1474 /// 1475 /// If [sizedByParent] has changed, calls 1476 /// [markNeedsLayoutForSizedByParentChange] instead of [markNeedsLayout]. 1477 void markNeedsLayout() { 1478 assert(_debugCanPerformMutations); 1479 if (_needsLayout) { 1480 assert(_debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout()); 1481 return; 1482 } 1483 assert(_relayoutBoundary != null); 1484 if (_relayoutBoundary != this) { 1485 markParentNeedsLayout(); 1486 } else { 1487 _needsLayout = true; 1488 if (owner != null) { 1489 assert(() { 1490 if (debugPrintMarkNeedsLayoutStacks) 1491 debugPrintStack(label: 'markNeedsLayout() called for $this'); 1492 return true; 1493 }()); 1494 owner._nodesNeedingLayout.add(this); 1495 owner.requestVisualUpdate(); 1496 } 1497 } 1498 } 1499 1500 /// Mark this render object's layout information as dirty, and then defer to 1501 /// the parent. 1502 /// 1503 /// This function should only be called from [markNeedsLayout] or 1504 /// [markNeedsLayoutForSizedByParentChange] implementations of subclasses that 1505 /// introduce more reasons for deferring the handling of dirty layout to the 1506 /// parent. See [markNeedsLayout] for details. 1507 /// 1508 /// Only call this if [parent] is not null. 1509 @protected 1510 void markParentNeedsLayout() { 1511 _needsLayout = true; 1512 final RenderObject parent = this.parent; 1513 if (!_doingThisLayoutWithCallback) { 1514 parent.markNeedsLayout(); 1515 } else { 1516 assert(parent._debugDoingThisLayout); 1517 } 1518 assert(parent == this.parent); 1519 } 1520 1521 /// Mark this render object's layout information as dirty (like 1522 /// [markNeedsLayout]), and additionally also handle any necessary work to 1523 /// handle the case where [sizedByParent] has changed value. 1524 /// 1525 /// This should be called whenever [sizedByParent] might have changed. 1526 /// 1527 /// Only call this if [parent] is not null. 1528 void markNeedsLayoutForSizedByParentChange() { 1529 markNeedsLayout(); 1530 markParentNeedsLayout(); 1531 } 1532 1533 void _cleanRelayoutBoundary() { 1534 if (_relayoutBoundary != this) { 1535 _relayoutBoundary = null; 1536 _needsLayout = true; 1537 visitChildren((RenderObject child) { 1538 child._cleanRelayoutBoundary(); 1539 }); 1540 } 1541 } 1542 1543 /// Bootstrap the rendering pipeline by scheduling the very first layout. 1544 /// 1545 /// Requires this render object to be attached and that this render object 1546 /// is the root of the render tree. 1547 /// 1548 /// See [RenderView] for an example of how this function is used. 1549 void scheduleInitialLayout() { 1550 assert(attached); 1551 assert(parent is! RenderObject); 1552 assert(!owner._debugDoingLayout); 1553 assert(_relayoutBoundary == null); 1554 _relayoutBoundary = this; 1555 assert(() { 1556 _debugCanParentUseSize = false; 1557 return true; 1558 }()); 1559 owner._nodesNeedingLayout.add(this); 1560 } 1561 1562 void _layoutWithoutResize() { 1563 assert(_relayoutBoundary == this); 1564 RenderObject debugPreviousActiveLayout; 1565 assert(!_debugMutationsLocked); 1566 assert(!_doingThisLayoutWithCallback); 1567 assert(_debugCanParentUseSize != null); 1568 assert(() { 1569 _debugMutationsLocked = true; 1570 _debugDoingThisLayout = true; 1571 debugPreviousActiveLayout = _debugActiveLayout; 1572 _debugActiveLayout = this; 1573 if (debugPrintLayouts) 1574 debugPrint('Laying out (without resize) $this'); 1575 return true; 1576 }()); 1577 try { 1578 performLayout(); 1579 markNeedsSemanticsUpdate(); 1580 } catch (e, stack) { 1581 _debugReportException('performLayout', e, stack); 1582 } 1583 assert(() { 1584 _debugActiveLayout = debugPreviousActiveLayout; 1585 _debugDoingThisLayout = false; 1586 _debugMutationsLocked = false; 1587 return true; 1588 }()); 1589 _needsLayout = false; 1590 markNeedsPaint(); 1591 } 1592 1593 /// Compute the layout for this render object. 1594 /// 1595 /// This method is the main entry point for parents to ask their children to 1596 /// update their layout information. The parent passes a constraints object, 1597 /// which informs the child as to which layouts are permissible. The child is 1598 /// required to obey the given constraints. 1599 /// 1600 /// If the parent reads information computed during the child's layout, the 1601 /// parent must pass true for `parentUsesSize`. In that case, the parent will 1602 /// be marked as needing layout whenever the child is marked as needing layout 1603 /// because the parent's layout information depends on the child's layout 1604 /// information. If the parent uses the default value (false) for 1605 /// `parentUsesSize`, the child can change its layout information (subject to 1606 /// the given constraints) without informing the parent. 1607 /// 1608 /// Subclasses should not override [layout] directly. Instead, they should 1609 /// override [performResize] and/or [performLayout]. The [layout] method 1610 /// delegates the actual work to [performResize] and [performLayout]. 1611 /// 1612 /// The parent's [performLayout] method should call the [layout] of all its 1613 /// children unconditionally. It is the [layout] method's responsibility (as 1614 /// implemented here) to return early if the child does not need to do any 1615 /// work to update its layout information. 1616 void layout(Constraints constraints, { bool parentUsesSize = false }) { 1617 assert(constraints != null); 1618 assert(constraints.debugAssertIsValid( 1619 isAppliedConstraint: true, 1620 informationCollector: () sync* { 1621 final List<String> stack = StackTrace.current.toString().split('\n'); 1622 int targetFrame; 1623 final Pattern layoutFramePattern = RegExp(r'^#[0-9]+ +RenderObject.layout \('); 1624 for (int i = 0; i < stack.length; i += 1) { 1625 if (layoutFramePattern.matchAsPrefix(stack[i]) != null) { 1626 targetFrame = i + 1; 1627 break; 1628 } 1629 } 1630 if (targetFrame != null && targetFrame < stack.length) { 1631 final Pattern targetFramePattern = RegExp(r'^#[0-9]+ +(.+)$'); 1632 final Match targetFrameMatch = targetFramePattern.matchAsPrefix(stack[targetFrame]); 1633 final String problemFunction = (targetFrameMatch != null && targetFrameMatch.groupCount > 0) ? targetFrameMatch.group(1) : stack[targetFrame].trim(); 1634 // TODO(jacobr): this case is similar to displaying a single stack frame. 1635 yield ErrorDescription( 1636 'These invalid constraints were provided to $runtimeType\'s layout() ' 1637 'function by the following function, which probably computed the ' 1638 'invalid constraints in question:\n' 1639 ' $problemFunction' 1640 ); 1641 } 1642 }, 1643 )); 1644 assert(!_debugDoingThisResize); 1645 assert(!_debugDoingThisLayout); 1646 RenderObject relayoutBoundary; 1647 if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) { 1648 relayoutBoundary = this; 1649 } else { 1650 final RenderObject parent = this.parent; 1651 relayoutBoundary = parent._relayoutBoundary; 1652 } 1653 assert(() { 1654 _debugCanParentUseSize = parentUsesSize; 1655 return true; 1656 }()); 1657 if (!_needsLayout && constraints == _constraints && relayoutBoundary == _relayoutBoundary) { 1658 assert(() { 1659 // in case parentUsesSize changed since the last invocation, set size 1660 // to itself, so it has the right internal debug values. 1661 _debugDoingThisResize = sizedByParent; 1662 _debugDoingThisLayout = !sizedByParent; 1663 final RenderObject debugPreviousActiveLayout = _debugActiveLayout; 1664 _debugActiveLayout = this; 1665 debugResetSize(); 1666 _debugActiveLayout = debugPreviousActiveLayout; 1667 _debugDoingThisLayout = false; 1668 _debugDoingThisResize = false; 1669 return true; 1670 }()); 1671 return; 1672 } 1673 _constraints = constraints; 1674 _relayoutBoundary = relayoutBoundary; 1675 assert(!_debugMutationsLocked); 1676 assert(!_doingThisLayoutWithCallback); 1677 assert(() { 1678 _debugMutationsLocked = true; 1679 if (debugPrintLayouts) 1680 debugPrint('Laying out (${sizedByParent ? "with separate resize" : "with resize allowed"}) $this'); 1681 return true; 1682 }()); 1683 if (sizedByParent) { 1684 assert(() { _debugDoingThisResize = true; return true; }()); 1685 try { 1686 performResize(); 1687 assert(() { debugAssertDoesMeetConstraints(); return true; }()); 1688 } catch (e, stack) { 1689 _debugReportException('performResize', e, stack); 1690 } 1691 assert(() { _debugDoingThisResize = false; return true; }()); 1692 } 1693 RenderObject debugPreviousActiveLayout; 1694 assert(() { 1695 _debugDoingThisLayout = true; 1696 debugPreviousActiveLayout = _debugActiveLayout; 1697 _debugActiveLayout = this; 1698 return true; 1699 }()); 1700 try { 1701 performLayout(); 1702 markNeedsSemanticsUpdate(); 1703 assert(() { debugAssertDoesMeetConstraints(); return true; }()); 1704 } catch (e, stack) { 1705 _debugReportException('performLayout', e, stack); 1706 } 1707 assert(() { 1708 _debugActiveLayout = debugPreviousActiveLayout; 1709 _debugDoingThisLayout = false; 1710 _debugMutationsLocked = false; 1711 return true; 1712 }()); 1713 _needsLayout = false; 1714 markNeedsPaint(); 1715 } 1716 1717 /// If a subclass has a "size" (the state controlled by `parentUsesSize`, 1718 /// whatever it is in the subclass, e.g. the actual `size` property of 1719 /// [RenderBox]), and the subclass verifies that in checked mode this "size" 1720 /// property isn't used when [debugCanParentUseSize] isn't set, then that 1721 /// subclass should override [debugResetSize] to reapply the current values of 1722 /// [debugCanParentUseSize] to that state. 1723 @protected 1724 void debugResetSize() { } 1725 1726 /// Whether the constraints are the only input to the sizing algorithm (in 1727 /// particular, child nodes have no impact). 1728 /// 1729 /// Returning false is always correct, but returning true can be more 1730 /// efficient when computing the size of this render object because we don't 1731 /// need to recompute the size if the constraints don't change. 1732 /// 1733 /// Typically, subclasses will always return the same value. If the value can 1734 /// change, then, when it does change, the subclass should make sure to call 1735 /// [markNeedsLayoutForSizedByParentChange]. 1736 @protected 1737 bool get sizedByParent => false; 1738 1739 /// Updates the render objects size using only the constraints. 1740 /// 1741 /// Do not call this function directly: call [layout] instead. This function 1742 /// is called by [layout] when there is actually work to be done by this 1743 /// render object during layout. The layout constraints provided by your 1744 /// parent are available via the [constraints] getter. 1745 /// 1746 /// Subclasses that set [sizedByParent] to true should override this method 1747 /// to compute their size. 1748 /// 1749 /// This function is called only if [sizedByParent] is true. 1750 @protected 1751 void performResize(); 1752 1753 /// Do the work of computing the layout for this render object. 1754 /// 1755 /// Do not call this function directly: call [layout] instead. This function 1756 /// is called by [layout] when there is actually work to be done by this 1757 /// render object during layout. The layout constraints provided by your 1758 /// parent are available via the [constraints] getter. 1759 /// 1760 /// If [sizedByParent] is true, then this function should not actually change 1761 /// the dimensions of this render object. Instead, that work should be done by 1762 /// [performResize]. If [sizedByParent] is false, then this function should 1763 /// both change the dimensions of this render object and instruct its children 1764 /// to layout. 1765 /// 1766 /// In implementing this function, you must call [layout] on each of your 1767 /// children, passing true for parentUsesSize if your layout information is 1768 /// dependent on your child's layout information. Passing true for 1769 /// parentUsesSize ensures that this render object will undergo layout if the 1770 /// child undergoes layout. Otherwise, the child can change its layout 1771 /// information without informing this render object. 1772 @protected 1773 void performLayout(); 1774 1775 /// Allows mutations to be made to this object's child list (and any 1776 /// descendants) as well as to any other dirty nodes in the render tree owned 1777 /// by the same [PipelineOwner] as this object. The `callback` argument is 1778 /// invoked synchronously, and the mutations are allowed only during that 1779 /// callback's execution. 1780 /// 1781 /// This exists to allow child lists to be built on-demand during layout (e.g. 1782 /// based on the object's size), and to enable nodes to be moved around the 1783 /// tree as this happens (e.g. to handle [GlobalKey] reparenting), while still 1784 /// ensuring that any particular node is only laid out once per frame. 1785 /// 1786 /// Calling this function disables a number of assertions that are intended to 1787 /// catch likely bugs. As such, using this function is generally discouraged. 1788 /// 1789 /// This function can only be called during layout. 1790 @protected 1791 void invokeLayoutCallback<T extends Constraints>(LayoutCallback<T> callback) { 1792 assert(_debugMutationsLocked); 1793 assert(_debugDoingThisLayout); 1794 assert(!_doingThisLayoutWithCallback); 1795 _doingThisLayoutWithCallback = true; 1796 try { 1797 owner._enableMutationsToDirtySubtrees(() { callback(constraints); }); 1798 } finally { 1799 _doingThisLayoutWithCallback = false; 1800 } 1801 } 1802 1803 /// Rotate this render object (not yet implemented). 1804 void rotate({ 1805 int oldAngle, // 0..3 1806 int newAngle, // 0..3 1807 Duration time, 1808 }) { } 1809 1810 // when the parent has rotated (e.g. when the screen has been turned 1811 // 90 degrees), immediately prior to layout() being called for the 1812 // new dimensions, rotate() is called with the old and new angles. 1813 // The next time paint() is called, the coordinate space will have 1814 // been rotated N quarter-turns clockwise, where: 1815 // N = newAngle-oldAngle 1816 // ...but the rendering is expected to remain the same, pixel for 1817 // pixel, on the output device. Then, the layout() method or 1818 // equivalent will be called. 1819 1820 1821 // PAINTING 1822 1823 /// Whether [paint] for this render object is currently running. 1824 /// 1825 /// Only valid when asserts are enabled. In release builds, always returns 1826 /// false. 1827 bool get debugDoingThisPaint => _debugDoingThisPaint; 1828 bool _debugDoingThisPaint = false; 1829 1830 /// The render object that is actively painting. 1831 /// 1832 /// Only valid when asserts are enabled. In release builds, always returns 1833 /// null. 1834 static RenderObject get debugActivePaint => _debugActivePaint; 1835 static RenderObject _debugActivePaint; 1836 1837 /// Whether this render object repaints separately from its parent. 1838 /// 1839 /// Override this in subclasses to indicate that instances of your class ought 1840 /// to repaint independently. For example, render objects that repaint 1841 /// frequently might want to repaint themselves without requiring their parent 1842 /// to repaint. 1843 /// 1844 /// If this getter returns true, the [paintBounds] are applied to this object 1845 /// and all descendants. The framework automatically creates an [OffsetLayer] 1846 /// and assigns it to the [layer] field. Render objects that declare 1847 /// themselves as repaint boundaries must not replace the layer created by 1848 /// the framework. 1849 /// 1850 /// Warning: This getter must not change value over the lifetime of this object. 1851 bool get isRepaintBoundary => false; 1852 1853 /// Called, in checked mode, if [isRepaintBoundary] is true, when either the 1854 /// this render object or its parent attempt to paint. 1855 /// 1856 /// This can be used to record metrics about whether the node should actually 1857 /// be a repaint boundary. 1858 void debugRegisterRepaintBoundaryPaint({ bool includedParent = true, bool includedChild = false }) { } 1859 1860 /// Whether this render object always needs compositing. 1861 /// 1862 /// Override this in subclasses to indicate that your paint function always 1863 /// creates at least one composited layer. For example, videos should return 1864 /// true if they use hardware decoders. 1865 /// 1866 /// You must call [markNeedsCompositingBitsUpdate] if the value of this getter 1867 /// changes. (This is implied when [adoptChild] or [dropChild] are called.) 1868 @protected 1869 bool get alwaysNeedsCompositing => false; 1870 1871 /// The compositing layer that this render object uses to repaint. 1872 /// 1873 /// If this render object is not a repaint boundary, it is the responsibility 1874 /// of the [paint] method to populate this field. If [needsCompositing] is 1875 /// true, this field may be populated with the root-most layer used by the 1876 /// render object implementation. When repainting, instead of creating a new 1877 /// layer the render object may update the layer stored in this field for better 1878 /// performance. It is also OK to leave this field as null and create a new 1879 /// layer on every repaint, but without the performance benefit. If 1880 /// [needsCompositing] is false, this field must be set to null either by 1881 /// never populating this field, or by setting it to null when the value of 1882 /// [needsCompositing] changes from true to false. 1883 /// 1884 /// If this render object is a repaint boundary, the framework automatically 1885 /// creates an [OffsetLayer] and populates this field prior to calling the 1886 /// [paint] method. The [paint] method must not replace the value of this 1887 /// field. 1888 @protected 1889 ContainerLayer get layer { 1890 assert(!isRepaintBoundary || (_layer == null || _layer is OffsetLayer)); 1891 return _layer; 1892 } 1893 1894 @protected 1895 set layer(ContainerLayer newLayer) { 1896 assert( 1897 !isRepaintBoundary, 1898 'Attempted to set a layer to a repaint boundary render object.\n' 1899 'The framework creates and assigns an OffsetLayer to a repaint ' 1900 'boundary automatically.', 1901 ); 1902 _layer = newLayer; 1903 } 1904 ContainerLayer _layer; 1905 1906 /// In debug mode, the compositing layer that this render object uses to repaint. 1907 /// 1908 /// This getter is intended for debugging purposes only. In release builds, it 1909 /// always returns null. In debug builds, it returns the layer even if the layer 1910 /// is dirty. 1911 /// 1912 /// For production code, consider [layer]. 1913 ContainerLayer get debugLayer { 1914 ContainerLayer result; 1915 assert(() { 1916 result = _layer; 1917 return true; 1918 }()); 1919 return result; 1920 } 1921 1922 bool _needsCompositingBitsUpdate = false; // set to true when a child is added 1923 /// Mark the compositing state for this render object as dirty. 1924 /// 1925 /// This is called to indicate that the value for [needsCompositing] needs to 1926 /// be recomputed during the next [PipelineOwner.flushCompositingBits] engine 1927 /// phase. 1928 /// 1929 /// When the subtree is mutated, we need to recompute our 1930 /// [needsCompositing] bit, and some of our ancestors need to do the 1931 /// same (in case ours changed in a way that will change theirs). To 1932 /// this end, [adoptChild] and [dropChild] call this method, and, as 1933 /// necessary, this method calls the parent's, etc, walking up the 1934 /// tree to mark all the nodes that need updating. 1935 /// 1936 /// This method does not schedule a rendering frame, because since 1937 /// it cannot be the case that _only_ the compositing bits changed, 1938 /// something else will have scheduled a frame for us. 1939 void markNeedsCompositingBitsUpdate() { 1940 if (_needsCompositingBitsUpdate) 1941 return; 1942 _needsCompositingBitsUpdate = true; 1943 if (parent is RenderObject) { 1944 final RenderObject parent = this.parent; 1945 if (parent._needsCompositingBitsUpdate) 1946 return; 1947 if (!isRepaintBoundary && !parent.isRepaintBoundary) { 1948 parent.markNeedsCompositingBitsUpdate(); 1949 return; 1950 } 1951 } 1952 assert(() { 1953 final AbstractNode parent = this.parent; 1954 if (parent is RenderObject) 1955 return parent._needsCompositing; 1956 return true; 1957 }()); 1958 // parent is fine (or there isn't one), but we are dirty 1959 if (owner != null) 1960 owner._nodesNeedingCompositingBitsUpdate.add(this); 1961 } 1962 1963 bool _needsCompositing; // initialized in the constructor 1964 /// Whether we or one of our descendants has a compositing layer. 1965 /// 1966 /// If this node needs compositing as indicated by this bit, then all ancestor 1967 /// nodes will also need compositing. 1968 /// 1969 /// Only legal to call after [PipelineOwner.flushLayout] and 1970 /// [PipelineOwner.flushCompositingBits] have been called. 1971 bool get needsCompositing { 1972 assert(!_needsCompositingBitsUpdate); // make sure we don't use this bit when it is dirty 1973 return _needsCompositing; 1974 } 1975 1976 void _updateCompositingBits() { 1977 if (!_needsCompositingBitsUpdate) 1978 return; 1979 final bool oldNeedsCompositing = _needsCompositing; 1980 _needsCompositing = false; 1981 visitChildren((RenderObject child) { 1982 child._updateCompositingBits(); 1983 if (child.needsCompositing) 1984 _needsCompositing = true; 1985 }); 1986 if (isRepaintBoundary || alwaysNeedsCompositing) 1987 _needsCompositing = true; 1988 if (oldNeedsCompositing != _needsCompositing) 1989 markNeedsPaint(); 1990 _needsCompositingBitsUpdate = false; 1991 } 1992 1993 /// Whether this render object's paint information is dirty. 1994 /// 1995 /// This is only set in debug mode. In general, render objects should not need 1996 /// to condition their runtime behavior on whether they are dirty or not, 1997 /// since they should only be marked dirty immediately prior to being laid 1998 /// out and painted. 1999 /// 2000 /// It is intended to be used by tests and asserts. 2001 /// 2002 /// It is possible (and indeed, quite common) for [debugNeedsPaint] to be 2003 /// false and [debugNeedsLayout] to be true. The render object will still be 2004 /// repainted in the next frame when this is the case, because the 2005 /// [markNeedsPaint] method is implicitly called by the framework after a 2006 /// render object is laid out, prior to the paint phase. 2007 bool get debugNeedsPaint { 2008 bool result; 2009 assert(() { 2010 result = _needsPaint; 2011 return true; 2012 }()); 2013 return result; 2014 } 2015 bool _needsPaint = true; 2016 2017 /// Mark this render object as having changed its visual appearance. 2018 /// 2019 /// Rather than eagerly updating this render object's display list 2020 /// in response to writes, we instead mark the render object as needing to 2021 /// paint, which schedules a visual update. As part of the visual update, the 2022 /// rendering pipeline will give this render object an opportunity to update 2023 /// its display list. 2024 /// 2025 /// This mechanism batches the painting work so that multiple sequential 2026 /// writes are coalesced, removing redundant computation. 2027 /// 2028 /// Once [markNeedsPaint] has been called on a render object, 2029 /// [debugNeedsPaint] returns true for that render object until just after 2030 /// the pipeline owner has called [paint] on the render object. 2031 /// 2032 /// See also: 2033 /// 2034 /// * [RepaintBoundary], to scope a subtree of render objects to their own 2035 /// layer, thus limiting the number of nodes that [markNeedsPaint] must mark 2036 /// dirty. 2037 void markNeedsPaint() { 2038 assert(owner == null || !owner.debugDoingPaint); 2039 if (_needsPaint) 2040 return; 2041 _needsPaint = true; 2042 if (isRepaintBoundary) { 2043 assert(() { 2044 if (debugPrintMarkNeedsPaintStacks) 2045 debugPrintStack(label: 'markNeedsPaint() called for $this'); 2046 return true; 2047 }()); 2048 // If we always have our own layer, then we can just repaint 2049 // ourselves without involving any other nodes. 2050 assert(_layer is OffsetLayer); 2051 if (owner != null) { 2052 owner._nodesNeedingPaint.add(this); 2053 owner.requestVisualUpdate(); 2054 } 2055 } else if (parent is RenderObject) { 2056 final RenderObject parent = this.parent; 2057 parent.markNeedsPaint(); 2058 assert(parent == this.parent); 2059 } else { 2060 assert(() { 2061 if (debugPrintMarkNeedsPaintStacks) 2062 debugPrintStack(label: 'markNeedsPaint() called for $this (root of render tree)'); 2063 return true; 2064 }()); 2065 // If we're the root of the render tree (probably a RenderView), 2066 // then we have to paint ourselves, since nobody else can paint 2067 // us. We don't add ourselves to _nodesNeedingPaint in this 2068 // case, because the root is always told to paint regardless. 2069 if (owner != null) 2070 owner.requestVisualUpdate(); 2071 } 2072 } 2073 2074 // Called when flushPaint() tries to make us paint but our layer is detached. 2075 // To make sure that our subtree is repainted when it's finally reattached, 2076 // even in the case where some ancestor layer is itself never marked dirty, we 2077 // have to mark our entire detached subtree as dirty and needing to be 2078 // repainted. That way, we'll eventually be repainted. 2079 void _skippedPaintingOnLayer() { 2080 assert(attached); 2081 assert(isRepaintBoundary); 2082 assert(_needsPaint); 2083 assert(_layer != null); 2084 assert(!_layer.attached); 2085 AbstractNode ancestor = parent; 2086 while (ancestor is RenderObject) { 2087 final RenderObject node = ancestor; 2088 if (node.isRepaintBoundary) { 2089 if (node._layer == null) 2090 break; // looks like the subtree here has never been painted. let it handle itself. 2091 if (node._layer.attached) 2092 break; // it's the one that detached us, so it's the one that will decide to repaint us. 2093 node._needsPaint = true; 2094 } 2095 ancestor = node.parent; 2096 } 2097 } 2098 2099 /// Bootstrap the rendering pipeline by scheduling the very first paint. 2100 /// 2101 /// Requires that this render object is attached, is the root of the render 2102 /// tree, and has a composited layer. 2103 /// 2104 /// See [RenderView] for an example of how this function is used. 2105 void scheduleInitialPaint(ContainerLayer rootLayer) { 2106 assert(rootLayer.attached); 2107 assert(attached); 2108 assert(parent is! RenderObject); 2109 assert(!owner._debugDoingPaint); 2110 assert(isRepaintBoundary); 2111 assert(_layer == null); 2112 _layer = rootLayer; 2113 assert(_needsPaint); 2114 owner._nodesNeedingPaint.add(this); 2115 } 2116 2117 /// Replace the layer. This is only valid for the root of a render 2118 /// object subtree (whatever object [scheduleInitialPaint] was 2119 /// called on). 2120 /// 2121 /// This might be called if, e.g., the device pixel ratio changed. 2122 void replaceRootLayer(OffsetLayer rootLayer) { 2123 assert(rootLayer.attached); 2124 assert(attached); 2125 assert(parent is! RenderObject); 2126 assert(!owner._debugDoingPaint); 2127 assert(isRepaintBoundary); 2128 assert(_layer != null); // use scheduleInitialPaint the first time 2129 _layer.detach(); 2130 _layer = rootLayer; 2131 markNeedsPaint(); 2132 } 2133 2134 void _paintWithContext(PaintingContext context, Offset offset) { 2135 assert(() { 2136 if (_debugDoingThisPaint) { 2137 throw FlutterError.fromParts(<DiagnosticsNode>[ 2138 ErrorSummary('Tried to paint a RenderObject reentrantly.'), 2139 describeForError( 2140 'The following RenderObject was already being painted when it was ' 2141 'painted again' 2142 ), 2143 ErrorDescription( 2144 'Since this typically indicates an infinite recursion, it is ' 2145 'disallowed.' 2146 ) 2147 ]); 2148 } 2149 return true; 2150 }()); 2151 // If we still need layout, then that means that we were skipped in the 2152 // layout phase and therefore don't need painting. We might not know that 2153 // yet (that is, our layer might not have been detached yet), because the 2154 // same node that skipped us in layout is above us in the tree (obviously) 2155 // and therefore may not have had a chance to paint yet (since the tree 2156 // paints in reverse order). In particular this will happen if they have 2157 // a different layer, because there's a repaint boundary between us. 2158 if (_needsLayout) 2159 return; 2160 assert(() { 2161 if (_needsCompositingBitsUpdate) { 2162 throw FlutterError.fromParts(<DiagnosticsNode>[ 2163 ErrorSummary( 2164 'Tried to paint a RenderObject before its compositing bits were ' 2165 'updated.' 2166 ), 2167 describeForError( 2168 'The following RenderObject was marked as having dirty compositing ' 2169 'bits at the time that it was painted', 2170 ), 2171 ErrorDescription( 2172 'A RenderObject that still has dirty compositing bits cannot be ' 2173 'painted because this indicates that the tree has not yet been ' 2174 'properly configured for creating the layer tree.' 2175 ), 2176 ErrorHint( 2177 'This usually indicates an error in the Flutter framework itself.' 2178 ) 2179 ]); 2180 } 2181 return true; 2182 }()); 2183 RenderObject debugLastActivePaint; 2184 assert(() { 2185 _debugDoingThisPaint = true; 2186 debugLastActivePaint = _debugActivePaint; 2187 _debugActivePaint = this; 2188 assert(!isRepaintBoundary || _layer != null); 2189 return true; 2190 }()); 2191 _needsPaint = false; 2192 try { 2193 paint(context, offset); 2194 assert(!_needsLayout); // check that the paint() method didn't mark us dirty again 2195 assert(!_needsPaint); // check that the paint() method didn't mark us dirty again 2196 } catch (e, stack) { 2197 _debugReportException('paint', e, stack); 2198 } 2199 assert(() { 2200 debugPaint(context, offset); 2201 _debugActivePaint = debugLastActivePaint; 2202 _debugDoingThisPaint = false; 2203 return true; 2204 }()); 2205 } 2206 2207 /// An estimate of the bounds within which this render object will paint. 2208 /// Useful for debugging flags such as [debugPaintLayerBordersEnabled]. 2209 /// 2210 /// These are also the bounds used by [showOnScreen] to make a [RenderObject] 2211 /// visible on screen. 2212 Rect get paintBounds; 2213 2214 /// Override this method to paint debugging information. 2215 void debugPaint(PaintingContext context, Offset offset) { } 2216 2217 /// Paint this render object into the given context at the given offset. 2218 /// 2219 /// Subclasses should override this method to provide a visual appearance 2220 /// for themselves. The render object's local coordinate system is 2221 /// axis-aligned with the coordinate system of the context's canvas and the 2222 /// render object's local origin (i.e, x=0 and y=0) is placed at the given 2223 /// offset in the context's canvas. 2224 /// 2225 /// Do not call this function directly. If you wish to paint yourself, call 2226 /// [markNeedsPaint] instead to schedule a call to this function. If you wish 2227 /// to paint one of your children, call [PaintingContext.paintChild] on the 2228 /// given `context`. 2229 /// 2230 /// When painting one of your children (via a paint child function on the 2231 /// given context), the current canvas held by the context might change 2232 /// because draw operations before and after painting children might need to 2233 /// be recorded on separate compositing layers. 2234 void paint(PaintingContext context, Offset offset) { } 2235 2236 /// Applies the transform that would be applied when painting the given child 2237 /// to the given matrix. 2238 /// 2239 /// Used by coordinate conversion functions to translate coordinates local to 2240 /// one render object into coordinates local to another render object. 2241 void applyPaintTransform(covariant RenderObject child, Matrix4 transform) { 2242 assert(child.parent == this); 2243 } 2244 2245 /// Applies the paint transform up the tree to `ancestor`. 2246 /// 2247 /// Returns a matrix that maps the local paint coordinate system to the 2248 /// coordinate system of `ancestor`. 2249 /// 2250 /// If `ancestor` is null, this method returns a matrix that maps from the 2251 /// local paint coordinate system to the coordinate system of the 2252 /// [PipelineOwner.rootNode]. For the render tree owner by the 2253 /// [RendererBinding] (i.e. for the main render tree displayed on the device) 2254 /// this means that this method maps to the global coordinate system in 2255 /// logical pixels. To get physical pixels, use [applyPaintTransform] from the 2256 /// [RenderView] to further transform the coordinate. 2257 Matrix4 getTransformTo(RenderObject ancestor) { 2258 final bool ancestorSpecified = ancestor != null; 2259 assert(attached); 2260 if (ancestor == null) { 2261 final AbstractNode rootNode = owner.rootNode; 2262 if (rootNode is RenderObject) 2263 ancestor = rootNode; 2264 } 2265 final List<RenderObject> renderers = <RenderObject>[]; 2266 for (RenderObject renderer = this; renderer != ancestor; renderer = renderer.parent) { 2267 assert(renderer != null); // Failed to find ancestor in parent chain. 2268 renderers.add(renderer); 2269 } 2270 if (ancestorSpecified) 2271 renderers.add(ancestor); 2272 final Matrix4 transform = Matrix4.identity(); 2273 for (int index = renderers.length - 1; index > 0; index -= 1) { 2274 renderers[index].applyPaintTransform(renderers[index - 1], transform); 2275 } 2276 return transform; 2277 } 2278 2279 2280 /// Returns a rect in this object's coordinate system that describes 2281 /// the approximate bounding box of the clip rect that would be 2282 /// applied to the given child during the paint phase, if any. 2283 /// 2284 /// Returns null if the child would not be clipped. 2285 /// 2286 /// This is used in the semantics phase to avoid including children 2287 /// that are not physically visible. 2288 Rect describeApproximatePaintClip(covariant RenderObject child) => null; 2289 2290 /// Returns a rect in this object's coordinate system that describes 2291 /// which [SemanticsNode]s produced by the `child` should be included in the 2292 /// semantics tree. [SemanticsNode]s from the `child` that are positioned 2293 /// outside of this rect will be dropped. Child [SemanticsNode]s that are 2294 /// positioned inside this rect, but outside of [describeApproximatePaintClip] 2295 /// will be included in the tree marked as hidden. Child [SemanticsNode]s 2296 /// that are inside of both rect will be included in the tree as regular 2297 /// nodes. 2298 /// 2299 /// This method only returns a non-null value if the semantics clip rect 2300 /// is different from the rect returned by [describeApproximatePaintClip]. 2301 /// If the semantics clip rect and the paint clip rect are the same, this 2302 /// method returns null. 2303 /// 2304 /// A viewport would typically implement this method to include semantic nodes 2305 /// in the semantics tree that are currently hidden just before the leading 2306 /// or just after the trailing edge. These nodes have to be included in the 2307 /// semantics tree to implement implicit accessibility scrolling on iOS where 2308 /// the viewport scrolls implicitly when moving the accessibility focus from 2309 /// a the last visible node in the viewport to the first hidden one. 2310 Rect describeSemanticsClip(covariant RenderObject child) => null; 2311 2312 // SEMANTICS 2313 2314 /// Bootstrap the semantics reporting mechanism by marking this node 2315 /// as needing a semantics update. 2316 /// 2317 /// Requires that this render object is attached, and is the root of 2318 /// the render tree. 2319 /// 2320 /// See [RendererBinding] for an example of how this function is used. 2321 void scheduleInitialSemantics() { 2322 assert(attached); 2323 assert(parent is! RenderObject); 2324 assert(!owner._debugDoingSemantics); 2325 assert(_semantics == null); 2326 assert(_needsSemanticsUpdate); 2327 assert(owner._semanticsOwner != null); 2328 owner._nodesNeedingSemantics.add(this); 2329 owner.requestVisualUpdate(); 2330 } 2331 2332 /// Report the semantics of this node, for example for accessibility purposes. 2333 /// 2334 /// This method should be overridden by subclasses that have interesting 2335 /// semantic information. 2336 /// 2337 /// The given [SemanticsConfiguration] object is mutable and should be 2338 /// annotated in a manner that describes the current state. No reference 2339 /// should be kept to that object; mutating it outside of the context of the 2340 /// [describeSemanticsConfiguration] call (for example as a result of 2341 /// asynchronous computation) will at best have no useful effect and at worse 2342 /// will cause crashes as the data will be in an inconsistent state. 2343 /// 2344 /// {@tool sample} 2345 /// 2346 /// The following snippet will describe the node as a button that responds to 2347 /// tap actions. 2348 /// 2349 /// ```dart 2350 /// abstract class SemanticButtonRenderObject extends RenderObject { 2351 /// @override 2352 /// void describeSemanticsConfiguration(SemanticsConfiguration config) { 2353 /// super.describeSemanticsConfiguration(config); 2354 /// config 2355 /// ..onTap = _handleTap 2356 /// ..label = 'I am a button' 2357 /// ..isButton = true; 2358 /// } 2359 /// 2360 /// void _handleTap() { 2361 /// // Do something. 2362 /// } 2363 /// } 2364 /// ``` 2365 /// {@end-tool} 2366 @protected 2367 void describeSemanticsConfiguration(SemanticsConfiguration config) { 2368 // Nothing to do by default. 2369 } 2370 2371 /// Sends a [SemanticsEvent] associated with this render object's [SemanticsNode]. 2372 /// 2373 /// If this render object has no semantics information, the first parent 2374 /// render object with a non-null semantic node is used. 2375 /// 2376 /// If semantics are disabled, no events are dispatched. 2377 /// 2378 /// See [SemanticsNode.sendEvent] for a full description of the behavior. 2379 void sendSemanticsEvent(SemanticsEvent semanticsEvent) { 2380 if (owner.semanticsOwner == null) 2381 return; 2382 if (_semantics != null && !_semantics.isMergedIntoParent) { 2383 _semantics.sendEvent(semanticsEvent); 2384 } else if (parent != null) { 2385 final RenderObject renderParent = parent; 2386 renderParent.sendSemanticsEvent(semanticsEvent); 2387 } 2388 } 2389 2390 // Use [_semanticsConfiguration] to access. 2391 SemanticsConfiguration _cachedSemanticsConfiguration; 2392 2393 SemanticsConfiguration get _semanticsConfiguration { 2394 if (_cachedSemanticsConfiguration == null) { 2395 _cachedSemanticsConfiguration = SemanticsConfiguration(); 2396 describeSemanticsConfiguration(_cachedSemanticsConfiguration); 2397 } 2398 return _cachedSemanticsConfiguration; 2399 } 2400 2401 /// The bounding box, in the local coordinate system, of this 2402 /// object, for accessibility purposes. 2403 Rect get semanticBounds; 2404 2405 bool _needsSemanticsUpdate = true; 2406 SemanticsNode _semantics; 2407 2408 /// The semantics of this render object. 2409 /// 2410 /// Exposed only for testing and debugging. To learn about the semantics of 2411 /// render objects in production, obtain a [SemanticsHandle] from 2412 /// [PipelineOwner.ensureSemantics]. 2413 /// 2414 /// Only valid when asserts are enabled. In release builds, always returns 2415 /// null. 2416 SemanticsNode get debugSemantics { 2417 SemanticsNode result; 2418 assert(() { 2419 result = _semantics; 2420 return true; 2421 }()); 2422 return result; 2423 } 2424 2425 /// Removes all semantics from this render object and its descendants. 2426 /// 2427 /// Should only be called on objects whose [parent] is not a [RenderObject]. 2428 /// 2429 /// Override this method if you instantiate new [SemanticsNode]s in an 2430 /// overridden [assembleSemanticsNode] method, to dispose of those nodes. 2431 @mustCallSuper 2432 void clearSemantics() { 2433 _needsSemanticsUpdate = true; 2434 _semantics = null; 2435 visitChildren((RenderObject child) { 2436 child.clearSemantics(); 2437 }); 2438 } 2439 2440 /// Mark this node as needing an update to its semantics description. 2441 /// 2442 /// This must be called whenever the semantics configuration of this 2443 /// [RenderObject] as annotated by [describeSemanticsConfiguration] changes in 2444 /// any way to update the semantics tree. 2445 void markNeedsSemanticsUpdate() { 2446 assert(!attached || !owner._debugDoingSemantics); 2447 if (!attached || owner._semanticsOwner == null) { 2448 _cachedSemanticsConfiguration = null; 2449 return; 2450 } 2451 2452 // Dirty the semantics tree starting at `this` until we have reached a 2453 // RenderObject that is a semantics boundary. All semantics past this 2454 // RenderObject are still up-to date. Therefore, we will later only rebuild 2455 // the semantics subtree starting at the identified semantics boundary. 2456 2457 final bool wasSemanticsBoundary = _semantics != null && _cachedSemanticsConfiguration?.isSemanticBoundary == true; 2458 _cachedSemanticsConfiguration = null; 2459 bool isEffectiveSemanticsBoundary = _semanticsConfiguration.isSemanticBoundary && wasSemanticsBoundary; 2460 RenderObject node = this; 2461 2462 while (!isEffectiveSemanticsBoundary && node.parent is RenderObject) { 2463 if (node != this && node._needsSemanticsUpdate) 2464 break; 2465 node._needsSemanticsUpdate = true; 2466 2467 node = node.parent; 2468 isEffectiveSemanticsBoundary = node._semanticsConfiguration.isSemanticBoundary; 2469 if (isEffectiveSemanticsBoundary && node._semantics == null) { 2470 // We have reached a semantics boundary that doesn't own a semantics node. 2471 // That means the semantics of this branch are currently blocked and will 2472 // not appear in the semantics tree. We can abort the walk here. 2473 return; 2474 } 2475 } 2476 if (node != this && _semantics != null && _needsSemanticsUpdate) { 2477 // If `this` node has already been added to [owner._nodesNeedingSemantics] 2478 // remove it as it is no longer guaranteed that its semantics 2479 // node will continue to be in the tree. If it still is in the tree, the 2480 // ancestor `node` added to [owner._nodesNeedingSemantics] at the end of 2481 // this block will ensure that the semantics of `this` node actually gets 2482 // updated. 2483 // (See semantics_10_test.dart for an example why this is required). 2484 owner._nodesNeedingSemantics.remove(this); 2485 } 2486 if (!node._needsSemanticsUpdate) { 2487 node._needsSemanticsUpdate = true; 2488 if (owner != null) { 2489 assert(node._semanticsConfiguration.isSemanticBoundary || node.parent is! RenderObject); 2490 owner._nodesNeedingSemantics.add(node); 2491 owner.requestVisualUpdate(); 2492 } 2493 } 2494 } 2495 2496 /// Updates the semantic information of the render object. 2497 void _updateSemantics() { 2498 assert(_semanticsConfiguration.isSemanticBoundary || parent is! RenderObject); 2499 if (_needsLayout) { 2500 // There's not enough information in this subtree to compute semantics. 2501 // The subtree is probably being kept alive by a viewport but not laid out. 2502 return; 2503 } 2504 final _SemanticsFragment fragment = _getSemanticsForParent( 2505 mergeIntoParent: _semantics?.parent?.isPartOfNodeMerging ?? false, 2506 ); 2507 assert(fragment is _InterestingSemanticsFragment); 2508 final _InterestingSemanticsFragment interestingFragment = fragment; 2509 final SemanticsNode node = interestingFragment.compileChildren( 2510 parentSemanticsClipRect: _semantics?.parentSemanticsClipRect, 2511 parentPaintClipRect: _semantics?.parentPaintClipRect, 2512 elevationAdjustment: _semantics?.elevationAdjustment ?? 0.0, 2513 ).single; 2514 // Fragment only wants to add this node's SemanticsNode to the parent. 2515 assert(interestingFragment.config == null && node == _semantics); 2516 } 2517 2518 /// Returns the semantics that this node would like to add to its parent. 2519 _SemanticsFragment _getSemanticsForParent({ 2520 @required bool mergeIntoParent, 2521 }) { 2522 assert(mergeIntoParent != null); 2523 assert(!_needsLayout, 'Updated layout information required for $this to calculate semantics.'); 2524 2525 final SemanticsConfiguration config = _semanticsConfiguration; 2526 bool dropSemanticsOfPreviousSiblings = config.isBlockingSemanticsOfPreviouslyPaintedNodes; 2527 2528 final bool producesForkingFragment = !config.hasBeenAnnotated && !config.isSemanticBoundary; 2529 final List<_InterestingSemanticsFragment> fragments = <_InterestingSemanticsFragment>[]; 2530 final Set<_InterestingSemanticsFragment> toBeMarkedExplicit = <_InterestingSemanticsFragment>{}; 2531 final bool childrenMergeIntoParent = mergeIntoParent || config.isMergingSemanticsOfDescendants; 2532 2533 // When set to true there's currently not enough information in this subtree 2534 // to compute semantics. In this case the walk needs to be aborted and no 2535 // SemanticsNodes in the subtree should be updated. 2536 // This will be true for subtrees that are currently kept alive by a 2537 // viewport but not laid out. 2538 bool abortWalk = false; 2539 2540 visitChildrenForSemantics((RenderObject renderChild) { 2541 if (abortWalk || _needsLayout) { 2542 abortWalk = true; 2543 return; 2544 } 2545 final _SemanticsFragment parentFragment = renderChild._getSemanticsForParent( 2546 mergeIntoParent: childrenMergeIntoParent, 2547 ); 2548 if (parentFragment.abortsWalk) { 2549 abortWalk = true; 2550 return; 2551 } 2552 if (parentFragment.dropsSemanticsOfPreviousSiblings) { 2553 fragments.clear(); 2554 toBeMarkedExplicit.clear(); 2555 if (!config.isSemanticBoundary) 2556 dropSemanticsOfPreviousSiblings = true; 2557 } 2558 // Figure out which child fragments are to be made explicit. 2559 for (_InterestingSemanticsFragment fragment in parentFragment.interestingFragments) { 2560 fragments.add(fragment); 2561 fragment.addAncestor(this); 2562 fragment.addTags(config.tagsForChildren); 2563 if (config.explicitChildNodes || parent is! RenderObject) { 2564 fragment.markAsExplicit(); 2565 continue; 2566 } 2567 if (!fragment.hasConfigForParent || producesForkingFragment) 2568 continue; 2569 if (!config.isCompatibleWith(fragment.config)) 2570 toBeMarkedExplicit.add(fragment); 2571 for (_InterestingSemanticsFragment siblingFragment in fragments.sublist(0, fragments.length - 1)) { 2572 if (!fragment.config.isCompatibleWith(siblingFragment.config)) { 2573 toBeMarkedExplicit.add(fragment); 2574 toBeMarkedExplicit.add(siblingFragment); 2575 } 2576 } 2577 } 2578 }); 2579 2580 if (abortWalk) { 2581 return _AbortingSemanticsFragment(owner: this); 2582 } 2583 2584 for (_InterestingSemanticsFragment fragment in toBeMarkedExplicit) 2585 fragment.markAsExplicit(); 2586 2587 _needsSemanticsUpdate = false; 2588 2589 _SemanticsFragment result; 2590 if (parent is! RenderObject) { 2591 assert(!config.hasBeenAnnotated); 2592 assert(!mergeIntoParent); 2593 result = _RootSemanticsFragment( 2594 owner: this, 2595 dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings, 2596 ); 2597 } else if (producesForkingFragment) { 2598 result = _ContainerSemanticsFragment( 2599 dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings, 2600 ); 2601 } else { 2602 result = _SwitchableSemanticsFragment( 2603 config: config, 2604 mergeIntoParent: mergeIntoParent, 2605 owner: this, 2606 dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings, 2607 ); 2608 if (config.isSemanticBoundary) { 2609 final _SwitchableSemanticsFragment fragment = result; 2610 fragment.markAsExplicit(); 2611 } 2612 } 2613 2614 result.addAll(fragments); 2615 2616 return result; 2617 } 2618 2619 /// Called when collecting the semantics of this node. 2620 /// 2621 /// The implementation has to return the children in paint order skipping all 2622 /// children that are not semantically relevant (e.g. because they are 2623 /// invisible). 2624 /// 2625 /// The default implementation mirrors the behavior of 2626 /// [visitChildren()] (which is supposed to walk all the children). 2627 void visitChildrenForSemantics(RenderObjectVisitor visitor) { 2628 visitChildren(visitor); 2629 } 2630 2631 /// Assemble the [SemanticsNode] for this [RenderObject]. 2632 /// 2633 /// If [isSemanticBoundary] is true, this method is called with the `node` 2634 /// created for this [RenderObject], the `config` to be applied to that node 2635 /// and the `children` [SemanticNode]s that descendants of this RenderObject 2636 /// have generated. 2637 /// 2638 /// By default, the method will annotate `node` with `config` and add the 2639 /// `children` to it. 2640 /// 2641 /// Subclasses can override this method to add additional [SemanticsNode]s 2642 /// to the tree. If new [SemanticsNode]s are instantiated in this method 2643 /// they must be disposed in [clearSemantics]. 2644 void assembleSemanticsNode( 2645 SemanticsNode node, 2646 SemanticsConfiguration config, 2647 Iterable<SemanticsNode> children, 2648 ) { 2649 assert(node == _semantics); 2650 node.updateWith(config: config, childrenInInversePaintOrder: children); 2651 } 2652 2653 // EVENTS 2654 2655 /// Override this method to handle pointer events that hit this render object. 2656 @override 2657 void handleEvent(PointerEvent event, covariant HitTestEntry entry) { } 2658 2659 2660 // HIT TESTING 2661 2662 // RenderObject subclasses are expected to have a method like the following 2663 // (with the signature being whatever passes for coordinates for this 2664 // particular class): 2665 // 2666 // bool hitTest(HitTestResult result, { Offset position }) { 2667 // // If the given position is not inside this node, then return false. 2668 // // Otherwise: 2669 // // For each child that intersects the position, in z-order starting from 2670 // // the top, call hitTest() for that child, passing it /result/, and the 2671 // // coordinates converted to the child's coordinate origin, and stop at 2672 // // the first child that returns true. 2673 // // Then, add yourself to /result/, and return true. 2674 // } 2675 // 2676 // If you add yourself to /result/ and still return false, then that means you 2677 // will see events but so will objects below you. 2678 2679 2680 /// Returns a human understandable name. 2681 @override 2682 String toStringShort() { 2683 String header = describeIdentity(this); 2684 if (_relayoutBoundary != null && _relayoutBoundary != this) { 2685 int count = 1; 2686 RenderObject target = parent; 2687 while (target != null && target != _relayoutBoundary) { 2688 target = target.parent; 2689 count += 1; 2690 } 2691 header += ' relayoutBoundary=up$count'; 2692 } 2693 if (_needsLayout) 2694 header += ' NEEDS-LAYOUT'; 2695 if (_needsPaint) 2696 header += ' NEEDS-PAINT'; 2697 if (_needsCompositingBitsUpdate) 2698 header += ' NEEDS-COMPOSITING-BITS-UPDATE'; 2699 if (!attached) 2700 header += ' DETACHED'; 2701 return header; 2702 } 2703 2704 @override 2705 String toString({ DiagnosticLevel minLevel = DiagnosticLevel.debug }) => toStringShort(); 2706 2707 /// Returns a description of the tree rooted at this node. 2708 /// If the prefix argument is provided, then every line in the output 2709 /// will be prefixed by that string. 2710 @override 2711 String toStringDeep({ 2712 String prefixLineOne = '', 2713 String prefixOtherLines = '', 2714 DiagnosticLevel minLevel = DiagnosticLevel.debug, 2715 }) { 2716 RenderObject debugPreviousActiveLayout; 2717 assert(() { 2718 debugPreviousActiveLayout = _debugActiveLayout; 2719 _debugActiveLayout = null; 2720 return true; 2721 }()); 2722 final String result = super.toStringDeep( 2723 prefixLineOne: prefixLineOne, 2724 prefixOtherLines: prefixOtherLines, 2725 minLevel: minLevel, 2726 ); 2727 assert(() { 2728 _debugActiveLayout = debugPreviousActiveLayout; 2729 return true; 2730 }()); 2731 return result; 2732 } 2733 2734 /// Returns a one-line detailed description of the render object. 2735 /// This description is often somewhat long. 2736 /// 2737 /// This includes the same information for this RenderObject as given by 2738 /// [toStringDeep], but does not recurse to any children. 2739 @override 2740 String toStringShallow({ 2741 String joiner = ', ', 2742 DiagnosticLevel minLevel = DiagnosticLevel.debug, 2743 }) { 2744 RenderObject debugPreviousActiveLayout; 2745 assert(() { 2746 debugPreviousActiveLayout = _debugActiveLayout; 2747 _debugActiveLayout = null; 2748 return true; 2749 }()); 2750 final String result = super.toStringShallow(joiner: joiner, minLevel: minLevel); 2751 assert(() { 2752 _debugActiveLayout = debugPreviousActiveLayout; 2753 return true; 2754 }()); 2755 return result; 2756 } 2757 2758 @protected 2759 @override 2760 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 2761 super.debugFillProperties(properties); 2762 properties.add(FlagProperty('needsCompositing', value: _needsCompositing, ifTrue: 'needs compositing')); 2763 properties.add(DiagnosticsProperty<dynamic>('creator', debugCreator, defaultValue: null, level: DiagnosticLevel.debug)); 2764 properties.add(DiagnosticsProperty<ParentData>('parentData', parentData, tooltip: _debugCanParentUseSize == true ? 'can use size' : null, missingIfNull: true)); 2765 properties.add(DiagnosticsProperty<Constraints>('constraints', constraints, missingIfNull: true)); 2766 // don't access it via the "layer" getter since that's only valid when we don't need paint 2767 properties.add(DiagnosticsProperty<ContainerLayer>('layer', _layer, defaultValue: null)); 2768 properties.add(DiagnosticsProperty<SemanticsNode>('semantics node', _semantics, defaultValue: null)); 2769 properties.add(FlagProperty( 2770 'isBlockingSemanticsOfPreviouslyPaintedNodes', 2771 value: _semanticsConfiguration.isBlockingSemanticsOfPreviouslyPaintedNodes, 2772 ifTrue: 'blocks semantics of earlier render objects below the common boundary', 2773 )); 2774 properties.add(FlagProperty('isSemanticBoundary', value: _semanticsConfiguration.isSemanticBoundary, ifTrue: 'semantic boundary')); 2775 } 2776 2777 @override 2778 List<DiagnosticsNode> debugDescribeChildren() => <DiagnosticsNode>[]; 2779 2780 /// Attempt to make (a portion of) this or a descendant [RenderObject] visible 2781 /// on screen. 2782 /// 2783 /// If `descendant` is provided, that [RenderObject] is made visible. If 2784 /// `descendant` is omitted, this [RenderObject] is made visible. 2785 /// 2786 /// The optional `rect` parameter describes which area of that [RenderObject] 2787 /// should be shown on screen. If `rect` is null, the entire 2788 /// [RenderObject] (as defined by its [paintBounds]) will be revealed. The 2789 /// `rect` parameter is interpreted relative to the coordinate system of 2790 /// `descendant` if that argument is provided and relative to this 2791 /// [RenderObject] otherwise. 2792 /// 2793 /// The `duration` parameter can be set to a non-zero value to bring the 2794 /// target object on screen in an animation defined by `curve`. 2795 void showOnScreen({ 2796 RenderObject descendant, 2797 Rect rect, 2798 Duration duration = Duration.zero, 2799 Curve curve = Curves.ease, 2800 }) { 2801 if (parent is RenderObject) { 2802 final RenderObject renderParent = parent; 2803 renderParent.showOnScreen( 2804 descendant: descendant ?? this, 2805 rect: rect, 2806 duration: duration, 2807 curve: curve, 2808 ); 2809 } 2810 } 2811 2812 /// Adds a debug representation of a [RenderObject] optimized for including in 2813 /// error messages. 2814 /// 2815 /// The default [style] of [DiagnosticsTreeStyle.shallow] ensures that all of 2816 /// the properties of the render object are included in the error output but 2817 /// none of the children of the object are. 2818 /// 2819 /// You should always include a RenderObject in an error message if it is the 2820 /// [RenderObject] causing the failure or contract violation of the error. 2821 DiagnosticsNode describeForError(String name, { DiagnosticsTreeStyle style = DiagnosticsTreeStyle.shallow }) { 2822 return toDiagnosticsNode(name: name, style: style); 2823 } 2824} 2825 2826/// Generic mixin for render objects with one child. 2827/// 2828/// Provides a child model for a render object subclass that has a unique child. 2829mixin RenderObjectWithChildMixin<ChildType extends RenderObject> on RenderObject { 2830 2831 /// Checks whether the given render object has the correct [runtimeType] to be 2832 /// a child of this render object. 2833 /// 2834 /// Does nothing if assertions are disabled. 2835 /// 2836 /// Always returns true. 2837 bool debugValidateChild(RenderObject child) { 2838 assert(() { 2839 if (child is! ChildType) { 2840 throw FlutterError.fromParts(<DiagnosticsNode>[ 2841 ErrorSummary( 2842 'A $runtimeType expected a child of type $ChildType but received a ' 2843 'child of type ${child.runtimeType}.' 2844 ), 2845 ErrorDescription( 2846 'RenderObjects expect specific types of children because they ' 2847 'coordinate with their children during layout and paint. For ' 2848 'example, a RenderSliver cannot be the child of a RenderBox because ' 2849 'a RenderSliver does not understand the RenderBox layout protocol.', 2850 ), 2851 ErrorSpacer(), 2852 DiagnosticsProperty<dynamic>( 2853 'The $runtimeType that expected a $ChildType child was created by', 2854 debugCreator, 2855 style: DiagnosticsTreeStyle.errorProperty, 2856 ), 2857 ErrorSpacer(), 2858 DiagnosticsProperty<dynamic>( 2859 'The ${child.runtimeType} that did not match the expected child type ' 2860 'was created by', 2861 child.debugCreator, 2862 style: DiagnosticsTreeStyle.errorProperty, 2863 ) 2864 ]); 2865 } 2866 return true; 2867 }()); 2868 return true; 2869 } 2870 2871 ChildType _child; 2872 /// The render object's unique child 2873 ChildType get child => _child; 2874 set child(ChildType value) { 2875 if (_child != null) 2876 dropChild(_child); 2877 _child = value; 2878 if (_child != null) 2879 adoptChild(_child); 2880 } 2881 2882 @override 2883 void attach(PipelineOwner owner) { 2884 super.attach(owner); 2885 if (_child != null) 2886 _child.attach(owner); 2887 } 2888 2889 @override 2890 void detach() { 2891 super.detach(); 2892 if (_child != null) 2893 _child.detach(); 2894 } 2895 2896 @override 2897 void redepthChildren() { 2898 if (_child != null) 2899 redepthChild(_child); 2900 } 2901 2902 @override 2903 void visitChildren(RenderObjectVisitor visitor) { 2904 if (_child != null) 2905 visitor(_child); 2906 } 2907 2908 @override 2909 List<DiagnosticsNode> debugDescribeChildren() { 2910 return child != null ? <DiagnosticsNode>[child.toDiagnosticsNode(name: 'child')] : <DiagnosticsNode>[]; 2911 } 2912} 2913 2914/// Parent data to support a doubly-linked list of children. 2915mixin ContainerParentDataMixin<ChildType extends RenderObject> on ParentData { 2916 /// The previous sibling in the parent's child list. 2917 ChildType previousSibling; 2918 /// The next sibling in the parent's child list. 2919 ChildType nextSibling; 2920 2921 /// Clear the sibling pointers. 2922 @override 2923 void detach() { 2924 assert(previousSibling == null, 'Pointers to siblings must be nulled before detaching ParentData.'); 2925 assert(nextSibling == null, 'Pointers to siblings must be nulled before detaching ParentData.'); 2926 super.detach(); 2927 } 2928} 2929 2930/// Generic mixin for render objects with a list of children. 2931/// 2932/// Provides a child model for a render object subclass that has a doubly-linked 2933/// list of children. 2934mixin ContainerRenderObjectMixin<ChildType extends RenderObject, ParentDataType extends ContainerParentDataMixin<ChildType>> on RenderObject { 2935 bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) { 2936 ParentDataType childParentData = child.parentData; 2937 while (childParentData.previousSibling != null) { 2938 assert(childParentData.previousSibling != child); 2939 child = childParentData.previousSibling; 2940 childParentData = child.parentData; 2941 } 2942 return child == equals; 2943 } 2944 bool _debugUltimateNextSiblingOf(ChildType child, { ChildType equals }) { 2945 ParentDataType childParentData = child.parentData; 2946 while (childParentData.nextSibling != null) { 2947 assert(childParentData.nextSibling != child); 2948 child = childParentData.nextSibling; 2949 childParentData = child.parentData; 2950 } 2951 return child == equals; 2952 } 2953 2954 int _childCount = 0; 2955 /// The number of children. 2956 int get childCount => _childCount; 2957 2958 /// Checks whether the given render object has the correct [runtimeType] to be 2959 /// a child of this render object. 2960 /// 2961 /// Does nothing if assertions are disabled. 2962 /// 2963 /// Always returns true. 2964 bool debugValidateChild(RenderObject child) { 2965 assert(() { 2966 if (child is! ChildType) { 2967 throw FlutterError.fromParts(<DiagnosticsNode>[ 2968 ErrorSummary( 2969 'A $runtimeType expected a child of type $ChildType but received a ' 2970 'child of type ${child.runtimeType}.' 2971 ), 2972 ErrorDescription( 2973 'RenderObjects expect specific types of children because they ' 2974 'coordinate with their children during layout and paint. For ' 2975 'example, a RenderSliver cannot be the child of a RenderBox because ' 2976 'a RenderSliver does not understand the RenderBox layout protocol.' 2977 ), 2978 ErrorSpacer(), 2979 DiagnosticsProperty<dynamic>( 2980 'The $runtimeType that expected a $ChildType child was created by', 2981 debugCreator, 2982 style: DiagnosticsTreeStyle.errorProperty, 2983 ), 2984 ErrorSpacer(), 2985 DiagnosticsProperty<dynamic>( 2986 'The ${child.runtimeType} that did not match the expected child type ' 2987 'was created by', 2988 child.debugCreator, 2989 style: DiagnosticsTreeStyle.errorProperty, 2990 ), 2991 ]); 2992 } 2993 return true; 2994 }()); 2995 return true; 2996 } 2997 2998 ChildType _firstChild; 2999 ChildType _lastChild; 3000 void _insertIntoChildList(ChildType child, { ChildType after }) { 3001 final ParentDataType childParentData = child.parentData; 3002 assert(childParentData.nextSibling == null); 3003 assert(childParentData.previousSibling == null); 3004 _childCount += 1; 3005 assert(_childCount > 0); 3006 if (after == null) { 3007 // insert at the start (_firstChild) 3008 childParentData.nextSibling = _firstChild; 3009 if (_firstChild != null) { 3010 final ParentDataType _firstChildParentData = _firstChild.parentData; 3011 _firstChildParentData.previousSibling = child; 3012 } 3013 _firstChild = child; 3014 _lastChild ??= child; 3015 } else { 3016 assert(_firstChild != null); 3017 assert(_lastChild != null); 3018 assert(_debugUltimatePreviousSiblingOf(after, equals: _firstChild)); 3019 assert(_debugUltimateNextSiblingOf(after, equals: _lastChild)); 3020 final ParentDataType afterParentData = after.parentData; 3021 if (afterParentData.nextSibling == null) { 3022 // insert at the end (_lastChild); we'll end up with two or more children 3023 assert(after == _lastChild); 3024 childParentData.previousSibling = after; 3025 afterParentData.nextSibling = child; 3026 _lastChild = child; 3027 } else { 3028 // insert in the middle; we'll end up with three or more children 3029 // set up links from child to siblings 3030 childParentData.nextSibling = afterParentData.nextSibling; 3031 childParentData.previousSibling = after; 3032 // set up links from siblings to child 3033 final ParentDataType childPreviousSiblingParentData = childParentData.previousSibling.parentData; 3034 final ParentDataType childNextSiblingParentData = childParentData.nextSibling.parentData; 3035 childPreviousSiblingParentData.nextSibling = child; 3036 childNextSiblingParentData.previousSibling = child; 3037 assert(afterParentData.nextSibling == child); 3038 } 3039 } 3040 } 3041 /// Insert child into this render object's child list after the given child. 3042 /// 3043 /// If `after` is null, then this inserts the child at the start of the list, 3044 /// and the child becomes the new [firstChild]. 3045 void insert(ChildType child, { ChildType after }) { 3046 assert(child != this, 'A RenderObject cannot be inserted into itself.'); 3047 assert(after != this, 'A RenderObject cannot simultaneously be both the parent and the sibling of another RenderObject.'); 3048 assert(child != after, 'A RenderObject cannot be inserted after itself.'); 3049 assert(child != _firstChild); 3050 assert(child != _lastChild); 3051 adoptChild(child); 3052 _insertIntoChildList(child, after: after); 3053 } 3054 3055 /// Append child to the end of this render object's child list. 3056 void add(ChildType child) { 3057 insert(child, after: _lastChild); 3058 } 3059 3060 /// Add all the children to the end of this render object's child list. 3061 void addAll(List<ChildType> children) { 3062 children?.forEach(add); 3063 } 3064 3065 void _removeFromChildList(ChildType child) { 3066 final ParentDataType childParentData = child.parentData; 3067 assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild)); 3068 assert(_debugUltimateNextSiblingOf(child, equals: _lastChild)); 3069 assert(_childCount >= 0); 3070 if (childParentData.previousSibling == null) { 3071 assert(_firstChild == child); 3072 _firstChild = childParentData.nextSibling; 3073 } else { 3074 final ParentDataType childPreviousSiblingParentData = childParentData.previousSibling.parentData; 3075 childPreviousSiblingParentData.nextSibling = childParentData.nextSibling; 3076 } 3077 if (childParentData.nextSibling == null) { 3078 assert(_lastChild == child); 3079 _lastChild = childParentData.previousSibling; 3080 } else { 3081 final ParentDataType childNextSiblingParentData = childParentData.nextSibling.parentData; 3082 childNextSiblingParentData.previousSibling = childParentData.previousSibling; 3083 } 3084 childParentData.previousSibling = null; 3085 childParentData.nextSibling = null; 3086 _childCount -= 1; 3087 } 3088 3089 /// Remove this child from the child list. 3090 /// 3091 /// Requires the child to be present in the child list. 3092 void remove(ChildType child) { 3093 _removeFromChildList(child); 3094 dropChild(child); 3095 } 3096 3097 /// Remove all their children from this render object's child list. 3098 /// 3099 /// More efficient than removing them individually. 3100 void removeAll() { 3101 ChildType child = _firstChild; 3102 while (child != null) { 3103 final ParentDataType childParentData = child.parentData; 3104 final ChildType next = childParentData.nextSibling; 3105 childParentData.previousSibling = null; 3106 childParentData.nextSibling = null; 3107 dropChild(child); 3108 child = next; 3109 } 3110 _firstChild = null; 3111 _lastChild = null; 3112 _childCount = 0; 3113 } 3114 3115 /// Move the given `child` in the child list to be after another child. 3116 /// 3117 /// More efficient than removing and re-adding the child. Requires the child 3118 /// to already be in the child list at some position. Pass null for `after` to 3119 /// move the child to the start of the child list. 3120 void move(ChildType child, { ChildType after }) { 3121 assert(child != this); 3122 assert(after != this); 3123 assert(child != after); 3124 assert(child.parent == this); 3125 final ParentDataType childParentData = child.parentData; 3126 if (childParentData.previousSibling == after) 3127 return; 3128 _removeFromChildList(child); 3129 _insertIntoChildList(child, after: after); 3130 markNeedsLayout(); 3131 } 3132 3133 @override 3134 void attach(PipelineOwner owner) { 3135 super.attach(owner); 3136 ChildType child = _firstChild; 3137 while (child != null) { 3138 child.attach(owner); 3139 final ParentDataType childParentData = child.parentData; 3140 child = childParentData.nextSibling; 3141 } 3142 } 3143 3144 @override 3145 void detach() { 3146 super.detach(); 3147 ChildType child = _firstChild; 3148 while (child != null) { 3149 child.detach(); 3150 final ParentDataType childParentData = child.parentData; 3151 child = childParentData.nextSibling; 3152 } 3153 } 3154 3155 @override 3156 void redepthChildren() { 3157 ChildType child = _firstChild; 3158 while (child != null) { 3159 redepthChild(child); 3160 final ParentDataType childParentData = child.parentData; 3161 child = childParentData.nextSibling; 3162 } 3163 } 3164 3165 @override 3166 void visitChildren(RenderObjectVisitor visitor) { 3167 ChildType child = _firstChild; 3168 while (child != null) { 3169 visitor(child); 3170 final ParentDataType childParentData = child.parentData; 3171 child = childParentData.nextSibling; 3172 } 3173 } 3174 3175 /// The first child in the child list. 3176 ChildType get firstChild => _firstChild; 3177 3178 /// The last child in the child list. 3179 ChildType get lastChild => _lastChild; 3180 3181 /// The previous child before the given child in the child list. 3182 ChildType childBefore(ChildType child) { 3183 assert(child != null); 3184 assert(child.parent == this); 3185 final ParentDataType childParentData = child.parentData; 3186 return childParentData.previousSibling; 3187 } 3188 3189 /// The next child after the given child in the child list. 3190 ChildType childAfter(ChildType child) { 3191 assert(child != null); 3192 assert(child.parent == this); 3193 final ParentDataType childParentData = child.parentData; 3194 return childParentData.nextSibling; 3195 } 3196 3197 @override 3198 List<DiagnosticsNode> debugDescribeChildren() { 3199 final List<DiagnosticsNode> children = <DiagnosticsNode>[]; 3200 if (firstChild != null) { 3201 ChildType child = firstChild; 3202 int count = 1; 3203 while (true) { 3204 children.add(child.toDiagnosticsNode(name: 'child $count')); 3205 if (child == lastChild) 3206 break; 3207 count += 1; 3208 final ParentDataType childParentData = child.parentData; 3209 child = childParentData.nextSibling; 3210 } 3211 } 3212 return children; 3213 } 3214} 3215 3216/// Variant of [FlutterErrorDetails] with extra fields for the rendering 3217/// library. 3218class FlutterErrorDetailsForRendering extends FlutterErrorDetails { 3219 /// Creates a [FlutterErrorDetailsForRendering] object with the given 3220 /// arguments setting the object's properties. 3221 /// 3222 /// The rendering library calls this constructor when catching an exception 3223 /// that will subsequently be reported using [FlutterError.onError]. 3224 const FlutterErrorDetailsForRendering({ 3225 dynamic exception, 3226 StackTrace stack, 3227 String library, 3228 DiagnosticsNode context, 3229 this.renderObject, 3230 InformationCollector informationCollector, 3231 bool silent = false, 3232 }) : super( 3233 exception: exception, 3234 stack: stack, 3235 library: library, 3236 context: context, 3237 informationCollector: informationCollector, 3238 silent: silent 3239 ); 3240 3241 /// The RenderObject that was being processed when the exception was caught. 3242 final RenderObject renderObject; 3243} 3244 3245/// Describes the semantics information a [RenderObject] wants to add to its 3246/// parent. 3247/// 3248/// It has two notable subclasses: 3249/// * [_InterestingSemanticsFragment] describing actual semantic information to 3250/// be added to the parent. 3251/// * [_ContainerSemanticsFragment]: a container class to transport the semantic 3252/// information of multiple [_InterestingSemanticsFragment] to a parent. 3253abstract class _SemanticsFragment { 3254 _SemanticsFragment({@required this.dropsSemanticsOfPreviousSiblings }) 3255 : assert (dropsSemanticsOfPreviousSiblings != null); 3256 3257 /// Incorporate the fragments of children into this fragment. 3258 void addAll(Iterable<_InterestingSemanticsFragment> fragments); 3259 3260 /// Whether this fragment wants to make the semantics information of 3261 /// previously painted [RenderObject]s unreachable for accessibility purposes. 3262 /// 3263 /// See also: 3264 /// 3265 /// * [SemanticsConfiguration.isBlockingSemanticsOfPreviouslyPaintedNodes] 3266 /// describes what semantics are dropped in more detail. 3267 final bool dropsSemanticsOfPreviousSiblings; 3268 3269 /// Returns [_InterestingSemanticsFragment] describing the actual semantic 3270 /// information that this fragment wants to add to the parent. 3271 Iterable<_InterestingSemanticsFragment> get interestingFragments; 3272 3273 /// Whether this fragment wants to abort the semantics walk because the 3274 /// information in the tree are not sufficient to calculate semantics. 3275 /// 3276 /// This happens for subtrees that are currently kept alive by a viewport but 3277 /// not laid out. 3278 /// 3279 /// See also: 3280 /// 3281 /// * [_AbortingSemanticsFragment], which sets this to true. 3282 bool get abortsWalk => false; 3283} 3284 3285/// A container used when a [RenderObject] wants to add multiple independent 3286/// [_InterestingSemanticsFragment] to its parent. 3287/// 3288/// The [_InterestingSemanticsFragment] to be added to the parent can be 3289/// obtained via [interestingFragments]. 3290class _ContainerSemanticsFragment extends _SemanticsFragment { 3291 3292 _ContainerSemanticsFragment({ @required bool dropsSemanticsOfPreviousSiblings }) 3293 : super(dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings); 3294 3295 @override 3296 void addAll(Iterable<_InterestingSemanticsFragment> fragments) { 3297 interestingFragments.addAll(fragments); 3298 } 3299 3300 @override 3301 final List<_InterestingSemanticsFragment> interestingFragments = <_InterestingSemanticsFragment>[]; 3302} 3303 3304/// A [_SemanticsFragment] that describes which concrete semantic information 3305/// a [RenderObject] wants to add to the [SemanticsNode] of its parent. 3306/// 3307/// Specifically, it describes which children (as returned by [compileChildren]) 3308/// should be added to the parent's [SemanticsNode] and which [config] should be 3309/// merged into the parent's [SemanticsNode]. 3310abstract class _InterestingSemanticsFragment extends _SemanticsFragment { 3311 _InterestingSemanticsFragment({ 3312 @required RenderObject owner, 3313 @required bool dropsSemanticsOfPreviousSiblings, 3314 }) : assert(owner != null), 3315 _ancestorChain = <RenderObject>[owner], 3316 super(dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings); 3317 3318 /// The [RenderObject] that owns this fragment (and any new [SemanticNode] 3319 /// introduced by it). 3320 RenderObject get owner => _ancestorChain.first; 3321 3322 final List<RenderObject> _ancestorChain; 3323 3324 /// The children to be added to the parent. 3325 /// 3326 /// See also: 3327 /// 3328 /// * [SemanticsNode.parentSemanticsClipRect] for the source and definition 3329 /// of the `parentSemanticsClipRect` argument. 3330 /// * [SemanticsNode.parentPaintClipRect] for the source and definition 3331 // of the `parentPaintClipRect` argument. 3332 /// * [SemanticsNode.elevationAdjustment] for the source and definition 3333 // of the `elevationAdjustment` argument. 3334 Iterable<SemanticsNode> compileChildren({ 3335 @required Rect parentSemanticsClipRect, 3336 @required Rect parentPaintClipRect, 3337 @required double elevationAdjustment, 3338 }); 3339 3340 /// The [SemanticsConfiguration] the child wants to merge into the parent's 3341 /// [SemanticsNode] or null if it doesn't want to merge anything. 3342 SemanticsConfiguration get config; 3343 3344 /// Disallows this fragment to merge any configuration into its parent's 3345 /// [SemanticsNode]. 3346 /// 3347 /// After calling this the fragment will only produce children to be added 3348 /// to the parent and it will return null for [config]. 3349 void markAsExplicit(); 3350 3351 /// Consume the fragments of children. 3352 /// 3353 /// For each provided fragment it will add that fragment's children to 3354 /// this fragment's children (as returned by [compileChildren]) and merge that 3355 /// fragment's [config] into this fragment's [config]. 3356 /// 3357 /// If a provided fragment should not merge anything into [config] call 3358 /// [markAsExplicit] before passing the fragment to this method. 3359 @override 3360 void addAll(Iterable<_InterestingSemanticsFragment> fragments); 3361 3362 /// Whether this fragment wants to add any semantic information to the parent 3363 /// [SemanticsNode]. 3364 bool get hasConfigForParent => config != null; 3365 3366 @override 3367 Iterable<_InterestingSemanticsFragment> get interestingFragments sync* { 3368 yield this; 3369 } 3370 3371 Set<SemanticsTag> _tagsForChildren; 3372 3373 /// Tag all children produced by [compileChildren] with `tags`. 3374 void addTags(Iterable<SemanticsTag> tags) { 3375 if (tags == null || tags.isEmpty) 3376 return; 3377 _tagsForChildren ??= <SemanticsTag>{}; 3378 _tagsForChildren.addAll(tags); 3379 } 3380 3381 /// Adds the geometric information of `ancestor` to this object. 3382 /// 3383 /// Those information are required to properly compute the value for 3384 /// [SemanticsNode.transform], [SemanticsNode.clipRect], and 3385 /// [SemanticsNode.rect]. 3386 /// 3387 /// Ancestors have to be added in order from [owner] up until the next 3388 /// [RenderObject] that owns a [SemanticsNode] is reached. 3389 void addAncestor(RenderObject ancestor) { 3390 _ancestorChain.add(ancestor); 3391 } 3392} 3393 3394/// An [_InterestingSemanticsFragment] that produces the root [SemanticsNode] of 3395/// the semantics tree. 3396/// 3397/// The root node is available as the only element in the Iterable returned by 3398/// [children]. 3399class _RootSemanticsFragment extends _InterestingSemanticsFragment { 3400 _RootSemanticsFragment({ 3401 @required RenderObject owner, 3402 @required bool dropsSemanticsOfPreviousSiblings, 3403 }) : super(owner: owner, dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings); 3404 3405 @override 3406 Iterable<SemanticsNode> compileChildren({ Rect parentSemanticsClipRect, Rect parentPaintClipRect, double elevationAdjustment }) sync* { 3407 assert(_tagsForChildren == null || _tagsForChildren.isEmpty); 3408 assert(parentSemanticsClipRect == null); 3409 assert(parentPaintClipRect == null); 3410 assert(_ancestorChain.length == 1); 3411 assert(elevationAdjustment == 0.0); 3412 3413 owner._semantics ??= SemanticsNode.root( 3414 showOnScreen: owner.showOnScreen, 3415 owner: owner.owner.semanticsOwner, 3416 ); 3417 final SemanticsNode node = owner._semantics; 3418 assert(MatrixUtils.matrixEquals(node.transform, Matrix4.identity())); 3419 assert(node.parentSemanticsClipRect == null); 3420 assert(node.parentPaintClipRect == null); 3421 3422 node.rect = owner.semanticBounds; 3423 3424 final List<SemanticsNode> children = _children 3425 .expand((_InterestingSemanticsFragment fragment) { 3426 assert(fragment.config == null); 3427 return fragment.compileChildren( 3428 parentSemanticsClipRect: parentSemanticsClipRect, 3429 parentPaintClipRect: parentPaintClipRect, 3430 elevationAdjustment: 0.0, 3431 ); 3432 }) 3433 .toList(); 3434 node.updateWith(config: null, childrenInInversePaintOrder: children); 3435 3436 // The root node is the only semantics node allowed to be invisible. This 3437 // can happen when the canvas the app is drawn on has a size of 0 by 0 3438 // pixel. If this happens, the root node must not have any children (because 3439 // these would be invisible as well and are therefore excluded from the 3440 // tree). 3441 assert(!node.isInvisible || children.isEmpty); 3442 yield node; 3443 } 3444 3445 @override 3446 SemanticsConfiguration get config => null; 3447 3448 final List<_InterestingSemanticsFragment> _children = <_InterestingSemanticsFragment>[]; 3449 3450 @override 3451 void markAsExplicit() { 3452 // nothing to do, we are always explicit. 3453 } 3454 3455 @override 3456 void addAll(Iterable<_InterestingSemanticsFragment> fragments) { 3457 _children.addAll(fragments); 3458 } 3459} 3460 3461/// An [_InterestingSemanticsFragment] that can be told to only add explicit 3462/// [SemanticsNode]s to the parent. 3463/// 3464/// If [markAsExplicit] was not called before this fragment is added to 3465/// another fragment it will merge [config] into the parent's [SemanticsNode] 3466/// and add its [children] to it. 3467/// 3468/// If [markAsExplicit] was called before adding this fragment to another 3469/// fragment it will create a new [SemanticsNode]. The newly created node will 3470/// be annotated with the [SemanticsConfiguration] that - without the call to 3471/// [markAsExplicit] - would have been merged into the parent's [SemanticsNode]. 3472/// Similarly, the new node will also take over the children that otherwise 3473/// would have been added to the parent's [SemanticsNode]. 3474/// 3475/// After a call to [markAsExplicit] the only element returned by [children] 3476/// is the newly created node and [config] will return null as the fragment 3477/// no longer wants to merge any semantic information into the parent's 3478/// [SemanticsNode]. 3479class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment { 3480 _SwitchableSemanticsFragment({ 3481 @required bool mergeIntoParent, 3482 @required SemanticsConfiguration config, 3483 @required RenderObject owner, 3484 @required bool dropsSemanticsOfPreviousSiblings, 3485 }) : _mergeIntoParent = mergeIntoParent, 3486 _config = config, 3487 assert(mergeIntoParent != null), 3488 assert(config != null), 3489 super(owner: owner, dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings); 3490 3491 final bool _mergeIntoParent; 3492 SemanticsConfiguration _config; 3493 bool _isConfigWritable = false; 3494 final List<_InterestingSemanticsFragment> _children = <_InterestingSemanticsFragment>[]; 3495 3496 @override 3497 Iterable<SemanticsNode> compileChildren({ Rect parentSemanticsClipRect, Rect parentPaintClipRect, double elevationAdjustment }) sync* { 3498 if (!_isExplicit) { 3499 owner._semantics = null; 3500 for (_InterestingSemanticsFragment fragment in _children) { 3501 assert(_ancestorChain.first == fragment._ancestorChain.last); 3502 fragment._ancestorChain.addAll(_ancestorChain.sublist(1)); 3503 yield* fragment.compileChildren( 3504 parentSemanticsClipRect: parentSemanticsClipRect, 3505 parentPaintClipRect: parentPaintClipRect, 3506 // The fragment is not explicit, its elevation has been absorbed by 3507 // the parent config (as thickness). We still need to make sure that 3508 // its children are placed at the elevation dictated by this config. 3509 elevationAdjustment: elevationAdjustment + _config.elevation, 3510 ); 3511 } 3512 return; 3513 } 3514 3515 final _SemanticsGeometry geometry = _needsGeometryUpdate 3516 ? _SemanticsGeometry(parentSemanticsClipRect: parentSemanticsClipRect, parentPaintClipRect: parentPaintClipRect, ancestors: _ancestorChain) 3517 : null; 3518 3519 if (!_mergeIntoParent && (geometry?.dropFromTree == true)) 3520 return; // Drop the node, it's not going to be visible. 3521 3522 owner._semantics ??= SemanticsNode(showOnScreen: owner.showOnScreen); 3523 final SemanticsNode node = owner._semantics 3524 ..isMergedIntoParent = _mergeIntoParent 3525 ..tags = _tagsForChildren; 3526 3527 node.elevationAdjustment = elevationAdjustment; 3528 if (elevationAdjustment != 0.0) { 3529 _ensureConfigIsWritable(); 3530 _config.elevation += elevationAdjustment; 3531 } 3532 3533 if (geometry != null) { 3534 assert(_needsGeometryUpdate); 3535 node 3536 ..rect = geometry.rect 3537 ..transform = geometry.transform 3538 ..parentSemanticsClipRect = geometry.semanticsClipRect 3539 ..parentPaintClipRect = geometry.paintClipRect; 3540 if (!_mergeIntoParent && geometry.markAsHidden) { 3541 _ensureConfigIsWritable(); 3542 _config.isHidden = true; 3543 } 3544 } 3545 3546 final List<SemanticsNode> children = _children 3547 .expand((_InterestingSemanticsFragment fragment) => fragment.compileChildren( 3548 parentSemanticsClipRect: node.parentSemanticsClipRect, 3549 parentPaintClipRect: node.parentPaintClipRect, 3550 elevationAdjustment: 0.0, 3551 )) 3552 .toList(); 3553 3554 if (_config.isSemanticBoundary) { 3555 owner.assembleSemanticsNode(node, _config, children); 3556 } else { 3557 node.updateWith(config: _config, childrenInInversePaintOrder: children); 3558 } 3559 3560 yield node; 3561 } 3562 3563 @override 3564 SemanticsConfiguration get config { 3565 return _isExplicit ? null : _config; 3566 } 3567 3568 @override 3569 void addAll(Iterable<_InterestingSemanticsFragment> fragments) { 3570 for (_InterestingSemanticsFragment fragment in fragments) { 3571 _children.add(fragment); 3572 if (fragment.config == null) 3573 continue; 3574 _ensureConfigIsWritable(); 3575 _config.absorb(fragment.config); 3576 } 3577 } 3578 3579 void _ensureConfigIsWritable() { 3580 if (!_isConfigWritable) { 3581 _config = _config.copy(); 3582 _isConfigWritable = true; 3583 } 3584 } 3585 3586 bool _isExplicit = false; 3587 3588 @override 3589 void markAsExplicit() { 3590 _isExplicit = true; 3591 } 3592 3593 bool get _needsGeometryUpdate => _ancestorChain.length > 1; 3594} 3595 3596 3597/// [_SemanticsFragment] used to indicate that the current information in this 3598/// subtree is not sufficient to update semantics. 3599/// 3600/// Anybody processing this [_SemanticsFragment] should abort the walk of the 3601/// current subtree without updating any [SemanticsNode]s as there is no semantic 3602/// information to compute. As a result, this fragment also doesn't carry any 3603/// semantics information either. 3604class _AbortingSemanticsFragment extends _InterestingSemanticsFragment { 3605 _AbortingSemanticsFragment({@required RenderObject owner}) : super(owner: owner, dropsSemanticsOfPreviousSiblings: false); 3606 3607 @override 3608 bool get abortsWalk => true; 3609 3610 @override 3611 SemanticsConfiguration get config => null; 3612 3613 @override 3614 void addAll(Iterable<_InterestingSemanticsFragment> fragments) { 3615 assert(false); 3616 } 3617 3618 @override 3619 Iterable<SemanticsNode> compileChildren({ Rect parentSemanticsClipRect, Rect parentPaintClipRect, double elevationAdjustment }) sync* { 3620 yield owner._semantics; 3621 } 3622 3623 @override 3624 void markAsExplicit() { 3625 // Is never explicit. 3626 } 3627} 3628 3629/// Helper class that keeps track of the geometry of a [SemanticsNode]. 3630/// 3631/// It is used to annotate a [SemanticsNode] with the current information for 3632/// [SemanticsNode.rect] and [SemanticsNode.transform]. 3633class _SemanticsGeometry { 3634 3635 /// The `parentClippingRect` may be null if no clip is to be applied. 3636 /// 3637 /// The `ancestors` list has to include all [RenderObject] in order that are 3638 /// located between the [SemanticsNode] whose geometry is represented here 3639 /// (first [RenderObject] in the list) and its closest ancestor [RenderObject] 3640 /// that also owns its own [SemanticsNode] (last [RenderObject] in the list). 3641 _SemanticsGeometry({ 3642 @required Rect parentSemanticsClipRect, 3643 @required Rect parentPaintClipRect, 3644 @required List<RenderObject> ancestors, 3645 }) { 3646 _computeValues(parentSemanticsClipRect, parentPaintClipRect, ancestors); 3647 } 3648 3649 Rect _paintClipRect; 3650 Rect _semanticsClipRect; 3651 Matrix4 _transform; 3652 Rect _rect; 3653 3654 /// Value for [SemanticsNode.transform]. 3655 Matrix4 get transform => _transform; 3656 3657 /// Value for [SemanticsNode.parentSemanticsClipRect]. 3658 Rect get semanticsClipRect => _semanticsClipRect; 3659 3660 /// Value for [SemanticsNode.parentPaintClipRect]. 3661 Rect get paintClipRect => _paintClipRect; 3662 3663 /// Value for [SemanticsNode.rect]. 3664 Rect get rect => _rect; 3665 3666 void _computeValues(Rect parentSemanticsClipRect, Rect parentPaintClipRect, List<RenderObject> ancestors) { 3667 assert(ancestors.length > 1); 3668 3669 _transform = Matrix4.identity(); 3670 _semanticsClipRect = parentSemanticsClipRect; 3671 _paintClipRect = parentPaintClipRect; 3672 for (int index = ancestors.length-1; index > 0; index -= 1) { 3673 final RenderObject parent = ancestors[index]; 3674 final RenderObject child = ancestors[index-1]; 3675 final Rect parentSemanticsClipRect = parent.describeSemanticsClip(child); 3676 if (parentSemanticsClipRect != null) { 3677 _semanticsClipRect = parentSemanticsClipRect; 3678 _paintClipRect = _intersectRects(_paintClipRect, parent.describeApproximatePaintClip(child)); 3679 } else { 3680 _semanticsClipRect = _intersectRects(_semanticsClipRect, parent.describeApproximatePaintClip(child)); 3681 } 3682 _temporaryTransformHolder.setIdentity(); // clears data from previous call(s) 3683 _applyIntermediatePaintTransforms(parent, child, _transform, _temporaryTransformHolder); 3684 _semanticsClipRect = _transformRect(_semanticsClipRect, _temporaryTransformHolder); 3685 _paintClipRect = _transformRect(_paintClipRect, _temporaryTransformHolder); 3686 } 3687 3688 final RenderObject owner = ancestors.first; 3689 _rect = _semanticsClipRect == null ? owner.semanticBounds : _semanticsClipRect.intersect(owner.semanticBounds); 3690 if (_paintClipRect != null) { 3691 final Rect paintRect = _paintClipRect.intersect(_rect); 3692 _markAsHidden = paintRect.isEmpty && !_rect.isEmpty; 3693 if (!_markAsHidden) 3694 _rect = paintRect; 3695 } 3696 } 3697 3698 // A matrix used to store transient transform data. 3699 // 3700 // Reusing this matrix avoids allocating a new matrix every time a temporary 3701 // matrix is needed. 3702 // 3703 // This instance should never be returned to the caller. Otherwise, the data 3704 // stored in it will be overwritten unpredictably by subsequent reuses. 3705 static final Matrix4 _temporaryTransformHolder = Matrix4.zero(); 3706 3707 /// From parent to child coordinate system. 3708 static Rect _transformRect(Rect rect, Matrix4 transform) { 3709 assert(transform != null); 3710 if (rect == null) 3711 return null; 3712 if (rect.isEmpty || transform.isZero()) 3713 return Rect.zero; 3714 return MatrixUtils.inverseTransformRect(transform, rect); 3715 } 3716 3717 // Calls applyPaintTransform on all of the render objects between [child] and 3718 // [ancestor]. This method handles cases where the immediate semantic parent 3719 // is not the immediate render object parent of the child. 3720 // 3721 // It will mutate both transform and clipRectTransform. 3722 static void _applyIntermediatePaintTransforms( 3723 RenderObject ancestor, 3724 RenderObject child, 3725 Matrix4 transform, 3726 Matrix4 clipRectTransform, 3727 ) { 3728 assert(ancestor != null); 3729 assert(child != null); 3730 assert(transform != null); 3731 assert(clipRectTransform != null); 3732 assert(clipRectTransform.isIdentity()); 3733 RenderObject intermediateParent = child.parent; 3734 assert(intermediateParent != null); 3735 while (intermediateParent != ancestor) { 3736 intermediateParent.applyPaintTransform(child, transform); 3737 intermediateParent = intermediateParent.parent; 3738 child = child.parent; 3739 assert(intermediateParent != null); 3740 } 3741 ancestor.applyPaintTransform(child, transform); 3742 ancestor.applyPaintTransform(child, clipRectTransform); 3743 } 3744 3745 static Rect _intersectRects(Rect a, Rect b) { 3746 if (a == null) 3747 return b; 3748 if (b == null) 3749 return a; 3750 return a.intersect(b); 3751 } 3752 3753 /// Whether the [SemanticsNode] annotated with the geometric information tracked 3754 /// by this object can be dropped from the semantics tree without losing 3755 /// semantics information. 3756 bool get dropFromTree { 3757 return _rect.isEmpty; 3758 } 3759 3760 /// Whether the [SemanticsNode] annotated with the geometric information 3761 /// tracked by this object should be marked as hidden because it is not 3762 /// visible on screen. 3763 /// 3764 /// Hidden elements should still be included in the tree to work around 3765 /// platform limitations (e.g. accessibility scrolling on iOS). 3766 /// 3767 /// See also: 3768 /// 3769 /// * [SemanticsFlag.isHidden] for the purpose of marking a node as hidden. 3770 bool get markAsHidden => _markAsHidden; 3771 bool _markAsHidden = false; 3772} 3773 3774/// A class that creates [DiagnosticsNode] by wrapping [RenderObject.debugCreator]. 3775/// 3776/// Attach a [DiagnosticsDebugCreator] into [FlutterErrorDetails.informationCollector] 3777/// when a [RenderObject.debugCreator] is available. This will lead to improved 3778/// error message. 3779class DiagnosticsDebugCreator extends DiagnosticsProperty<Object> { 3780 /// Create a [DiagnosticsProperty] with its [value] initialized to input 3781 /// [RenderObject.debugCreator]. 3782 DiagnosticsDebugCreator(Object value): 3783 assert(value != null), 3784 super( 3785 'debugCreator', 3786 value, 3787 level: DiagnosticLevel.hidden 3788 ); 3789} 3790