framework.dart 98.1 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:async';
6
import 'dart:collection';
7
import 'dart:developer';
8

9 10
import 'debug.dart';

11
import 'package:flutter/rendering.dart';
12
import 'package:flutter/foundation.dart';
pq's avatar
pq committed
13
import 'package:meta/meta.dart';
14

15
export 'dart:ui' show hashValues, hashList;
16
export 'package:flutter/rendering.dart' show RenderObject, RenderBox, debugPrint;
17
export 'package:flutter/foundation.dart' show FlutterError;
18

Hixie's avatar
Hixie committed
19 20
// KEYS

21
/// A [Key] is an identifier for [Widget]s and [Element]s.
22
///
23 24
/// A new widget will only be used to update an existing element if its key is
/// the same as the key of the current widget associted with the element.
Hixie's avatar
Hixie committed
25
///
26 27 28
/// Keys must be unique amongst the [Element]s with the same parent.
///
/// Subclasses of [Key] should either subclass [LocalKey] or [GlobalKey].
Eric Seidel's avatar
Eric Seidel committed
29
abstract class Key {
30 31
  /// Construct a [ValueKey<String>] with the given [String].
  ///
32
  /// This is the simplest way to create keys.
Hixie's avatar
Hixie committed
33
  factory Key(String value) => new ValueKey<String>(value);
Ian Hickson's avatar
Ian Hickson committed
34 35

  /// Default constructor, used by subclasses.
36 37 38 39
  ///
  /// Useful so that subclasses can call us, because the Key() factory
  /// constructor shadows the implicit constructor.
  const Key._();
40 41
}

Hixie's avatar
Hixie committed
42
/// A key that is not a [GlobalKey].
43 44 45
///
/// Keys must be unique amongst the [Element]s with the same parent. By
/// contrast, [GlobalKey]s must be unique across the entire app.
Hixie's avatar
Hixie committed
46 47
abstract class LocalKey extends Key {
  /// Default constructor, used by subclasses.
48
  const LocalKey() : super._();
Hixie's avatar
Hixie committed
49 50
}

51
/// A key that uses a value of a particular type to identify itself.
52
///
53 54
/// A [ValueKey<T>] is equal to another [ValueKey<T>] if, and only if, their
/// values are [operator==].
Hixie's avatar
Hixie committed
55
class ValueKey<T> extends LocalKey {
56
  /// Creates a key that delgates its [operator==] to the given value.
Hixie's avatar
Hixie committed
57
  const ValueKey(this.value);
58

59
  /// The value to which this key delegates its [operator==]
Hixie's avatar
Hixie committed
60
  final T value;
61 62

  @override
Hixie's avatar
Hixie committed
63 64 65 66 67 68
  bool operator ==(dynamic other) {
    if (other is! ValueKey<T>)
      return false;
    final ValueKey<T> typedOther = other;
    return value == typedOther.value;
  }
69 70

  @override
71
  int get hashCode => value.hashCode;
72 73

  @override
Hixie's avatar
Hixie committed
74
  String toString() => '[\'$value\']';
75 76
}

77
/// A key that is only equal to itself.
Hixie's avatar
Hixie committed
78
class UniqueKey extends LocalKey {
79 80
  /// Creates a key that is equal only to itself.
  UniqueKey();
81 82

  @override
Hixie's avatar
Hixie committed
83 84 85
  String toString() => '[$hashCode]';
}

86
/// A key that takes its identity from the object used as its value.
87
///
88 89
/// Used to tie the identity of a widget to the identity of an object used to
/// generate that widget.
Hixie's avatar
Hixie committed
90
class ObjectKey extends LocalKey {
91
  /// Creates a key that uses [identical] on [value] for its [operator==].
Hixie's avatar
Hixie committed
92
  const ObjectKey(this.value);
93

94
  /// The object whose identity is used by this key's [operator==].
95
  final Object value;
96 97

  @override
Hixie's avatar
Hixie committed
98 99 100 101 102 103
  bool operator ==(dynamic other) {
    if (other is! ObjectKey)
      return false;
    final ObjectKey typedOther = other;
    return identical(value, typedOther.value);
  }
104 105

  @override
106
  int get hashCode => identityHashCode(value);
107 108

  @override
Hixie's avatar
Hixie committed
109
  String toString() => '[${value.runtimeType}(${value.hashCode})]';
110 111
}

112
/// Signature for a callback when a global key is removed from the tree.
113
typedef void GlobalKeyRemoveListener(GlobalKey key);
114

115
/// A key that is unique across the entire app.
116
///
117 118 119
/// Global keys uniquely indentify elements. Global keys provide access to other
/// objects that are associated with elements, such as the a [BuildContext] and,
/// for [StatefulWidget]s, a [State].
120 121 122 123 124 125 126
///
/// Widgets that have global keys reparent their subtrees when they are moved
/// from one location in the tree to another location in the tree. In order to
/// reparent its subtree, a widget must arrive at its new location in the tree
/// in the same animation frame in which it was removed from its old location in
/// the tree.
///
127
/// Global keys are relatively expensive. If you don't need any of the features
128 129
/// listed above, consider using a [Key], [ValueKey], [ObjectKey], or
/// [UniqueKey] instead.
pq's avatar
pq committed
130
@optionalTypeArgs
131
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
132 133 134 135
  /// Creates a [LabeledGlobalKey], which is a [GlobalKey] with a label used for debugging.
  ///
  /// The label is purely for debugging and not used for comparing the identity
  /// of the key.
136
  factory GlobalKey({ String debugLabel }) => new LabeledGlobalKey<T>(debugLabel); // the label is purely for debugging purposes and is otherwise ignored
137

138 139 140 141 142
  /// Creates a global key without a label.
  ///
  /// Used by subclasss because the factory constructor shadows the implicit
  /// constructor.
  const GlobalKey.constructor() : super._();
Ian Hickson's avatar
Ian Hickson committed
143

144
  static final Map<GlobalKey, Element> _registry = new Map<GlobalKey, Element>();
145
  static final Map<GlobalKey, int> _debugDuplicates = new Map<GlobalKey, int>();
146
  static final Map<GlobalKey, Set<GlobalKeyRemoveListener>> _removeListeners = new Map<GlobalKey, Set<GlobalKeyRemoveListener>>();
147
  static final Set<GlobalKey> _removedKeys = new HashSet<GlobalKey>();
148

149
  void _register(Element element) {
150 151 152 153 154 155 156 157
    assert(() {
      if (_registry.containsKey(this)) {
        int oldCount = _debugDuplicates.putIfAbsent(this, () => 1);
        assert(oldCount >= 1);
        _debugDuplicates[this] = oldCount + 1;
      }
      return true;
    });
158
    _registry[this] = element;
159 160
  }

161
  void _unregister(Element element) {
162 163 164 165 166 167 168 169 170 171 172 173
    assert(() {
      if (_registry.containsKey(this) && _debugDuplicates.containsKey(this)) {
        int oldCount = _debugDuplicates[this];
        assert(oldCount >= 2);
        if (oldCount == 2) {
          _debugDuplicates.remove(this);
        } else {
          _debugDuplicates[this] = oldCount - 1;
        }
      }
      return true;
    });
174
    if (_registry[this] == element) {
175 176 177 178 179
      _registry.remove(this);
      _removedKeys.add(this);
    }
  }

180
  Element get _currentElement => _registry[this];
181 182 183 184 185

  /// The build context in which the widget with this key builds.
  ///
  /// The current context is null if there is no widget in the tree that matches
  /// this global key.
186
  BuildContext get currentContext => _currentElement;
187 188 189 190 191

  /// The widget in the tree that currently has this global key.
  ///
  /// The current widget is null if there is no widget in the tree that matches
  /// this global key.
192
  Widget get currentWidget => _currentElement?.widget;
193 194 195 196 197 198

  /// The [State] for the widget in the tree that currently has this global key.
  ///
  /// The current state is null if (1) there is no widget in the tree that
  /// matches this global key, (2) that widget is not a [StatefulWidget], or the
  /// assoicated [State] object is not a subtype of `T`.
199
  T get currentState {
200
    Element element = _currentElement;
201 202
    if (element is StatefulElement) {
      StatefulElement statefulElement = element;
203 204 205
      State state = statefulElement.state;
      if (state is T)
        return state;
206
    }
207
    return null;
208 209
  }

210 211 212 213
  /// Calls `listener` whenever a widget with the given global key is removed
  /// from the tree.
  ///
  /// Listeners can be removed with [unregisterRemoveListener].
214 215 216
  static void registerRemoveListener(GlobalKey key, GlobalKeyRemoveListener listener) {
    assert(key != null);
    Set<GlobalKeyRemoveListener> listeners =
217
        _removeListeners.putIfAbsent(key, () => new HashSet<GlobalKeyRemoveListener>());
218 219 220 221
    bool added = listeners.add(listener);
    assert(added);
  }

222 223 224 225
  /// Stop calling `listener` whenever a widget with the given global key is
  /// removed from the tree.
  ///
  /// Listeners can be added with [addListener].
226 227 228
  static void unregisterRemoveListener(GlobalKey key, GlobalKeyRemoveListener listener) {
    assert(key != null);
    assert(_removeListeners.containsKey(key));
229
    assert(_removeListeners[key].contains(listener));
230 231 232
    bool removed = _removeListeners[key].remove(listener);
    if (_removeListeners[key].isEmpty)
      _removeListeners.remove(key);
233 234 235
    assert(removed);
  }

236 237 238
  static bool _debugCheckForDuplicates() {
    String message = '';
    for (GlobalKey key in _debugDuplicates.keys) {
239 240
      message += 'The following GlobalKey was found multiple times among mounted elements: $key (${_debugDuplicates[key]} instances)\n';
      message += 'The most recently registered instance is: ${_registry[key]}\n';
241
    }
Ian Hickson's avatar
Ian Hickson committed
242
    if (_debugDuplicates.isNotEmpty) {
243
      throw new FlutterError(
244 245 246 247
        'Incorrect GlobalKey usage.\n'
        '$message'
      );
    }
248 249 250 251
    return true;
  }

  static void _notifyListeners() {
252
    if (_removedKeys.isEmpty)
253 254 255
      return;
    try {
      for (GlobalKey key in _removedKeys) {
256
        if (!_registry.containsKey(key) && _removeListeners.containsKey(key)) {
257
          Set<GlobalKeyRemoveListener> localListeners = new HashSet<GlobalKeyRemoveListener>.from(_removeListeners[key]);
258
          for (GlobalKeyRemoveListener listener in localListeners)
259 260
            listener(key);
        }
261
      }
262 263
    } catch (e, stack) {
      _debugReportException('while notifying GlobalKey listeners', e, stack);
264 265
    } finally {
      _removedKeys.clear();
266 267 268
    }
  }

269 270
}

271 272 273 274
/// A global key with a debugging label.
///
/// The debug label is useful for documentation and for debugging. The label
/// does not affect the key's identity.
275
class LabeledGlobalKey<T extends State<StatefulWidget>> extends GlobalKey<T> {
276 277 278
  /// Creates a global key with a debugging label.
  ///
  /// The label does not affect the key's identity.
279
  const LabeledGlobalKey(this._debugLabel) : super.constructor();
280

281
  final String _debugLabel;
282 283

  @override
284
  String toString() => '[GlobalKey ${_debugLabel != null ? _debugLabel : hashCode}]';
285 286
}

287
/// A global key that takes its identity from the object used as its value.
288
///
289 290
/// Used to tie the identity of a widget to the identity of an object used to
/// generate that widget.
291
class GlobalObjectKey extends GlobalKey {
292
  /// Creates a global key that uses [identical] on [value] for its [operator==].
Adam Barth's avatar
Adam Barth committed
293
  const GlobalObjectKey(this.value) : super.constructor();
294 295

  /// The object whose identity is used by this key's [operator==].
296
  final Object value;
297 298

  @override
Hixie's avatar
Hixie committed
299 300 301 302 303 304
  bool operator ==(dynamic other) {
    if (other is! GlobalObjectKey)
      return false;
    final GlobalObjectKey typedOther = other;
    return identical(value, typedOther.value);
  }
305 306

  @override
307
  int get hashCode => identityHashCode(value);
308 309

  @override
310
  String toString() => '[$runtimeType ${value.runtimeType}(${value.hashCode})]';
Eric Seidel's avatar
Eric Seidel committed
311 312
}

Ian Hickson's avatar
Ian Hickson committed
313
/// This class is a work-around for the "is" operator not accepting a variable value as its right operand
pq's avatar
pq committed
314
@optionalTypeArgs
Ian Hickson's avatar
Ian Hickson committed
315
class TypeMatcher<T> {
316
  /// Creates a type matcher for the given type parameter.
Ian Hickson's avatar
Ian Hickson committed
317
  const TypeMatcher();
318 319

  /// Returns `true` if the given object is of type `T`.
Ian Hickson's avatar
Ian Hickson committed
320 321
  bool check(dynamic object) => object is T;
}
322

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
/// Describes the configuration for an [Element].
///
/// Widgets are the central class hierarchy in the Flutter framework. A widget
/// is an immutable description of part of a user interface. Widgets can be
/// inflated into elements, which manage the underlying render tree.
///
/// Widgets themselves have no mutable state. If you wish to associate
/// mutatable state with a widget, consider using a [StatefulWidget], which
/// creates a [State] object (via [StatefulWidget.createState]) whenever it is
/// inflated into an element and incorporated into the tree.
///
/// A given widget can be included in the tree zero or more times. In particular
/// a given widget can be placed in the tree multiple times. Each time a widget
/// is placed in the tree, it is inflated into an [Element], which means a
/// widget that is incorporated into the tree multiple times will be inflated
/// multiple times.
///
/// The [key] property controls how one widget replaces another widget in the
/// tree. If the [runtimeType] and [key] properties of the two widgets are
/// [operator==], respectively, then the new widget replaces the old widget by
/// updating the underlying element (i.e., by calling [Element.update] with the
/// new widget). Otherwise, the old element is removed from the tree, the new
/// widget is inflated into an element, and the new element is inserted into the
/// tree.
///
/// See also:
///
///  * [StatelessWidget]
///  * [StatefulWidget]
///  * [InheritedWidget]
353
abstract class Widget {
354
  /// Initializes [key] for subclasses.
355
  const Widget({ this.key });
356 357 358 359 360 361 362 363 364

  /// Controls how one widget replaces another widget in the tree.
  ///
  /// If the [runtimeType] and [key] properties of the two widgets are
  /// [operator==], respectively, then the new widget replaces the old widget by
  /// updating the underlying element (i.e., by calling [Element.update] with the
  /// new widget). Otherwise, the old element is removed from the tree, the new
  /// widget is inflated into an element, and the new element is inserted into the
  /// tree.
365
  final Key key;
366

367
  /// Inflates this configuration to a concrete instance.
368 369 370 371 372 373
  ///
  /// A given widget can be included in the tree zero or more times. In particular
  /// a given widget can be placed in the tree multiple times. Each time a widget
  /// is placed in the tree, it is inflated into an [Element], which means a
  /// widget that is incorporated into the tree multiple times will be inflated
  /// multiple times.
374
  @protected
375
  Element createElement();
376

377
  /// A short, textual description of this widget.
378 379 380 381
  String toStringShort() {
    return key == null ? '$runtimeType' : '$runtimeType-$key';
  }

382
  @override
Hixie's avatar
Hixie committed
383
  String toString() {
384
    final String name = toStringShort();
385 386 387
    final List<String> data = <String>[];
    debugFillDescription(data);
    if (data.isEmpty)
Hixie's avatar
Hixie committed
388 389
      return '$name';
    return '$name(${data.join("; ")})';
390
  }
391

392 393 394 395 396
  /// Accumulates a list of strings describing the current widget's fields, one
  /// field per string.
  ///
  /// Subclasses should override this to have their information included in
  /// [toString].
397 398
  @protected
  @mustCallSuper
399
  void debugFillDescription(List<String> description) { }
400

401 402 403 404 405 406
  /// Whether the `newWidget` can be used to update an [Element] that currently
  /// has the `oldWidget` as its configuration.
  ///
  /// An element that uses a given widget as its configuration can be updated to
  /// use another widget as its configuration if, and only if, the two widgets
  /// have [runtimeType] and [key] properties that are [operator==].
407 408 409 410
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType &&
      oldWidget.key == newWidget.key;
  }
411
}
412

413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
/// A widget that does not require mutable state.
///
/// A stateless widget is a widget that describes part of the user interface by
/// building a constellation of other widgets that describe the user interface
/// more concretely. The building process continues recursively until the
/// description of the user interface is fully concrete (e.g., consists
/// enitrely of [RenderObjectWidget]s, which describe concrete [RenderObject]s).
///
/// Stateless widget are useful when the part of the user interface you are
/// describing does not depend on anything other than the configuration
/// information in the object itself and the [BuildContext] in which the widget
/// is inflated. For compositions that can change dynamically, e.g. due to
/// having an internal clock-driven state, or depending on some system state,
/// consider using [StatefulWidget].
///
/// See also:
///
///  * [StatefulWidget]
431
abstract class StatelessWidget extends Widget {
432
  /// Initializes [key] for subclasses.
433
  const StatelessWidget({ Key key }) : super(key: key);
434

435 436
  /// Creates a [StatelessElement] to manage this widget's location in the tree.
  ///
Adam Barth's avatar
Adam Barth committed
437
  /// It is uncommon for subclasses to override this method.
438
  @override
439
  StatelessElement createElement() => new StatelessElement(this);
440

441 442
  /// Describes the part of the user interface represented by this widget.
  ///
Adam Barth's avatar
Adam Barth committed
443
  /// The framework calls this method when this widget is inserted into the
444 445
  /// tree in a given [BuildContext] and when the dependencies of this widget
  /// change (e.g., an [InheritedWidget] referenced by this widget changes).
446
  ///
447
  /// The framework replaces the subtree below this widget with the widget
Adam Barth's avatar
Adam Barth committed
448
  /// returned by this method, either by updating the existing subtree or by
449
  /// removing the subtree and inflating a new subtree, depending on whether the
Adam Barth's avatar
Adam Barth committed
450 451
  /// widget returned by this method can update the root of the existing
  /// subtree, as determined by calling [Widget.canUpdate].
452
  ///
Adam Barth's avatar
Adam Barth committed
453
  /// Typically implementations return a newly created constellation of widgets
454 455 456 457 458 459 460 461 462
  /// that are configured with information from this widget's constructor and
  /// from the given [BuildContext].
  ///
  /// The given [BuildContext] contains information about the location in the
  /// tree at which this widget is being built. For example, the context
  /// provides the set of inherited widgets for this location in the tree. A
  /// given widget might be with multiple different [BuildContext] arguments
  /// over time if the widget is moved around the tree or if the widget is
  /// inserted into the tree in multiple places at once.
463
  @protected
464 465
  Widget build(BuildContext context);
}
466

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
/// A widget that has mutable state.
///
/// State is information (1) that can be read synchronously when the widget is
/// built and (2) for which we will be notified when it changes.
///
/// A stateful widget is a widget that describes part of the user interface by
/// building a constellation of other widgets that describe the user interface
/// more concretely. The building process continues recursively until the
/// description of the user interface is fully concrete (e.g., consists
/// enitrely of [RenderObjectWidget]s, which describe concrete [RenderObject]s).
///
/// Stateless widget are useful when the part of the user interface you are
/// describing can change dynamically, e.g. due to having an internal
/// clock-driven state, or depending on some system state. For compositions that
/// depend only on the configuration information in the object itself and the
/// [BuildContext] in which the widget is inflated, consider using
/// [StatelessWidget].
///
/// [StatefulWidget] instances themselves are immutable and store their mutable
/// state in separate [State] objects that are created by the [createState]
Adam Barth's avatar
Adam Barth committed
487
/// method. The framework calls [createState] whenever it inflates a
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
/// [StatefulWidget], which means that multiple [State] objects might be
/// associated with the same [StatefulWidget] if that widget has been inserted
/// into the tree in multiple places. Similarly, if a [StatefulWidget] is
/// removed from the tree and later inserted in to the tree again, the framework
/// will call [createState] again to create a fresh [State] object, simplifying
/// the lifecycle of [State] objects.
///
/// A [StatefulWidget] keeps the same [State] object when moving from one
/// location in the tree to another if its creator used a [GlobalKey] for its
/// [key]. Because a widget with a [GlobalKey] can be used in at most one
/// location in the tree, a widget that uses a [GlobalKey] has at most one
/// associated element. The framework takes advantage of this property when
/// moving a widget with a global key from one location in the tree to another
/// by grafting the (unique) subtree associated with that widget from the old
/// location to the new location (instead of recreating the subtree at the new
/// location). The [State] objects associated with [StatefulWidget] are grafted
/// along with the rest of the subtree, which means the [State] object is reused
/// (instead of being recreated) in the new location. However, in order to be
/// eligible for grafting, the widget might be inserted into the new location in
/// the same animation frame in which it was removed from the old location.
///
/// See also:
///
///  * [State]
///  * [StatelessWidget]
513
abstract class StatefulWidget extends Widget {
514
  /// Initializes [key] for subclasses.
515
  const StatefulWidget({ Key key }) : super(key: key);
516

517 518
  /// Creates a [StatefulElement] to manage this widget's location in the tree.
  ///
Adam Barth's avatar
Adam Barth committed
519
  /// It is uncommon for subclasses to override this method.
520
  @override
521
  StatefulElement createElement() => new StatefulElement(this);
522

523 524
  /// Creates the mutable state for this widget at a given location in the tree.
  ///
Adam Barth's avatar
Adam Barth committed
525
  /// Subclasses should override this method to return a newly created
526 527 528 529 530 531
  /// instance of their associated [State] subclass:
  ///
  /// ```dart
  /// @override
  /// _MyState createState() => new _MyState();
  /// ```
532
  ///
Adam Barth's avatar
Adam Barth committed
533
  /// The framework can call this method multiple times over the lifetime of
534 535 536 537 538 539
  /// a [StatefulWidget]. For example, if the widget is inserted into the tree
  /// in multiple locations, the framework will create a separate [State] object
  /// for each location. Similarly, if the widget is removed from the tree and
  /// later inserted into the tree again, the framework will call [createState]
  /// again to create a fresh [State] object, simplifying the lifecycle of
  /// [State] objects.
540
  @protected
541 542
  State createState();
}
543

544
/// Tracks the lifecycle of [State] objects when asserts are enabled.
545
enum _StateLifecycle {
546 547
  /// The [State] object has been created but [State.initState] has not yet been
  /// called.
548
  created,
549

Adam Barth's avatar
Adam Barth committed
550
  /// The [State.initState] method has been called but the [State] object is
551
  /// not yet ready to build.
552
  initialized,
553 554 555

  /// The [State] object is ready to build and [State.dispose] has not yet been
  /// called.
556
  ready,
557

Adam Barth's avatar
Adam Barth committed
558
  /// The [State.dispose] method has been called and the [State] object is
559
  /// no longer able to build.
560 561
  defunct,
}
562

563
/// The signature of [State.setState] functions.
564 565
typedef void StateSetter(VoidCallback fn);

566
/// The logic and internal state for a [StatefulWidget].
Adam Barth's avatar
Adam Barth committed
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
///
/// State is information (1) that can be read synchronously when the widget is
/// built and (2) for which we will be notified when it changes.
///
/// [State] objects are created by the framework by calling the
/// [StatefulWidget.createState] method when inflating a [StatefulWidget] to
/// insert it into the tree. Because a given [StatefulWidget] instance can be
/// inflated multiple times (e.g., the widget is incorporated into the tree in
/// multiple places at once), there might be more than one [State] object
/// associated with a given [StatefulWidget] instance. Similarly, if a
/// [StatefulWidget] is removed from the tree and later inserted in to the tree
/// again, the framework will call [StatefulWidget.createState] again to create
/// a fresh [State] object, simplifying the lifecycle of [State] objects.
///
/// [State] objects have the following lifecycle:
///
///  * The framework creates a [State] object by calling
///    [StatefulWidget.createState].
///  * The newly created [State] object is associated with a [BuildContext].
///    This association is permanent: the [State] object will never change its
///    [BuildContext]. However, the [BuildContext] itself can be moved around
///    the tree along with its subtree. At this point, the [State] object is
///    considered [mounted].
///  * The framework calls [initState]. Subclasses of [State] should override
///    [initState] to perform one-time initialization that depends on the
///    [BuildContext] or the widget, which are available as the [context] and
///    [config] properties, respectively, when the [initState] method is
///    called.
///  * At this point, the [State] object is fully initialized and the framework
///    might call its [build] method any number of times to obtain a
///    description of the user interface for this subtree. [State] objects can
///    spontanteously request to rebuild their subtree by callings their
///    [setState] method, which indicates that some of their internal state
///    has changed in a way that might impact the user interface in this
///    subtree.
///  * During this time, a parent widget might rebuild and request that this
///    location in the tree update to display a new widget with the same
///    [runtimeType] and [key]. When this happens, the framework will update the
///    [config] property to refer to the new widget and then call the
///    [didUpdateConfig] method with the previous widget as an argument.
///    [State] objects should override [didUpdateConfig] to respond to changes
///    in their associated wiget (e.g., to start implicit animations).
///    The framework always calls [build] after calling [didUpdateConfig], which
///    means any calls to [setState] in [didUpdateConfig] are redundant.
///  * If the subtree containing the [State] object is removed from the tree
///    (e.g., because the parent built a widget with a different [runtimeType]
///    or [key]), the framework calls the [deactivate] method. Subclasses
///    should override this method to clean up any links between this object
///    and other elements in the tree (e.g. if you have provided an ancestor
///    with a pointer to a descendant's [RenderObject]).
///  * At this point, the framework might reinsert this subtree into another
///    part of the tree. If that happens, the framework will ensure that it
///    calls [build] to give the [State] object a chance to adapt to its new
///    location in the tree. If the framework does reinsert this subtree, it
///    will do so before the end of the animation frame in which the subtree was
///    removed from the tree. For this reason, [State] objects can defer
///    releasing most resources until the framework calls their [dispose]
///    method.
///  * If the framework does not reinsert this subtree by the end of the current
///    animation frame, the framework will call [dispose], which indiciates that
///    this [State] object will never build again. Subclasses should override
///    this method to release any resources retained by this object (e.g.,
///    stop any active animations).
///  * After the framework calls [dispose], the [State] object is considered
///    unmounted and the [mounted] property is false. It is an error to call
///    [setState] at this point. This stage of the lifecycle is terminal: there
///    is no way to remount a [State] object that has been disposed.
///
/// See also:
///
///  * [StatefulWidget]
///  * [StatelessWidget]
pq's avatar
pq committed
639
@optionalTypeArgs
640
abstract class State<T extends StatefulWidget> {
Adam Barth's avatar
Adam Barth committed
641 642 643 644 645 646 647 648
  /// The current configuration.
  ///
  /// A [State] object's configuration is the corresponding [StatefulWidget]
  /// instance. This property is initialized by the framework before calling
  /// [initState]. If the parent updates this location in the tree to a new
  /// widget with the same [runtimeType] and [key] as the current configuration,
  /// the framework will update this property to refer to the new widget and
  /// then call [didUpdateConfig], passing the old configuration as an argument.
649 650
  T get config => _config;
  T _config;
651

Adam Barth's avatar
Adam Barth committed
652 653 654 655
  /// The current stage in the lifecycle for this state object.
  ///
  /// This field is used by the framework when asserts are enabled to verify
  /// that [State] objects move through their lifecycle in an orderly fashion.
656
  _StateLifecycle _debugLifecycleState = _StateLifecycle.created;
657

Adam Barth's avatar
Adam Barth committed
658 659
  /// Verifies that the [State] that was created is one that expects to be
  /// created for that particular [Widget].
660
  bool _debugTypesAreRight(Widget widget) => widget is T;
661

Adam Barth's avatar
Adam Barth committed
662 663 664 665 666 667 668 669 670
  /// The [StatefulElement] that owns this [State] object.
  ///
  /// The framework associates [State] objects with an element after creating
  /// them with [StatefulWidget.createState] and before calling [initState]. The
  /// association is permanent: the [State] object will never change its
  /// element. However, the element itself can be moved around the tree.
  ///
  /// After calling [dispose], the framework severs the [State] object's
  /// connection with the element.
671
  StatefulElement _element;
672

Adam Barth's avatar
Adam Barth committed
673 674 675 676 677 678 679 680 681 682
  /// The location in the tree where this widget builds.
  ///
  /// The framework associates [State] objects with a [BuildContext] after
  /// creating them with [StatefulWidget.createState] and before calling
  /// [initState]. The association is permanent: the [State] object will never
  /// change its [BuildContext]. However, the [BuildContext] itself can be moved
  /// around the tree.
  ///
  /// After calling [dispose], the framework severs the [State] object's
  /// connection with the [BuildContext].
683
  BuildContext get context => _element;
684

Adam Barth's avatar
Adam Barth committed
685 686 687 688 689 690 691 692 693
  /// Whether this [State] object is currently in a tree.
  ///
  /// After creating a [State] object and before calling [initState], the
  /// framework "mounts" the [State] object by associating it with a
  /// [BuildContext]. The [State] object remains mounted until the framework
  /// calls [dispose], after which time the framework will never ask the [State]
  /// object to [build] again.
  ///
  /// It is an error to call [setState] unless [mounted] is true.
694
  bool get mounted => _element != null;
695

Adam Barth's avatar
Adam Barth committed
696 697 698 699 700 701 702 703
  /// Called when this object is inserted into the tree.
  ///
  /// Override this method to perform initialization that depends on the
  /// location at which this object was inserted into the tree (i.e., [context])
  /// or on the widget used to configure this object (i.e., [config])
  ///
  /// The framework will call this method exactly once for each [State] object
  /// it creates.
704 705 706
  ///
  /// If you override this, make sure your method starts with a call to
  /// super.initState().
707
  @protected
708
  @mustCallSuper
709 710 711
  void initState() {
    assert(_debugLifecycleState == _StateLifecycle.created);
    assert(() { _debugLifecycleState = _StateLifecycle.initialized; return true; });
712
  }
713

Adam Barth's avatar
Adam Barth committed
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
  /// Called whenever the configuration changes.
  ///
  /// If the parent widget rebuilds and request that this location in the tree
  /// update to display a new widget with the same [runtimeType] and [key], the
  /// framework will update the [config] property of this [State] object to
  /// refer to the new widget and then call the this method with the previous
  /// widget as an argument.
  ///
  /// Override this metthod to respond to changes in the [config] widget (e.g.,
  /// to start implicit animations).
  ///
  /// The framework always calls [build] after calling [didUpdateConfig], which
  /// means any calls to [setState] in [didUpdateConfig] are redundant.
  ///
  /// If you override this, make sure your method starts with a call to
  /// super.didUpdateConfig(oldConfig).
  // TODO(abarth): Add @mustCallSuper.
731
  @protected
732
  void didUpdateConfig(T oldConfig) { }
733

Adam Barth's avatar
Adam Barth committed
734 735 736 737
  /// Notify the framework that the internal state of this object has changed.
  ///
  /// Whenever you change the internal state of a [State] object, make the
  /// change in a function that you pass to [setState]:
738
  ///
739
  /// ```dart
Adam Barth's avatar
Adam Barth committed
740
  /// setState(() { _myState = newValue });
741
  /// ```
742
  ///
Adam Barth's avatar
Adam Barth committed
743 744 745 746 747 748 749 750 751 752 753 754
  /// Calling [setState] notifies the framework that the internal state of this
  /// object has changed in a way that might impact the user interface in this
  /// subtree, which causes the framework to schedule a [build] for this [State]
  /// object.
  ///
  /// If you just change the state directly without calling [setState], the
  /// framework might not schedule a [build] and the user interface for this
  /// subtree might not be updated to reflect the new state.
  ///
  /// It is an error to call this method after the framework calls [dispose].
  /// You can determine whether it is legal to call this method by checking
  /// whether the [mounted] property is true.
755
  @protected
756
  void setState(VoidCallback fn) {
757 758
    assert(() {
      if (_debugLifecycleState == _StateLifecycle.defunct) {
759
        throw new FlutterError(
760
          'setState() called after dispose(): $this\n'
761 762 763 764 765 766 767 768 769 770 771 772 773
          'This error happens if you call setState() on State object for a widget that '
          'no longer appears in the widget tree (e.g., whose parent widget no longer '
          'includes the widget in its build). This error can occur when code calls '
          'setState() from a timer or an animation callback. The preferred solution is '
          'to cancel the timer or stop listening to the animation in the dispose() '
          'callback. Another solution is to check the "mounted" property of this '
          'object before calling setState() to ensure the object is still in the '
          'tree.\n'
          '\n'
          'This error might indicate a memory leak if setState() is being called '
          'because another object is retaining a reference to this State object '
          'after it has been removed from the tree. To avoid memory leaks, '
          'consider breaking the reference to this object during dipose().'
774 775 776 777
        );
      }
      return true;
    });
778 779 780 781 782
    dynamic result = fn() as dynamic;
    assert(() {
      if (result is Future) {
        throw new FlutterError(
          'setState() callback argument returned a Future.\n'
783
          'The setState() method on $this was called with a closure or method that '
784 785 786 787 788 789 790 791 792 793
          'returned a Future. Maybe it is marked as "async".\n'
          'Instead of performing asynchronous work inside a call to setState(), first '
          'execute the work (without updating the widget state), and then synchronously '
          'update the state inside a call to setState().'
        );
      }
      // We ignore other types of return values so that you can do things like:
      //   setState(() => x = 3);
      return true;
    });
794
    _element.markNeedsBuild();
795
  }
796

797 798
  /// Called when this object is removed from the tree.
  ///
Adam Barth's avatar
Adam Barth committed
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
  /// The framework calls this method whenever it removes this [State] object
  /// from the tree. In some cases, the framework will reinsert the [State]
  /// object into another part of the tree (e.g., if the subtree containing this
  /// [State] object is grafted from one location in the tree to another). If
  /// that happens, the framework will ensure that it calls [build] to give the
  /// [State] object a chance to adapt to its new location in the tree. If
  /// the framework does reinsert this subtree, it will do so before the end of
  /// the animation frame in which the subtree was removed from the tree. For
  /// this reason, [State] objects can defer releasing most resources until the
  /// framework calls their [dispose] method.
  ///
  /// Subclasses should override this method to clean up any links between
  /// this object and other elements in the tree (e.g. if you have provided an
  /// ancestor with a pointer to a descendant's [RenderObject]).
  ///
  /// If you override this, make sure to end your method with a call to
  /// super.deactivate().
816
  @protected
817
  @mustCallSuper
818 819 820
  void deactivate() { }

  /// Called when this object is removed from the tree permanently.
Adam Barth's avatar
Adam Barth committed
821 822 823 824 825 826 827 828 829
  ///
  /// The framework calls this method when this [State] object will never
  /// build again. After the framework calls [dispose], the [State] object is
  /// considered unmounted and the [mounted] property is false. It is an error
  /// to call [setState] at this point. This stage of the lifecycle is terminal:
  /// there is no way to remount a [State] object that has been disposed.
  ///
  /// Subclasses should override this method to release any resources retained
  /// by this object (e.g., stop any active animations).
830 831 832
  ///
  /// If you override this, make sure to end your method with a call to
  /// super.dispose().
833
  @protected
834
  @mustCallSuper
835 836 837
  void dispose() {
    assert(_debugLifecycleState == _StateLifecycle.ready);
    assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; });
838 839
  }

Adam Barth's avatar
Adam Barth committed
840
  /// Describes the part of the user interface represented by this widget.
841
  ///
Adam Barth's avatar
Adam Barth committed
842
  /// The framework calls this method in a number of different situations:
843
  ///
Adam Barth's avatar
Adam Barth committed
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
  ///  * After calling [initState].
  ///  * After calling [didUpdateConfig].
  ///  * After receiving a call to [setState].
  ///  * After a dependency of this [State] object changes (e.g., an
  ///    [InheritedWidget] referenced by the previous [build] changes).
  ///  * After calling [deactivate] and then reinserting the [State] object into
  ///    the tree at another location.
  ///
  /// The framework replaces the subtree below this widget with the widget
  /// returned by this method, either by updating the existing subtree or by
  /// removing the subtree and inflating a new subtree, depending on whether the
  /// widget returned by this method can update the root of the existing
  /// subtree, as determined by calling [Widget.canUpdate].
  ///
  /// Typically implementations return a newly created constellation of widgets
  /// that are configured with information from this widget's constructor, the
  /// given [BuildContext], and the internal state of this [State] object.
  ///
  /// The given [BuildContext] contains information about the location in the
  /// tree at which this widget is being built. For example, the context
  /// provides the set of inherited widgets for this location in the tree. The
  /// [BuildContext] argument is always the same as the [context] property of
  /// this [State] object and will remain the same for the lifetime of this
  /// object. The [BuildContext] argument is provided redundantly here so that
  /// this method matches the signature for a [WidgetBuilder].
869
  @protected
870
  Widget build(BuildContext context);
871

Adam Barth's avatar
Adam Barth committed
872 873 874 875 876 877 878 879 880 881 882
  /// Called when a dependencies of this [State] object changes.
  ///
  /// For example, if the previous call to [build] referenced an
  /// [InheritedWidget] that later changed, the framework would call this
  /// method to notify this object about the change.
  ///
  /// Subclasses rarely override this method because the framework always
  /// calls [build] after a dependency changes. Some subclasses do override
  /// this method because they need to do some expensive work (e.g., network
  /// fetches) when their dependencies change, and that work would be too
  /// expensive to do for every build.
883
  @protected
884
  @mustCallSuper
885
  void dependenciesChanged() { }
886

887
  @override
888 889 890 891
  String toString() {
    final List<String> data = <String>[];
    debugFillDescription(data);
    return '$runtimeType(${data.join("; ")})';
892 893
  }

Adam Barth's avatar
Adam Barth committed
894 895 896 897 898 899 900 901 902
  /// Add additional information to the given description for use by [toString].
  ///
  /// This method makes it easier for subclasses to coordinate to provide a
  /// high-quality [toString] implementation. The [toString] implementation on
  /// the [State] base class calls [debugFillDescription] to collect useful
  /// information from subclasses to incorporate into its return value.
  ///
  /// If you override this, make sure to start your method with a call to
  /// super.debugFillDescription(description).
903 904
  @protected
  @mustCallSuper
905 906
  void debugFillDescription(List<String> description) {
    description.add('$hashCode');
Hixie's avatar
Hixie committed
907 908 909 910 911
    assert(() {
      if (_debugLifecycleState != _StateLifecycle.ready)
        description.add('$_debugLifecycleState');
      return true;
    });
912 913 914 915
    if (_config == null)
      description.add('no config');
    if (_element == null)
      description.add('not mounted');
916
  }
917
}
918

919 920
abstract class _ProxyWidget extends Widget {
  const _ProxyWidget({ Key key, this.child }) : super(key: key);
921

922
  final Widget child;
923 924
}

925
abstract class ParentDataWidget<T extends RenderObjectWidget> extends _ProxyWidget {
Hixie's avatar
Hixie committed
926
  const ParentDataWidget({ Key key, Widget child })
927 928
    : super(key: key, child: child);

929
  @override
930
  ParentDataElement<T> createElement() => new ParentDataElement<T>(this);
931

932
  /// Subclasses should override this method to return true if the given
933 934
  /// ancestor is a RenderObjectWidget that wraps a RenderObject that can handle
  /// the kind of ParentData widget that the ParentDataWidget subclass handles.
935
  ///
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
  /// The default implementation uses the type argument.
  bool debugIsValidAncestor(RenderObjectWidget ancestor) {
    assert(T != dynamic);
    assert(T != RenderObjectWidget);
    return ancestor is T;
  }

  /// Subclasses should override this to describe the requirements for using the
  /// ParentDataWidget subclass. It is called when debugIsValidAncestor()
  /// returned false for an ancestor, or when there are extraneous
  /// ParentDataWidgets in the ancestor chain.
  String debugDescribeInvalidAncestorChain({ String description, String ownershipChain, bool foundValidAncestor, Iterable<Widget> badAncestors }) {
    assert(T != dynamic);
    assert(T != RenderObjectWidget);
    String result;
    if (!foundValidAncestor) {
      result = '$runtimeType widgets must be placed inside $T widgets.\n'
               '$description has no $T ancestor at all.\n';
    } else {
      assert(badAncestors.isNotEmpty);
      result = '$runtimeType widgets must be placed directly inside $T widgets.\n'
               '$description has a $T ancestor, but there are other widgets between them:\n';
      for (Widget ancestor in badAncestors) {
        if (ancestor.runtimeType == runtimeType) {
          result += '  $ancestor (this is a different $runtimeType than the one with the problem)\n';
        } else {
          result += '  $ancestor\n';
        }
      }
      result += 'These widgets cannot come between a $runtimeType and its $T.\n';
    }
    result += 'The ownership chain for the parent of the offending $runtimeType was:\n  $ownershipChain';
    return result;
  }
970

971
  @protected
972 973
  void applyParentData(RenderObject renderObject);
}
974

975
abstract class InheritedWidget extends _ProxyWidget {
976 977
  const InheritedWidget({ Key key, Widget child })
    : super(key: key, child: child);
978

979
  @override
980
  InheritedElement createElement() => new InheritedElement(this);
Eric Seidel's avatar
Eric Seidel committed
981

982
  @protected
983 984
  bool updateShouldNotify(InheritedWidget oldWidget);
}
985

986 987 988 989 990 991
/// RenderObjectWidgets provide the configuration for [RenderObjectElement]s,
/// which wrap [RenderObject]s, which provide the actual rendering of the
/// application.
abstract class RenderObjectWidget extends Widget {
  const RenderObjectWidget({ Key key }) : super(key: key);

992
  /// RenderObjectWidgets always inflate to a [RenderObjectElement] subclass.
993
  @override
994 995
  RenderObjectElement createElement();

996 997 998
  /// Creates an instance of the [RenderObject] class that this
  /// [RenderObjectWidget] represents, using the configuration described by this
  /// [RenderObjectWidget].
999
  @protected
1000
  RenderObject createRenderObject(BuildContext context);
1001

1002 1003 1004
  /// Copies the configuration described by this [RenderObjectWidget] to the
  /// given [RenderObject], which will be of the same type as returned by this
  /// object's [createRenderObject].
1005
  @protected
1006
  void updateRenderObject(BuildContext context, RenderObject renderObject) { }
1007

1008
  @protected
1009 1010 1011 1012 1013 1014 1015 1016
  void didUnmountRenderObject(RenderObject renderObject) { }
}

/// A superclass for RenderObjectWidgets that configure RenderObject subclasses
/// that have no children.
abstract class LeafRenderObjectWidget extends RenderObjectWidget {
  const LeafRenderObjectWidget({ Key key }) : super(key: key);

1017
  @override
1018 1019 1020 1021 1022 1023
  LeafRenderObjectElement createElement() => new LeafRenderObjectElement(this);
}

/// A superclass for RenderObjectWidgets that configure RenderObject subclasses
/// that have a single child slot. (This superclass only provides the storage
/// for that child, it doesn't actually provide the updating logic.)
1024 1025
abstract class SingleChildRenderObjectWidget extends RenderObjectWidget {
  const SingleChildRenderObjectWidget({ Key key, this.child }) : super(key: key);
1026

1027
  /// The widget below this widget in the tree.
1028 1029
  final Widget child;

1030
  @override
1031
  SingleChildRenderObjectElement createElement() => new SingleChildRenderObjectElement(this);
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
}

/// A superclass for RenderObjectWidgets that configure RenderObject subclasses
/// that have a single list of children. (This superclass only provides the
/// storage for that child list, it doesn't actually provide the updating
/// logic.)
abstract class MultiChildRenderObjectWidget extends RenderObjectWidget {
  MultiChildRenderObjectWidget({ Key key, this.children })
    : super(key: key) {
    assert(children != null);
    assert(!children.any((Widget child) => child == null));
  }

  final List<Widget> children;

1047
  @override
1048 1049 1050
  MultiChildRenderObjectElement createElement() => new MultiChildRenderObjectElement(this);
}

Hixie's avatar
Hixie committed
1051 1052 1053

// ELEMENTS

1054 1055
enum _ElementLifecycle {
  initial,
1056 1057
  active,
  inactive,
1058
  defunct,
1059 1060
}

1061
class _InactiveElements {
1062
  bool _locked = false;
1063
  final Set<Element> _elements = new HashSet<Element>();
1064

1065
  void _unmount(Element element) {
1066 1067 1068 1069 1070
    assert(element._debugLifecycleState == _ElementLifecycle.inactive);
    element.unmount();
    assert(element._debugLifecycleState == _ElementLifecycle.defunct);
    element.visitChildren((Element child) {
      assert(child._parent == element);
1071
      _unmount(child);
1072 1073 1074
    });
  }

1075 1076 1077 1078 1079 1080 1081 1082 1083
  void _unmountAll() {
    try {
      _locked = true;
      for (Element element in _elements)
        _unmount(element);
    } finally {
      _elements.clear();
      _locked = false;
    }
1084 1085
  }

1086
  void _deactivateRecursively(Element element) {
1087 1088 1089
    assert(element._debugLifecycleState == _ElementLifecycle.active);
    element.deactivate();
    assert(element._debugLifecycleState == _ElementLifecycle.inactive);
1090
    element.visitChildren(_deactivateRecursively);
1091
    assert(() { element.debugDeactivated(); return true; });
1092 1093
  }

1094 1095 1096 1097
  void add(Element element) {
    assert(!_locked);
    assert(!_elements.contains(element));
    assert(element._parent == null);
1098
    if (element._active)
1099
      _deactivateRecursively(element);
1100 1101
    _elements.add(element);
  }
1102 1103 1104 1105 1106 1107 1108 1109

  void remove(Element element) {
    assert(!_locked);
    assert(_elements.contains(element));
    assert(element._parent == null);
    _elements.remove(element);
    assert(!element._active);
  }
1110 1111
}

1112 1113 1114 1115 1116 1117
/// Signature for the callback to [BuildContext.visitChildElements].
///
/// The argument is the child being visited.
///
/// It is safe to call `element.visitChildElements` reentrantly within
/// this callback.
1118
typedef void ElementVisitor(Element element);
1119

1120
abstract class BuildContext {
1121
  Widget get widget;
1122
  RenderObject findRenderObject();
Ian Hickson's avatar
Ian Hickson committed
1123 1124 1125 1126
  InheritedWidget inheritFromWidgetOfExactType(Type targetType);
  Widget ancestorWidgetOfExactType(Type targetType);
  State ancestorStateOfType(TypeMatcher matcher);
  RenderObject ancestorRenderObjectOfType(TypeMatcher matcher);
1127
  void visitAncestorElements(bool visitor(Element element));
1128
  void visitChildElements(ElementVisitor visitor);
1129
}
1130

1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
class BuildOwner {
  BuildOwner({ this.onBuildScheduled });

  /// Called on each build pass when the first buildable element is marked dirty
  VoidCallback onBuildScheduled;

  final _InactiveElements _inactiveElements = new _InactiveElements();

  final List<BuildableElement> _dirtyElements = <BuildableElement>[];

  /// Adds an element to the dirty elements list so that it will be rebuilt
  /// when buildDirtyElements is called.
  void scheduleBuildFor(BuildableElement element) {
1144 1145 1146 1147
    assert(() {
      if (_dirtyElements.contains(element)) {
        throw new FlutterError(
          'scheduleBuildFor() called for a widget for which a build was already scheduled.\n'
1148
          'The method was called for the following element:\n'
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
          '  $element\n'
          'The current dirty list consists of:\n'
          '  $_dirtyElements\n'
          'This should not be possible and probably indicates a bug in the widgets framework. '
          'Please report it: https://github.com/flutter/flutter/issues/new'
        );
      }
      if (!element.dirty) {
        throw new FlutterError(
          'scheduleBuildFor() called for a widget that is not marked as dirty.\n'
1159
          'The method was called for the following element:\n'
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
          '  $element\n'
          'This element is not current marked as dirty. Make sure to set the dirty flag before '
          'calling scheduleBuildFor().\n'
          'If you did not attempt to call scheduleBuildFor() yourself, then this probably '
          'indicates a bug in the widgets framework. Please report it: '
          'https://github.com/flutter/flutter/issues/new'
        );
      }
      return true;
    });
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
    if (_dirtyElements.isEmpty && onBuildScheduled != null)
      onBuildScheduled();
    _dirtyElements.add(element);
  }

  int _debugStateLockLevel = 0;
  bool get _debugStateLocked => _debugStateLockLevel > 0;
  bool _debugBuilding = false;
  BuildableElement _debugCurrentBuildTarget;

1180
  /// Establishes a scope in which calls to [State.setState] are forbidden.
1181
  ///
1182 1183
  /// This mechanism prevents build functions from transitively requiring other
  /// build functions to run, potentially causing infinite loops.
1184
  ///
1185 1186
  /// If the building argument is true, then this function enables additional
  /// asserts that check invariants that should apply during building.
1187 1188 1189
  ///
  /// The context argument is used to describe the scope in case an exception is
  /// caught while invoking the callback.
1190
  void lockState(void callback(), { bool building: false }) {
1191
    bool debugPreviouslyBuilding;
1192 1193 1194
    assert(_debugStateLockLevel >= 0);
    assert(() {
      if (building) {
1195
        debugPreviouslyBuilding = _debugBuilding;
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
        _debugBuilding = true;
      }
      _debugStateLockLevel += 1;
      return true;
    });
    try {
      callback();
    } finally {
      assert(() {
        _debugStateLockLevel -= 1;
        if (building) {
          assert(_debugBuilding);
1208
          _debugBuilding = debugPreviouslyBuilding;
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
        }
        return true;
      });
    }
    assert(_debugStateLockLevel >= 0);
  }

  static int _elementSort(BuildableElement a, BuildableElement b) {
    if (a.depth < b.depth)
      return -1;
    if (b.depth < a.depth)
      return 1;
    if (b.dirty && !a.dirty)
      return -1;
    if (a.dirty && !b.dirty)
      return 1;
    return 0;
  }

  /// Builds all the elements that were marked as dirty using schedule(), in depth order.
  /// If elements are marked as dirty while this runs, they must be deeper than the algorithm
  /// has yet reached.
  /// This is called by beginFrame().
  void buildDirtyElements() {
    if (_dirtyElements.isEmpty)
      return;
    Timeline.startSync('Build');
1236 1237 1238 1239 1240 1241
    try {
      lockState(() {
        _dirtyElements.sort(_elementSort);
        int dirtyCount = _dirtyElements.length;
        int index = 0;
        while (index < dirtyCount) {
1242 1243 1244 1245 1246
          assert(() {
            if (debugPrintRebuildDirtyWidgets)
              debugPrint('Rebuilding ${_dirtyElements[index].widget}');
            return true;
          });
1247 1248 1249 1250 1251 1252
          _dirtyElements[index].rebuild();
          index += 1;
          if (dirtyCount < _dirtyElements.length) {
            _dirtyElements.sort(_elementSort);
            dirtyCount = _dirtyElements.length;
          }
1253
        }
1254 1255 1256
        assert(!_dirtyElements.any((BuildableElement element) => element.dirty));
      }, building: true);
    } finally {
1257
      _dirtyElements.clear();
1258 1259
      Timeline.finishSync();
    }
1260 1261 1262 1263
  }

  /// Complete the element build pass by unmounting any elements that are no
  /// longer active.
1264
  ///
1265
  /// This is called by beginFrame().
1266 1267 1268 1269 1270 1271
  ///
  /// In checked mode, this also verifies that each global key is used at most
  /// once.
  ///
  /// After the current call stack unwinds, a microtask that notifies listeners
  /// about changes to global keys will run.
1272
  void finalizeTree() {
1273
    Timeline.startSync('Finalize tree');
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
    try {
      lockState(() {
        _inactiveElements._unmountAll();
      });
      assert(GlobalKey._debugCheckForDuplicates);
      scheduleMicrotask(GlobalKey._notifyListeners);
    } catch (e, stack) {
      _debugReportException('while finalizing the widget tree', e, stack);
    } finally {
      Timeline.finishSync();
    }
1285
  }
1286

1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
  /// Cause the entire subtree rooted at the given [Element] to
  /// be entirely rebuilt. This is used by development tools when
  /// the application code has changed, to cause the widget tree to
  /// pick up any changed implementations.
  ///
  /// This is expensive and should not be called except during
  /// development.
  void reassemble(Element root) {
    assert(root._parent == null);
    assert(root.owner == this);
    root._reassemble();
  }
1299 1300
}

1301 1302 1303 1304
/// Elements are the instantiations of Widget configurations.
///
/// Elements can, in principle, have children. Only subclasses of
/// RenderObjectElement are allowed to have more than one child.
1305 1306
abstract class Element implements BuildContext {
  Element(Widget widget) : _widget = widget {
1307 1308
    assert(widget != null);
  }
1309

1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
  Element _parent;

  /// Information set by parent to define where this child fits in its parent's
  /// child list.
  ///
  /// Subclasses of Element that only have one child should use null for
  /// the slot for that child.
  dynamic get slot => _slot;
  dynamic _slot;

  /// An integer that is guaranteed to be greater than the parent's, if any.
  /// The element at the root of the tree must have a depth greater than 0.
  int get depth => _depth;
  int _depth;

  /// The configuration for this element.
1326
  @override
1327 1328
  Widget get widget => _widget;
  Widget _widget;
1329

1330 1331
  /// The owner for this node (null if unattached).
  BuildOwner get owner => _owner;
1332
  BuildOwner _owner;
1333

1334 1335
  bool _active = false;

1336 1337 1338 1339 1340 1341 1342
  void _reassemble() {
    assert(_active);
    visitChildren((Element child) {
      child._reassemble();
    });
  }

1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
  RenderObject get renderObject {
    RenderObject result;
    void visit(Element element) {
      assert(result == null); // this verifies that there's only one child
      if (element is RenderObjectElement)
        result = element.renderObject;
      else
        element.visitChildren(visit);
    }
    visit(this);
    return result;
1354 1355
  }

1356 1357
  /// This is used to verify that Element objects move through life in an orderly fashion.
  _ElementLifecycle _debugLifecycleState = _ElementLifecycle.initial;
1358

1359 1360
  /// Calls the argument for each child. Must be overridden by subclasses that support having children.
  void visitChildren(ElementVisitor visitor) { }
1361

1362
  /// Wrapper around visitChildren for BuildContext.
1363
  @override
1364 1365
  void visitChildElements(void visitor(Element element)) {
    // don't allow visitChildElements() during build, since children aren't necessarily built yet
1366
    assert(owner == null || !owner._debugStateLocked);
1367 1368 1369
    visitChildren(visitor);
  }

1370 1371
  bool detachChild(Element child) => false;

1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
  /// This method is the core of the system.
  ///
  /// It is called each time we are to add, update, or remove a child based on
  /// an updated configuration.
  ///
  /// If the child is null, and the newWidget is not null, then we have a new
  /// child for which we need to create an Element, configured with newWidget.
  ///
  /// If the newWidget is null, and the child is not null, then we need to
  /// remove it because it no longer has a configuration.
  ///
  /// If neither are null, then we need to update the child's configuration to
  /// be the new configuration given by newWidget. If newWidget can be given to
  /// the existing child, then it is so given. Otherwise, the old child needs
  /// to be disposed and a new child created for the new configuration.
  ///
  /// If both are null, then we don't have a child and won't have a child, so
  /// we do nothing.
  ///
  /// The updateChild() method returns the new child, if it had to create one,
  /// or the child that was passed in, if it just had to update the child, or
  /// null, if it removed the child and did not replace it.
1394
  @protected
1395 1396 1397
  Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
    if (newWidget == null) {
      if (child != null)
Hixie's avatar
Hixie committed
1398
        deactivateChild(child);
1399 1400 1401 1402 1403 1404 1405 1406
      return null;
    }
    if (child != null) {
      if (child.widget == newWidget) {
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        return child;
      }
1407
      if (Widget.canUpdate(child.widget, newWidget)) {
1408 1409 1410 1411 1412 1413
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        child.update(newWidget);
        assert(child.widget == newWidget);
        return child;
      }
Hixie's avatar
Hixie committed
1414
      deactivateChild(child);
1415 1416
      assert(child._parent == null);
    }
Hixie's avatar
Hixie committed
1417
    return inflateWidget(newWidget, newSlot);
1418 1419 1420 1421 1422 1423
  }

  /// Called when an Element is given a new parent shortly after having been
  /// created. Use this to initialize state that depends on having a parent. For
  /// state that is independent of the position in the tree, it's better to just
  /// initialize the Element in the constructor.
1424
  @mustCallSuper
1425 1426 1427 1428
  void mount(Element parent, dynamic newSlot) {
    assert(_debugLifecycleState == _ElementLifecycle.initial);
    assert(widget != null);
    assert(_parent == null);
1429
    assert(parent == null || parent._debugLifecycleState == _ElementLifecycle.active);
1430 1431
    assert(slot == null);
    assert(depth == null);
1432
    assert(!_active);
1433 1434 1435
    _parent = parent;
    _slot = newSlot;
    _depth = _parent != null ? _parent.depth + 1 : 1;
1436
    _active = true;
1437 1438
    if (parent != null) // Only assign ownership if the parent is non-null
      _owner = parent.owner;
1439 1440 1441 1442
    if (widget.key is GlobalKey) {
      final GlobalKey key = widget.key;
      key._register(this);
    }
1443
    _updateInheritance();
1444
    assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; });
1445 1446
  }

1447
  /// Called when an Element receives a new configuration widget.
1448
  @mustCallSuper
1449
  void update(Widget newWidget) {
1450
    assert(_debugLifecycleState == _ElementLifecycle.active);
1451 1452
    assert(widget != null);
    assert(newWidget != null);
Hixie's avatar
Hixie committed
1453
    assert(newWidget != widget);
1454
    assert(depth != null);
1455
    assert(_active);
1456
    assert(Widget.canUpdate(widget, newWidget));
1457
    _widget = newWidget;
1458 1459
  }

1460 1461 1462
  /// Called by MultiChildRenderObjectElement, and other RenderObjectElement
  /// subclasses that have multiple children, to update the slot of a particular
  /// child when the child is moved in its child list.
1463
  @protected
1464
  void updateSlotForChild(Element child, dynamic newSlot) {
1465
    assert(_debugLifecycleState == _ElementLifecycle.active);
1466 1467 1468 1469 1470 1471 1472 1473
    assert(child != null);
    assert(child._parent == this);
    void visit(Element element) {
      element._updateSlot(newSlot);
      if (element is! RenderObjectElement)
        element.visitChildren(visit);
    }
    visit(child);
1474 1475
  }

1476
  void _updateSlot(dynamic newSlot) {
1477
    assert(_debugLifecycleState == _ElementLifecycle.active);
1478 1479
    assert(widget != null);
    assert(_parent != null);
1480
    assert(_parent._debugLifecycleState == _ElementLifecycle.active);
1481
    assert(depth != null);
1482
    _slot = newSlot;
1483
  }
1484

1485 1486
  void _updateDepth(int parentDepth) {
    int expectedDepth = parentDepth + 1;
1487 1488 1489
    if (_depth < expectedDepth) {
      _depth = expectedDepth;
      visitChildren((Element child) {
1490
        child._updateDepth(expectedDepth);
1491 1492 1493 1494
      });
    }
  }

1495 1496 1497 1498 1499 1500 1501
  void detachRenderObject() {
    visitChildren((Element child) {
      child.detachRenderObject();
    });
    _slot = null;
  }

1502 1503 1504 1505 1506 1507 1508 1509
  void attachRenderObject(dynamic newSlot) {
    assert(_slot == null);
    visitChildren((Element child) {
      child.attachRenderObject(newSlot);
    });
    _slot = newSlot;
  }

1510
  Element _retakeInactiveElement(GlobalKey key, Widget newWidget) {
1511 1512 1513
    Element element = key._currentElement;
    if (element == null)
      return null;
1514
    if (!Widget.canUpdate(element.widget, newWidget))
1515 1516 1517 1518
      return null;
    if (element._parent != null && !element._parent.detachChild(element))
      return null;
    assert(element._parent == null);
1519
    owner._inactiveElements.remove(element);
1520 1521 1522
    return element;
  }

1523
  @protected
Hixie's avatar
Hixie committed
1524
  Element inflateWidget(Widget newWidget, dynamic newSlot) {
1525
    assert(newWidget != null);
1526 1527
    Key key = newWidget.key;
    if (key is GlobalKey) {
1528
      Element newChild = _retakeInactiveElement(key, newWidget);
1529 1530
      if (newChild != null) {
        assert(newChild._parent == null);
1531
        assert(() { _debugCheckForCycles(newChild); return true; });
1532
        newChild._activateWithParent(this, newSlot);
1533 1534 1535 1536 1537 1538
        Element updatedChild = updateChild(newChild, newWidget, newSlot);
        assert(newChild == updatedChild);
        return updatedChild;
      }
    }
    Element newChild = newWidget.createElement();
1539
    assert(() { _debugCheckForCycles(newChild); return true; });
1540 1541 1542 1543 1544
    newChild.mount(this, newSlot);
    assert(newChild._debugLifecycleState == _ElementLifecycle.active);
    return newChild;
  }

1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
  void _debugCheckForCycles(Element newChild) {
    assert(newChild._parent == null);
    assert(() {
      Element node = this;
      while (node._parent != null)
        node = node._parent;
      assert(node != newChild); // indicates we are about to create a cycle
      return true;
    });
  }

1556
  @protected
Hixie's avatar
Hixie committed
1557
  void deactivateChild(Element child) {
1558 1559 1560
    assert(child != null);
    assert(child._parent == this);
    child._parent = null;
1561
    child.detachRenderObject();
1562
    owner._inactiveElements.add(child); // this eventually calls child.deactivate()
1563
  }
1564

1565
  void _activateWithParent(Element parent, dynamic newSlot) {
1566 1567
    assert(_debugLifecycleState == _ElementLifecycle.inactive);
    _parent = parent;
1568 1569
    _updateDepth(_parent.depth);
    _activateRecursively(this);
1570 1571 1572 1573
    attachRenderObject(newSlot);
    assert(_debugLifecycleState == _ElementLifecycle.active);
  }

1574 1575 1576 1577 1578 1579 1580
  static void _activateRecursively(Element element) {
    assert(element._debugLifecycleState == _ElementLifecycle.inactive);
    element.activate();
    assert(element._debugLifecycleState == _ElementLifecycle.active);
    element.visitChildren(_activateRecursively);
  }

1581 1582
  /// Called when a previously de-activated widget (see [deactivate]) is reused
  /// instead of being unmounted (see [unmount]).
1583
  @mustCallSuper
1584
  void activate() {
1585 1586 1587 1588 1589
    assert(_debugLifecycleState == _ElementLifecycle.inactive);
    assert(widget != null);
    assert(depth != null);
    assert(!_active);
    _active = true;
1590 1591 1592
    // We unregistered our dependencies in deactivate, but never cleared the list.
    // Since we're going to be reused, let's clear our list now.
    _dependencies?.clear();
1593
    _updateInheritance();
1594 1595 1596
    assert(() { _debugLifecycleState = _ElementLifecycle.active; return true; });
  }

1597 1598
  // TODO(ianh): Define activation/deactivation thoroughly (other methods point
  // here for details).
1599
  @mustCallSuper
1600 1601 1602 1603
  void deactivate() {
    assert(_debugLifecycleState == _ElementLifecycle.active);
    assert(widget != null);
    assert(depth != null);
1604
    assert(_active);
1605
    if (_dependencies != null && _dependencies.length > 0) {
1606
      for (InheritedElement dependency in _dependencies)
1607
        dependency._dependents.remove(this);
1608 1609 1610 1611 1612 1613
      // For expediency, we don't actually clear the list here, even though it's
      // no longer representative of what we are registered with. If we never
      // get re-used, it doesn't matter. If we do, then we'll clear the list in
      // activate(). The benefit of this is that it allows BuildableElement's
      // activate() implementation to decide whether to rebuild based on whether
      // we had dependencies here.
1614
    }
1615
    _inheritedWidgets = null;
1616
    _active = false;
1617
    assert(() { _debugLifecycleState = _ElementLifecycle.inactive; return true; });
1618 1619
  }

1620
  /// Called after children have been deactivated (see [deactivate]).
1621
  @mustCallSuper
1622 1623 1624 1625
  void debugDeactivated() {
    assert(_debugLifecycleState == _ElementLifecycle.inactive);
  }

1626 1627
  /// Called when an Element is removed from the tree permanently after having
  /// been deactivated (see [deactivate]).
1628
  @mustCallSuper
1629
  void unmount() {
1630
    assert(_debugLifecycleState == _ElementLifecycle.inactive);
1631 1632
    assert(widget != null);
    assert(depth != null);
1633
    assert(!_active);
1634 1635 1636 1637 1638
    if (widget.key is GlobalKey) {
      final GlobalKey key = widget.key;
      key._unregister(this);
    }
    assert(() { _debugLifecycleState = _ElementLifecycle.defunct; return true; });
1639 1640
  }

1641
  @override
Hixie's avatar
Hixie committed
1642 1643
  RenderObject findRenderObject() => renderObject;

1644
  Map<Type, InheritedElement> _inheritedWidgets;
1645
  Set<InheritedElement> _dependencies;
1646
  bool _hadUnsatisfiedDependencies = false;
1647 1648

  @override
Ian Hickson's avatar
Ian Hickson committed
1649
  InheritedWidget inheritFromWidgetOfExactType(Type targetType) {
1650
    InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
1651 1652
    if (ancestor != null) {
      assert(ancestor is InheritedElement);
1653
      _dependencies ??= new HashSet<InheritedElement>();
1654
      _dependencies.add(ancestor);
1655
      ancestor._dependents.add(this);
1656 1657
      return ancestor.widget;
    }
1658
    _hadUnsatisfiedDependencies = true;
1659
    return null;
Hixie's avatar
Hixie committed
1660 1661
  }

1662
  void _updateInheritance() {
1663
    assert(_active);
1664 1665 1666
    _inheritedWidgets = _parent?._inheritedWidgets;
  }

1667
  @override
Ian Hickson's avatar
Ian Hickson committed
1668
  Widget ancestorWidgetOfExactType(Type targetType) {
1669 1670 1671 1672
    Element ancestor = _parent;
    while (ancestor != null && ancestor.widget.runtimeType != targetType)
      ancestor = ancestor._parent;
    return ancestor?.widget;
1673 1674
  }

1675
  @override
Ian Hickson's avatar
Ian Hickson committed
1676
  State ancestorStateOfType(TypeMatcher matcher) {
Hixie's avatar
Hixie committed
1677 1678
    Element ancestor = _parent;
    while (ancestor != null) {
1679
      if (ancestor is StatefulElement && matcher.check(ancestor.state))
Hixie's avatar
Hixie committed
1680 1681 1682
        break;
      ancestor = ancestor._parent;
    }
1683
    StatefulElement statefulAncestor = ancestor;
Hixie's avatar
Hixie committed
1684 1685
    return statefulAncestor?.state;
  }
1686

1687
  @override
Ian Hickson's avatar
Ian Hickson committed
1688
  RenderObject ancestorRenderObjectOfType(TypeMatcher matcher) {
1689 1690
    Element ancestor = _parent;
    while (ancestor != null) {
Ian Hickson's avatar
Ian Hickson committed
1691
      if (ancestor is RenderObjectElement && matcher.check(ancestor.renderObject))
1692 1693 1694 1695 1696 1697 1698
        break;
      ancestor = ancestor._parent;
    }
    RenderObjectElement renderObjectAncestor = ancestor;
    return renderObjectAncestor?.renderObject;
  }

Adam Barth's avatar
Adam Barth committed
1699 1700 1701
  /// Calls visitor for each ancestor element.
  ///
  /// Continues until visitor reaches the root or until visitor returns false.
1702
  @override
1703 1704 1705 1706
  void visitAncestorElements(bool visitor(Element element)) {
    Element ancestor = _parent;
    while (ancestor != null && visitor(ancestor))
      ancestor = ancestor._parent;
1707 1708
  }

1709 1710
  @mustCallSuper
  void dependenciesChanged() { }
1711

1712
  String debugGetCreatorChain(int limit) {
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723
    List<String> chain = <String>[];
    Element node = this;
    while (chain.length < limit && node != null) {
      chain.add(node.toStringShort());
      node = node._parent;
    }
    if (node != null)
      chain.add('\u22EF');
    return chain.join(' \u2190 ');
  }

1724 1725 1726 1727
  String toStringShort() {
    return widget != null ? '${widget.toStringShort()}' : '[$runtimeType]';
  }

1728
  @override
1729 1730 1731
  String toString() {
    final List<String> data = <String>[];
    debugFillDescription(data);
1732
    final String name = widget != null ? '${widget.runtimeType}' : '[$runtimeType]';
1733 1734
    return '$name(${data.join("; ")})';
  }
1735

1736 1737
  @protected
  @mustCallSuper
1738 1739 1740
  void debugFillDescription(List<String> description) {
    if (depth == null)
      description.add('no depth');
1741
    if (widget == null) {
1742
      description.add('no widget');
1743 1744 1745
    } else {
      if (widget.key != null)
        description.add('${widget.key}');
1746
      widget.debugFillDescription(description);
1747
    }
1748
  }
1749

1750
  String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) {
Hixie's avatar
Hixie committed
1751
    String result = '$prefixLineOne$this\n';
1752
    List<Element> children = <Element>[];
Hixie's avatar
Hixie committed
1753
    visitChildren(children.add);
1754 1755 1756 1757 1758 1759 1760 1761 1762
    if (children.length > 0) {
      Element last = children.removeLast();
      for (Element child in children)
        result += '${child.toStringDeep("$prefixOtherLines \u251C", "$prefixOtherLines \u2502")}';
      result += '${last.toStringDeep("$prefixOtherLines \u2514", "$prefixOtherLines  ")}';
    }
    return result;
  }
}
1763

1764 1765 1766 1767 1768
/// A widget that renders an exception's message. This widget is used when a
/// build function fails, to help with determining where the problem lies.
/// Exceptions are also logged to the console, which you can read using `flutter
/// logs`. The console will also include additional information such as the
/// stack trace for the exception.
1769
class ErrorWidget extends LeafRenderObjectWidget {
1770 1771 1772 1773
  ErrorWidget(
    Object exception
  ) : message = _stringify(exception),
      super(key: new UniqueKey());
1774

1775
  final String message;
1776

1777 1778 1779 1780 1781 1782
  static String _stringify(Object exception) {
    try {
      return exception.toString();
    } catch (e) { }
    return 'Error';
  }
1783 1784

  @override
1785
  RenderBox createRenderObject(BuildContext context) => new RenderErrorBox(message);
Adam Barth's avatar
Adam Barth committed
1786 1787 1788

  @override
  void debugFillDescription(List<String> description) {
1789
    super.debugFillDescription(description);
Adam Barth's avatar
Adam Barth committed
1790 1791
    description.add('message: ' + _stringify(message));
  }
1792
}
1793

1794 1795
/// Base class for instantiations of widgets that have builders and can be
/// marked dirty.
1796 1797
abstract class BuildableElement extends Element {
  BuildableElement(Widget widget) : super(widget);
1798

1799 1800 1801
  /// Returns true if the element has been marked as needing rebuilding.
  bool get dirty => _dirty;
  bool _dirty = true;
1802

1803
  // We let widget authors call setState from initState, didUpdateConfig, and
1804 1805 1806
  // build even when state is locked because its convenient and a no-op anyway.
  // This flag ensures that this convenience is only allowed on the element
  // currently undergoing initState, didUpdateConfig, or build.
1807 1808 1809 1810
  bool _debugAllowIgnoredCallsToMarkNeedsBuild = false;
  bool _debugSetAllowIgnoredCallsToMarkNeedsBuild(bool value) {
    assert(_debugAllowIgnoredCallsToMarkNeedsBuild == !value);
    _debugAllowIgnoredCallsToMarkNeedsBuild = value;
1811 1812 1813
    return true;
  }

1814 1815 1816 1817
  /// Marks the element as dirty and adds it to the global list of widgets to
  /// rebuild in the next frame.
  ///
  /// Since it is inefficient to build an element twice in one frame,
1818 1819
  /// applications and widgets should be structured so as to only mark
  /// widgets dirty during event handlers before the frame begins, not during
1820 1821 1822
  /// the build itself.
  void markNeedsBuild() {
    assert(_debugLifecycleState != _ElementLifecycle.defunct);
1823 1824
    if (!_active)
      return;
1825
    assert(owner != null);
1826
    assert(_debugLifecycleState == _ElementLifecycle.active);
Hixie's avatar
Hixie committed
1827
    assert(() {
1828 1829
      if (owner._debugBuilding) {
        if (owner._debugCurrentBuildTarget == null) {
1830 1831 1832 1833 1834 1835
          // If _debugCurrentBuildTarget is null, we're not actually building a
          // widget but instead building the root of the tree via runApp.
          // TODO(abarth): Remove these cases and ensure that we always have
          // a current build target when we're building.
          return true;
        }
Hixie's avatar
Hixie committed
1836 1837
        bool foundTarget = false;
        visitAncestorElements((Element element) {
1838
          if (element == owner._debugCurrentBuildTarget) {
Hixie's avatar
Hixie committed
1839 1840 1841 1842 1843 1844 1845 1846
            foundTarget = true;
            return false;
          }
          return true;
        });
        if (foundTarget)
          return true;
      }
1847
      if (owner._debugStateLocked && (!_debugAllowIgnoredCallsToMarkNeedsBuild || !dirty)) {
1848
        throw new FlutterError(
1849
          'setState() or markNeedsBuild() called during build.\n'
1850
          'This widget cannot be marked as needing to build because the framework '
1851 1852
          'is already in the process of building widgets. A widget can be marked as '
          'needing to be built during the build phase only if one if its ancestors '
1853 1854 1855 1856 1857 1858 1859
          'is currently building. This exception is allowed because the framework '
          'builds parent widgets before children, which means a dirty descendant '
          'will always be built. Otherwise, the framework might not visit this '
          'widget during this build phase.'
        );
      }
      return true;
Hixie's avatar
Hixie committed
1860
    });
1861 1862 1863
    if (dirty)
      return;
    _dirty = true;
1864
    owner.scheduleBuildFor(this);
1865
  }
1866

1867
  /// Called by the binding when scheduleBuild() has been called to mark this
1868
  /// element dirty, and, in components, by update() when the widget has
1869 1870 1871 1872 1873 1874 1875 1876
  /// changed.
  void rebuild() {
    assert(_debugLifecycleState != _ElementLifecycle.initial);
    if (!_active || !_dirty) {
      _dirty = false;
      return;
    }
    assert(_debugLifecycleState == _ElementLifecycle.active);
1877
    assert(owner._debugStateLocked);
1878 1879
    BuildableElement debugPreviousBuildTarget;
    assert(() {
1880 1881
      debugPreviousBuildTarget = owner._debugCurrentBuildTarget;
      owner._debugCurrentBuildTarget = this;
1882 1883
     return true;
    });
1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896
    _hadUnsatisfiedDependencies = false;
    // In theory, we would also clear our actual _dependencies here. However, to
    // clear it we'd have to notify each of them, unregister from them, and then
    // reregister as soon as the build function re-dependended on it. So to
    // avoid faffing around we just never unregister our dependencies except
    // when we're deactivated. In principle this means we might be getting
    // notified about widget types we once inherited from but no longer do, but
    // in practice this is so rare that the extra cost when it does happen is
    // far outweighed by the avoided work in the common case.
    // We _do_ clear the list properly any time our ancestor chain changes in a
    // way that might result in us getting a different Element's Widget for a
    // particular Type. This avoids the potential of being registered to
    // multiple identically-typed Widgets' Elements at the same time.
1897 1898
    performRebuild();
    assert(() {
1899 1900
      assert(owner._debugCurrentBuildTarget == this);
      owner._debugCurrentBuildTarget = debugPreviousBuildTarget;
1901 1902
      return true;
    });
1903
    assert(!_dirty);
1904 1905
  }

1906
  /// Called by rebuild() after the appropriate checks have been made.
1907
  @protected
1908
  void performRebuild();
1909

1910
  @override
1911
  void dependenciesChanged() {
1912
    super.dependenciesChanged();
1913
    assert(_active);
1914 1915
    markNeedsBuild();
  }
1916

1917 1918 1919 1920 1921 1922 1923 1924 1925 1926
  @override
  void activate() {
    final bool shouldRebuild = ((_dependencies != null && _dependencies.length > 0) || _hadUnsatisfiedDependencies);
    super.activate(); // clears _dependencies, and sets active to true
    if (shouldRebuild) {
      assert(_active); // otherwise markNeedsBuild is a no-op
      markNeedsBuild();
    }
  }

1927 1928
  @override
  void _reassemble() {
1929
    assert(_active); // otherwise markNeedsBuild is a no-op
1930 1931 1932 1933
    markNeedsBuild();
    super._reassemble();
  }

1934
  @override
1935 1936 1937 1938 1939
  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    if (dirty)
      description.add('dirty');
  }
1940 1941
}

1942
typedef Widget WidgetBuilder(BuildContext context);
1943
typedef Widget IndexedWidgetBuilder(BuildContext context, int index);
1944

1945
// See ComponentElement._builder.
1946 1947
Widget _buildNothing(BuildContext context) => null;

1948 1949
/// Base class for the instantiation of [StatelessWidget], [StatefulWidget],
/// and [_ProxyWidget] widgets.
1950 1951
abstract class ComponentElement extends BuildableElement {
  ComponentElement(Widget widget) : super(widget);
1952

1953 1954 1955 1956
  // Initializing this field with _buildNothing helps the compiler prove that
  // this field always holds a closure.
  WidgetBuilder _builder = _buildNothing;

1957 1958
  Element _child;

1959
  @override
1960 1961 1962 1963
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    assert(_child == null);
    assert(_active);
Ian Hickson's avatar
Ian Hickson committed
1964
    _firstBuild();
1965 1966 1967
    assert(_child != null);
  }

Ian Hickson's avatar
Ian Hickson committed
1968 1969 1970 1971
  void _firstBuild() {
    rebuild();
  }

1972
  /// Calls the build() method of the [StatelessWidget] object (for
1973
  /// stateless widgets) or the [State] object (for stateful widgets) and
1974 1975 1976 1977
  /// then updates the widget tree.
  ///
  /// Called automatically during mount() to generate the first build, and by
  /// rebuild() when the element needs updating.
1978
  @override
1979 1980 1981 1982 1983
  void performRebuild() {
    assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(true));
    Widget built;
    try {
      built = _builder(this);
1984
      debugWidgetBuilderValue(widget, built);
1985
    } catch (e, stack) {
Hixie's avatar
Hixie committed
1986
      _debugReportException('building $_widget', e, stack);
1987
      built = new ErrorWidget(e);
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997
    } finally {
      // We delay marking the element as clean until after calling _builder so
      // that attempts to markNeedsBuild() during build() will be ignored.
      _dirty = false;
      assert(_debugSetAllowIgnoredCallsToMarkNeedsBuild(false));
    }
    try {
      _child = updateChild(_child, built, slot);
      assert(_child != null);
    } catch (e, stack) {
Hixie's avatar
Hixie committed
1998
      _debugReportException('building $_widget', e, stack);
1999
      built = new ErrorWidget(e);
2000 2001 2002 2003
      _child = updateChild(null, built, slot);
    }
  }

2004
  @override
2005 2006 2007 2008 2009
  void visitChildren(ElementVisitor visitor) {
    if (_child != null)
      visitor(_child);
  }

2010
  @override
2011 2012
  bool detachChild(Element child) {
    assert(child == _child);
Hixie's avatar
Hixie committed
2013
    deactivateChild(_child);
2014 2015 2016 2017 2018
    _child = null;
    return true;
  }
}

2019 2020 2021
/// Instantiation of [StatelessWidget]s.
class StatelessElement extends ComponentElement {
  StatelessElement(StatelessWidget widget) : super(widget) {
2022
    _builder = widget.build;
2023
  }
2024

2025
  @override
2026
  StatelessWidget get widget => super.widget;
2027

2028
  @override
2029
  void update(StatelessWidget newWidget) {
2030 2031
    super.update(newWidget);
    assert(widget == newWidget);
2032
    _builder = widget.build;
2033 2034 2035
    _dirty = true;
    rebuild();
  }
2036 2037 2038

  @override
  void _reassemble() {
2039
    _builder = widget.build;
2040 2041
    super._reassemble();
  }
2042
}
2043

2044 2045 2046
/// Instantiation of [StatefulWidget]s.
class StatefulElement extends ComponentElement {
  StatefulElement(StatefulWidget widget)
2047
    : _state = widget.createState(), super(widget) {
2048
    assert(_state._debugTypesAreRight(widget));
2049 2050
    assert(_state._element == null);
    _state._element = this;
2051
    assert(_builder == _buildNothing);
pq's avatar
pq committed
2052
    _builder = _state.build;
2053 2054 2055
    assert(_state._config == null);
    _state._config = widget;
    assert(_state._debugLifecycleState == _StateLifecycle.created);
Ian Hickson's avatar
Ian Hickson committed
2056 2057
  }

2058 2059
  State<StatefulWidget> get state => _state;
  State<StatefulWidget> _state;
Ian Hickson's avatar
Ian Hickson committed
2060

2061 2062
  @override
  void _reassemble() {
pq's avatar
pq committed
2063
    _builder = state.build;
2064 2065 2066
    super._reassemble();
  }

2067
  @override
Ian Hickson's avatar
Ian Hickson committed
2068 2069
  void _firstBuild() {
    assert(_state._debugLifecycleState == _StateLifecycle.created);
2070
    try {
2071 2072
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      _state.initState();
2073
    } finally {
2074
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
2075
    }
2076 2077 2078
    assert(() {
      if (_state._debugLifecycleState == _StateLifecycle.initialized)
        return true;
2079
      throw new FlutterError(
2080 2081 2082 2083
        '${_state.runtimeType}.initState failed to call super.initState.\n'
        'initState() implementations must always call their superclass initState() method, to ensure '
        'that the entire widget is initialized correctly.'
      );
2084 2085
    });
    assert(() { _state._debugLifecycleState = _StateLifecycle.ready; return true; });
Ian Hickson's avatar
Ian Hickson committed
2086
    super._firstBuild();
2087
  }
2088

2089
  @override
2090
  void update(StatefulWidget newWidget) {
2091 2092
    super.update(newWidget);
    assert(widget == newWidget);
2093
    StatefulWidget oldConfig = _state._config;
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103
    // Notice that we mark ourselves as dirty before calling didUpdateConfig to
    // let authors call setState from within didUpdateConfig without triggering
    // asserts.
    _dirty = true;
    _state._config = widget;
    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      _state.didUpdateConfig(oldConfig);
    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
2104
    }
2105
    rebuild();
2106
  }
2107

2108 2109 2110
  @override
  void activate() {
    super.activate();
2111 2112 2113 2114
    // Since the State could have observed the deactivate() and thus disposed of
    // resources allocated in the build function, we have to rebuild the widget
    // so that its State can reallocate its resources.
    assert(_active); // otherwise markNeedsBuild is a no-op
2115 2116 2117
    markNeedsBuild();
  }

2118
  @override
2119 2120 2121 2122 2123
  void deactivate() {
    _state.deactivate();
    super.deactivate();
  }

2124
  @override
2125 2126 2127 2128 2129 2130
  void unmount() {
    super.unmount();
    _state.dispose();
    assert(() {
      if (_state._debugLifecycleState == _StateLifecycle.defunct)
        return true;
2131
      throw new FlutterError(
2132 2133 2134 2135
        '${_state.runtimeType}.dispose failed to call super.dispose.\n'
        'dispose() implementations must always call their superclass dispose() method, to ensure '
        'that all the resources used by the widget are fully released.'
      );
2136 2137 2138 2139 2140
    });
    assert(!dirty); // See BuildableElement.unmount for why this is important.
    _state._element = null;
    _state = null;
  }
2141

2142
  @override
2143 2144 2145
  void dependenciesChanged() {
    super.dependenciesChanged();
    _state.dependenciesChanged();
2146 2147
  }

2148
  @override
2149 2150 2151 2152
  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    if (state != null)
      description.add('state: $state');
2153
  }
2154 2155
}

2156
abstract class _ProxyElement extends ComponentElement {
2157
  _ProxyElement(_ProxyWidget widget) : super(widget) {
2158
    _builder = _build;
Hixie's avatar
Hixie committed
2159 2160
  }

2161
  @override
2162
  _ProxyWidget get widget => super.widget;
2163

2164 2165
  Widget _build(BuildContext context) => widget.child;

2166 2167 2168 2169 2170 2171
  @override
  void _reassemble() {
    _builder = _build;
    super._reassemble();
  }

2172
  @override
2173 2174
  void update(_ProxyWidget newWidget) {
    _ProxyWidget oldWidget = widget;
Hixie's avatar
Hixie committed
2175 2176 2177 2178
    assert(widget != null);
    assert(widget != newWidget);
    super.update(newWidget);
    assert(widget == newWidget);
2179
    notifyClients(oldWidget);
Hixie's avatar
Hixie committed
2180 2181 2182 2183
    _dirty = true;
    rebuild();
  }

2184
  @protected
2185
  void notifyClients(_ProxyWidget oldWidget);
Hixie's avatar
Hixie committed
2186 2187
}

2188 2189 2190
class ParentDataElement<T extends RenderObjectWidget> extends _ProxyElement {
  ParentDataElement(ParentDataWidget<T> widget) : super(widget);

2191
  @override
2192
  ParentDataWidget<T> get widget => super.widget;
2193

2194
  @override
2195 2196
  void mount(Element parent, dynamic slot) {
    assert(() {
2197
      List<Widget> badAncestors = <Widget>[];
2198
      Element ancestor = parent;
2199
      while (ancestor != null) {
Hixie's avatar
Hixie committed
2200
        if (ancestor is ParentDataElement<RenderObjectWidget>) {
2201 2202 2203 2204 2205 2206
          badAncestors.add(ancestor.widget);
        } else if (ancestor is RenderObjectElement) {
          if (widget.debugIsValidAncestor(ancestor.widget))
            break;
          badAncestors.add(ancestor.widget);
        }
2207 2208
        ancestor = ancestor._parent;
      }
2209 2210
      if (ancestor != null && badAncestors.isEmpty)
        return true;
2211
      throw new FlutterError(
2212 2213 2214
        'Incorrect use of ParentDataWidget.\n' +
        widget.debugDescribeInvalidAncestorChain(
          description: "$this",
2215
          ownershipChain: parent.debugGetCreatorChain(10),
2216 2217 2218 2219
          foundValidAncestor: ancestor != null,
          badAncestors: badAncestors
        )
      );
2220 2221
    });
    super.mount(parent, slot);
2222 2223
  }

2224
  @override
2225
  void notifyClients(ParentDataWidget<T> oldWidget) {
2226
    void notifyChildren(Element child) {
2227
      if (child is RenderObjectElement) {
2228
        child._updateParentData(widget);
2229
      } else {
Hixie's avatar
Hixie committed
2230
        assert(child is! ParentDataElement<RenderObjectWidget>);
2231
        child.visitChildren(notifyChildren);
2232
      }
2233 2234 2235 2236
    }
    visitChildren(notifyChildren);
  }
}
2237 2238


2239
class InheritedElement extends _ProxyElement {
Hixie's avatar
Hixie committed
2240 2241
  InheritedElement(InheritedWidget widget) : super(widget);

2242
  @override
2243 2244
  InheritedWidget get widget => super.widget;

2245
  final Set<Element> _dependents = new HashSet<Element>();
2246

2247
  @override
2248
  void _updateInheritance() {
2249
    assert(_active);
2250 2251 2252 2253 2254 2255 2256
    final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
    if (incomingWidgets != null)
      _inheritedWidgets = new Map<Type, InheritedElement>.from(incomingWidgets);
    else
      _inheritedWidgets = new Map<Type, InheritedElement>();
    _inheritedWidgets[widget.runtimeType] = this;
  }
2257

2258
  @override
2259 2260
  void debugDeactivated() {
    assert(() {
2261
      assert(_dependents.isEmpty);
2262 2263 2264 2265 2266
      return true;
    });
    super.debugDeactivated();
  }

2267
  @override
2268
  void notifyClients(InheritedWidget oldWidget) {
Hixie's avatar
Hixie committed
2269 2270
    if (!widget.updateShouldNotify(oldWidget))
      return;
2271 2272 2273 2274 2275 2276 2277 2278 2279
    dispatchDependenciesChanged();
  }

  /// Notifies all dependent elements that this inherited widget has changed.
  ///
  /// [InheritedElement] calls this function if [InheritedWidget.updateShouldNotify]
  /// returns true. Subclasses of [InheritedElement] might wish to call this
  /// function at other times if their inherited information changes outside of
  /// the build phase.
2280
  @protected
2281
  void dispatchDependenciesChanged() {
2282
    for (Element dependent in _dependents) {
2283 2284
      assert(() {
        // check that it really is our descendant
2285
        Element ancestor = dependent._parent;
2286 2287 2288 2289
        while (ancestor != this && ancestor != null)
          ancestor = ancestor._parent;
        return ancestor == this;
      });
2290 2291
      // check that it really deepends on us
      assert(dependent._dependencies.contains(this));
2292
      dependent.dependenciesChanged();
2293 2294
    }
  }
2295
}
2296

2297
/// Base class for instantiations of RenderObjectWidget subclasses
2298 2299 2300
abstract class RenderObjectElement extends BuildableElement {
  RenderObjectElement(RenderObjectWidget widget) : super(widget);

2301
  @override
2302
  RenderObjectWidget get widget => super.widget;
2303

2304
  /// The underlying [RenderObject] for this element
2305
  @override
2306
  RenderObject get renderObject => _renderObject;
2307
  RenderObject _renderObject;
2308

2309
  RenderObjectElement _ancestorRenderObjectElement;
2310

2311 2312 2313 2314
  RenderObjectElement _findAncestorRenderObjectElement() {
    Element ancestor = _parent;
    while (ancestor != null && ancestor is! RenderObjectElement)
      ancestor = ancestor._parent;
2315 2316 2317
    return ancestor;
  }

Hixie's avatar
Hixie committed
2318
  ParentDataElement<RenderObjectWidget> _findAncestorParentDataElement() {
2319 2320
    Element ancestor = _parent;
    while (ancestor != null && ancestor is! RenderObjectElement) {
Hixie's avatar
Hixie committed
2321
      if (ancestor is ParentDataElement<RenderObjectWidget>)
2322 2323
        return ancestor;
      ancestor = ancestor._parent;
2324
    }
2325 2326 2327
    return null;
  }

2328
  @override
2329 2330
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
2331
    _renderObject = widget.createRenderObject(this);
2332
    assert(() { _debugUpdateRenderObjectOwner(); return true; });
2333
    assert(_slot == newSlot);
2334
    attachRenderObject(newSlot);
2335
    _dirty = false;
2336 2337
  }

2338
  @override
2339
  void update(RenderObjectWidget newWidget) {
2340 2341
    super.update(newWidget);
    assert(widget == newWidget);
2342
    assert(() { _debugUpdateRenderObjectOwner(); return true; });
2343
    widget.updateRenderObject(this, renderObject);
2344 2345 2346
    _dirty = false;
  }

2347
  void _debugUpdateRenderObjectOwner() {
2348
    _renderObject.debugCreator = debugGetCreatorChain(10);
2349 2350
  }

2351
  @override
2352
  void performRebuild() {
2353
    widget.updateRenderObject(this, renderObject);
2354 2355 2356
    _dirty = false;
  }

2357 2358 2359 2360
  /// Utility function for subclasses that have one or more lists of children.
  /// Attempts to update the given old children list using the given new
  /// widgets, removing obsolete elements and introducing new ones as necessary,
  /// and then returns the new child list.
2361
  @protected
2362
  List<Element> updateChildren(List<Element> oldChildren, List<Widget> newWidgets, { Set<Element> detachedChildren }) {
2363
    assert(oldChildren != null);
2364
    assert(newWidgets != null);
2365

2366 2367 2368 2369
    Element replaceWithNullIfDetached(Element child) {
      return detachedChildren != null && detachedChildren.contains(child) ? null : child;
    }

2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382
    // This attempts to diff the new child list (this.children) with
    // the old child list (old.children), and update our renderObject
    // accordingly.

    // The cases it tries to optimise for are:
    //  - the old list is empty
    //  - the lists are identical
    //  - there is an insertion or removal of one or more widgets in
    //    only one place in the list
    // If a widget with a key is in both lists, it will be synced.
    // Widgets without keys might be synced but there is no guarantee.

    // The general approach is to sync the entire new list backwards, as follows:
2383 2384 2385 2386 2387 2388
    // 1. Walk the lists from the top, syncing nodes, until you no longer have
    //    matching nodes.
    // 2. Walk the lists from the bottom, without syncing nodes, until you no
    //    longer have matching nodes. We'll sync these nodes at the end. We
    //    don't sync them now because we want to sync all the nodes in order
    //    from beginning ot end.
2389 2390 2391 2392
    // At this point we narrowed the old and new lists to the point
    // where the nodes no longer match.
    // 3. Walk the narrowed part of the old list to get the list of
    //    keys and sync null with non-keyed items.
2393
    // 4. Walk the narrowed part of the new list forwards:
2394 2395
    //     * Sync unkeyed items with null
    //     * Sync keyed items with the source if it exists, else with null.
2396
    // 5. Walk the bottom of the list again, syncing the nodes.
2397 2398 2399
    // 6. Sync null with any items in the list of keys that are still
    //    mounted.

2400 2401
    int newChildrenTop = 0;
    int oldChildrenTop = 0;
2402 2403
    int newChildrenBottom = newWidgets.length - 1;
    int oldChildrenBottom = oldChildren.length - 1;
2404

2405 2406 2407 2408 2409 2410 2411
    List<Element> newChildren = oldChildren.length == newWidgets.length ?
        oldChildren : new List<Element>(newWidgets.length);

    Element previousChild;

    // Update the top of the list.
    while ((oldChildrenTop <= oldChildrenBottom) && (newChildrenTop <= newChildrenBottom)) {
2412
      Element oldChild = replaceWithNullIfDetached(oldChildren[oldChildrenTop]);
2413
      Widget newWidget = newWidgets[newChildrenTop];
2414 2415
      assert(oldChild == null || oldChild._debugLifecycleState == _ElementLifecycle.active);
      if (oldChild == null || !Widget.canUpdate(oldChild.widget, newWidget))
2416
        break;
2417 2418 2419 2420 2421 2422
      Element newChild = updateChild(oldChild, newWidget, previousChild);
      assert(newChild._debugLifecycleState == _ElementLifecycle.active);
      newChildren[newChildrenTop] = newChild;
      previousChild = newChild;
      newChildrenTop += 1;
      oldChildrenTop += 1;
2423 2424
    }

2425 2426
    // Scan the bottom of the list.
    while ((oldChildrenTop <= oldChildrenBottom) && (newChildrenTop <= newChildrenBottom)) {
2427
      Element oldChild = replaceWithNullIfDetached(oldChildren[oldChildrenBottom]);
2428
      Widget newWidget = newWidgets[newChildrenBottom];
2429 2430
      assert(oldChild == null || oldChild._debugLifecycleState == _ElementLifecycle.active);
      if (oldChild == null || !Widget.canUpdate(oldChild.widget, newWidget))
2431
        break;
2432 2433
      oldChildrenBottom -= 1;
      newChildrenBottom -= 1;
2434 2435
    }

2436 2437
    // Scan the old children in the middle of the list.
    bool haveOldChildren = oldChildrenTop <= oldChildrenBottom;
2438
    Map<Key, Element> oldKeyedChildren;
2439
    if (haveOldChildren) {
2440
      oldKeyedChildren = new Map<Key, Element>();
2441
      while (oldChildrenTop <= oldChildrenBottom) {
2442
        Element oldChild = replaceWithNullIfDetached(oldChildren[oldChildrenTop]);
2443 2444 2445 2446 2447
        assert(oldChild == null || oldChild._debugLifecycleState == _ElementLifecycle.active);
        if (oldChild != null) {
          if (oldChild.widget.key != null)
            oldKeyedChildren[oldChild.widget.key] = oldChild;
          else
Hixie's avatar
Hixie committed
2448
            deactivateChild(oldChild);
2449
        }
2450
        oldChildrenTop += 1;
2451
      }
2452 2453
    }

2454 2455
    // Update the middle of the list.
    while (newChildrenTop <= newChildrenBottom) {
2456
      Element oldChild;
2457 2458
      Widget newWidget = newWidgets[newChildrenTop];
      if (haveOldChildren) {
2459
        Key key = newWidget.key;
2460
        if (key != null) {
2461
          oldChild = oldKeyedChildren[newWidget.key];
2462
          if (oldChild != null) {
2463
            if (Widget.canUpdate(oldChild.widget, newWidget)) {
2464 2465 2466 2467
              // we found a match!
              // remove it from oldKeyedChildren so we don't unsync it later
              oldKeyedChildren.remove(key);
            } else {
2468
              // Not a match, let's pretend we didn't see it for now.
2469
              oldChild = null;
2470
            }
2471 2472
          }
        }
2473
      }
2474
      assert(oldChild == null || Widget.canUpdate(oldChild.widget, newWidget));
2475
      Element newChild = updateChild(oldChild, newWidget, previousChild);
2476 2477
      assert(newChild._debugLifecycleState == _ElementLifecycle.active);
      assert(oldChild == newChild || oldChild == null || oldChild._debugLifecycleState != _ElementLifecycle.active);
2478 2479 2480
      newChildren[newChildrenTop] = newChild;
      previousChild = newChild;
      newChildrenTop += 1;
2481
    }
2482

2483 2484 2485 2486 2487 2488 2489 2490 2491 2492
    // We've scaned the whole list.
    assert(oldChildrenTop == oldChildrenBottom + 1);
    assert(newChildrenTop == newChildrenBottom + 1);
    assert(newWidgets.length - newChildrenTop == oldChildren.length - oldChildrenTop);
    newChildrenBottom = newWidgets.length - 1;
    oldChildrenBottom = oldChildren.length - 1;

    // Update the bottom of the list.
    while ((oldChildrenTop <= oldChildrenBottom) && (newChildrenTop <= newChildrenBottom)) {
      Element oldChild = oldChildren[oldChildrenTop];
2493
      assert(replaceWithNullIfDetached(oldChild) != null);
2494
      assert(oldChild._debugLifecycleState == _ElementLifecycle.active);
2495
      Widget newWidget = newWidgets[newChildrenTop];
2496
      assert(Widget.canUpdate(oldChild.widget, newWidget));
2497
      Element newChild = updateChild(oldChild, newWidget, previousChild);
2498 2499
      assert(newChild._debugLifecycleState == _ElementLifecycle.active);
      assert(oldChild == newChild || oldChild == null || oldChild._debugLifecycleState != _ElementLifecycle.active);
2500 2501 2502 2503
      newChildren[newChildrenTop] = newChild;
      previousChild = newChild;
      newChildrenTop += 1;
      oldChildrenTop += 1;
2504 2505
    }

2506
    // clean up any of the remaining middle nodes from the old list
Ian Hickson's avatar
Ian Hickson committed
2507
    if (haveOldChildren && oldKeyedChildren.isNotEmpty) {
2508 2509
      for (Element oldChild in oldKeyedChildren.values) {
        if (detachedChildren == null || !detachedChildren.contains(oldChild))
Hixie's avatar
Hixie committed
2510
          deactivateChild(oldChild);
2511
      }
2512 2513
    }

2514
    return newChildren;
2515 2516
  }

2517
  @override
2518 2519 2520 2521 2522
  void deactivate() {
    super.deactivate();
    assert(!renderObject.attached);
  }

2523
  @override
2524 2525 2526 2527 2528 2529
  void unmount() {
    super.unmount();
    assert(!renderObject.attached);
    widget.didUnmountRenderObject(renderObject);
  }

2530
  void _updateParentData(ParentDataWidget<RenderObjectWidget> parentData) {
2531
    parentData.applyParentData(renderObject);
Hixie's avatar
Hixie committed
2532 2533
  }

2534
  @override
2535 2536 2537 2538 2539
  void _updateSlot(dynamic newSlot) {
    assert(slot != newSlot);
    super._updateSlot(newSlot);
    assert(slot == newSlot);
    _ancestorRenderObjectElement.moveChildRenderObject(renderObject, slot);
Hixie's avatar
Hixie committed
2540 2541
  }

2542
  @override
2543 2544 2545 2546 2547
  void attachRenderObject(dynamic newSlot) {
    assert(_ancestorRenderObjectElement == null);
    _slot = newSlot;
    _ancestorRenderObjectElement = _findAncestorRenderObjectElement();
    _ancestorRenderObjectElement?.insertChildRenderObject(renderObject, newSlot);
Hixie's avatar
Hixie committed
2548
    ParentDataElement<RenderObjectWidget> parentDataElement = _findAncestorParentDataElement();
2549
    if (parentDataElement != null)
2550
      _updateParentData(parentDataElement.widget);
2551 2552
  }

2553
  @override
Hixie's avatar
Hixie committed
2554
  void detachRenderObject() {
2555 2556 2557 2558
    if (_ancestorRenderObjectElement != null) {
      _ancestorRenderObjectElement.removeChildRenderObject(renderObject);
      _ancestorRenderObjectElement = null;
    }
2559
    _slot = null;
Hixie's avatar
Hixie committed
2560 2561
  }

2562
  @protected
2563
  void insertChildRenderObject(RenderObject child, dynamic slot);
2564 2565

  @protected
2566
  void moveChildRenderObject(RenderObject child, dynamic slot);
2567 2568

  @protected
2569
  void removeChildRenderObject(RenderObject child);
Hixie's avatar
Hixie committed
2570

2571
  @override
2572 2573 2574 2575 2576 2577
  void debugFillDescription(List<String> description) {
    super.debugFillDescription(description);
    if (renderObject != null)
      description.add('renderObject: $renderObject');
  }
}
Hixie's avatar
Hixie committed
2578

2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598
/// Instantiation of RenderObjectWidgets at the root of the tree
///
/// Only root elements may have their owner set explicitly. All other
/// elements inherit their owner from their parent.
abstract class RootRenderObjectElement extends RenderObjectElement {
  RootRenderObjectElement(RenderObjectWidget widget): super(widget);

  void assignOwner(BuildOwner owner) {
    _owner = owner;
  }

  @override
  void mount(Element parent, dynamic newSlot) {
    // Root elements should never have parents
    assert(parent == null);
    assert(newSlot == null);
    super.mount(parent, newSlot);
  }
}

2599
/// Instantiation of RenderObjectWidgets that have no children
2600 2601
class LeafRenderObjectElement extends RenderObjectElement {
  LeafRenderObjectElement(LeafRenderObjectWidget widget): super(widget);
Hixie's avatar
Hixie committed
2602

2603
  @override
2604
  void insertChildRenderObject(RenderObject child, dynamic slot) {
Hixie's avatar
Hixie committed
2605 2606 2607
    assert(false);
  }

2608
  @override
2609
  void moveChildRenderObject(RenderObject child, dynamic slot) {
Hixie's avatar
Hixie committed
2610 2611 2612
    assert(false);
  }

2613
  @override
2614 2615 2616
  void removeChildRenderObject(RenderObject child) {
    assert(false);
  }
Hixie's avatar
Hixie committed
2617 2618
}

2619
/// Instantiation of RenderObjectWidgets that have up to one child
2620 2621
class SingleChildRenderObjectElement extends RenderObjectElement {
  SingleChildRenderObjectElement(SingleChildRenderObjectWidget widget) : super(widget);
2622

2623
  @override
2624
  SingleChildRenderObjectWidget get widget => super.widget;
Hixie's avatar
Hixie committed
2625

2626
  Element _child;
Hixie's avatar
Hixie committed
2627

2628
  @override
2629 2630 2631
  void visitChildren(ElementVisitor visitor) {
    if (_child != null)
      visitor(_child);
Hixie's avatar
Hixie committed
2632 2633
  }

2634
  @override
2635 2636
  bool detachChild(Element child) {
    assert(child == _child);
Hixie's avatar
Hixie committed
2637
    deactivateChild(_child);
2638 2639 2640 2641
    _child = null;
    return true;
  }

2642
  @override
2643 2644 2645
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    _child = updateChild(_child, widget.child, null);
2646 2647
  }

2648
  @override
2649
  void update(SingleChildRenderObjectWidget newWidget) {
2650 2651 2652
    super.update(newWidget);
    assert(widget == newWidget);
    _child = updateChild(_child, widget.child, null);
Hixie's avatar
Hixie committed
2653 2654
  }

2655
  @override
2656
  void insertChildRenderObject(RenderObject child, dynamic slot) {
Hixie's avatar
Hixie committed
2657
    final RenderObjectWithChildMixin<RenderObject> renderObject = this.renderObject;
Hixie's avatar
Hixie committed
2658
    assert(slot == null);
2659
    renderObject.child = child;
Hixie's avatar
Hixie committed
2660
    assert(renderObject == this.renderObject);
Hixie's avatar
Hixie committed
2661 2662
  }

2663
  @override
2664 2665 2666 2667
  void moveChildRenderObject(RenderObject child, dynamic slot) {
    assert(false);
  }

2668
  @override
2669
  void removeChildRenderObject(RenderObject child) {
Hixie's avatar
Hixie committed
2670
    final RenderObjectWithChildMixin<RenderObject> renderObject = this.renderObject;
2671
    assert(renderObject.child == child);
Hixie's avatar
Hixie committed
2672
    renderObject.child = null;
Hixie's avatar
Hixie committed
2673
    assert(renderObject == this.renderObject);
Hixie's avatar
Hixie committed
2674 2675 2676
  }
}

2677
/// Instantiation of RenderObjectWidgets that can have a list of children
2678 2679
class MultiChildRenderObjectElement extends RenderObjectElement {
  MultiChildRenderObjectElement(MultiChildRenderObjectWidget widget) : super(widget) {
2680
    assert(!debugChildrenHaveDuplicateKeys(widget, widget.children));
Hixie's avatar
Hixie committed
2681 2682
  }

2683
  @override
2684 2685
  MultiChildRenderObjectWidget get widget => super.widget;

2686
  List<Element> _children;
2687
  // We keep a set of detached children to avoid O(n^2) work walking _children
2688
  // repeatedly to remove children.
2689
  final Set<Element> _detachedChildren = new HashSet<Element>();
Hixie's avatar
Hixie committed
2690

2691
  @override
2692
  void insertChildRenderObject(RenderObject child, Element slot) {
Hixie's avatar
Hixie committed
2693
    final ContainerRenderObjectMixin<RenderObject, ContainerParentDataMixin<RenderObject>> renderObject = this.renderObject;
2694
    renderObject.insert(child, after: slot?.renderObject);
Hixie's avatar
Hixie committed
2695
    assert(renderObject == this.renderObject);
Hixie's avatar
Hixie committed
2696 2697
  }

2698
  @override
2699
  void moveChildRenderObject(RenderObject child, dynamic slot) {
Hixie's avatar
Hixie committed
2700
    final ContainerRenderObjectMixin<RenderObject, ContainerParentDataMixin<RenderObject>> renderObject = this.renderObject;
2701
    assert(child.parent == renderObject);
2702
    renderObject.move(child, after: slot?.renderObject);
Hixie's avatar
Hixie committed
2703
    assert(renderObject == this.renderObject);
Hixie's avatar
Hixie committed
2704 2705
  }

2706
  @override
2707
  void removeChildRenderObject(RenderObject child) {
Hixie's avatar
Hixie committed
2708
    final ContainerRenderObjectMixin<RenderObject, ContainerParentDataMixin<RenderObject>> renderObject = this.renderObject;
2709 2710
    assert(child.parent == renderObject);
    renderObject.remove(child);
Hixie's avatar
Hixie committed
2711
    assert(renderObject == this.renderObject);
Hixie's avatar
Hixie committed
2712 2713
  }

2714
  @override
2715
  void visitChildren(ElementVisitor visitor) {
2716
    for (Element child in _children) {
2717
      if (!_detachedChildren.contains(child))
2718 2719 2720 2721
        visitor(child);
    }
  }

2722
  @override
2723 2724
  bool detachChild(Element child) {
    _detachedChildren.add(child);
Hixie's avatar
Hixie committed
2725
    deactivateChild(child);
2726
    return true;
2727 2728
  }

2729
  @override
2730 2731 2732 2733
  void mount(Element parent, dynamic newSlot) {
    super.mount(parent, newSlot);
    _children = new List<Element>(widget.children.length);
    Element previousChild;
2734
    for (int i = 0; i < _children.length; ++i) {
Hixie's avatar
Hixie committed
2735
      Element newChild = inflateWidget(widget.children[i], previousChild);
2736 2737
      _children[i] = newChild;
      previousChild = newChild;
2738 2739 2740
    }
  }

2741
  @override
2742
  void update(MultiChildRenderObjectWidget newWidget) {
2743 2744
    super.update(newWidget);
    assert(widget == newWidget);
2745 2746
    _children = updateChildren(_children, widget.children, detachedChildren: _detachedChildren);
    _detachedChildren.clear();
2747
  }
2748 2749 2750
}

void _debugReportException(String context, dynamic exception, StackTrace stack) {
2751 2752 2753 2754 2755 2756
  FlutterError.reportError(new FlutterErrorDetails(
    exception: exception,
    stack: stack,
    library: 'widgets library',
    context: context
  ));
2757
}