| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 library fn; | |
| 6 | |
| 7 import 'app.dart'; | |
| 8 import 'dart:async'; | 5 import 'dart:async'; |
| 9 import 'dart:collection'; | 6 import 'dart:collection'; |
| 10 import 'dart:mirrors'; | 7 import 'dart:mirrors'; |
| 11 import 'dart:sky' as sky; | 8 import 'dart:sky' as sky; |
| 12 import 'package:vector_math/vector_math.dart'; | 9 |
| 13 import 'rendering/block.dart'; | 10 import '../app.dart'; |
| 14 import 'rendering/box.dart'; | 11 import '../rendering/box.dart'; |
| 15 import 'rendering/flex.dart'; | 12 import '../rendering/object.dart'; |
| 16 import 'rendering/object.dart'; | 13 |
| 17 import 'rendering/paragraph.dart'; | 14 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde
rSide, EdgeDims; |
| 18 import 'rendering/stack.dart'; | 15 export '../rendering/flex.dart' show FlexDirection; |
| 19 export 'rendering/object.dart' show Point, Size, Rect, Color, Paint, Path; | 16 export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path; |
| 20 export 'rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSi
de, EdgeDims; | 17 |
| 21 export 'rendering/flex.dart' show FlexDirection; | |
| 22 | 18 |
| 23 // final sky.Tracing _tracing = sky.window.tracing; | 19 // final sky.Tracing _tracing = sky.window.tracing; |
| 24 | 20 |
| 25 final bool _shouldLogRenderDuration = false; | 21 final bool _shouldLogRenderDuration = false; |
| 26 | 22 |
| 27 /* | 23 /* |
| 28 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and | 24 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and |
| 29 * can be sync'd. | 25 * can be sync'd. |
| 30 */ | 26 */ |
| 31 abstract class UINode { | 27 abstract class UINode { |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 } | 144 } |
| 149 | 145 |
| 150 assert(!node.mounted); | 146 assert(!node.mounted); |
| 151 node.setParent(this); | 147 node.setParent(this); |
| 152 node._sync(oldNode, slot); | 148 node._sync(oldNode, slot); |
| 153 assert(node.root is RenderObject); | 149 assert(node.root is RenderObject); |
| 154 return node; | 150 return node; |
| 155 } | 151 } |
| 156 } | 152 } |
| 157 | 153 |
| 154 |
| 158 // Descendants of TagNode provide a way to tag RenderObjectWrapper and | 155 // Descendants of TagNode provide a way to tag RenderObjectWrapper and |
| 159 // Component nodes with annotations, such as event listeners, | 156 // Component nodes with annotations, such as event listeners, |
| 160 // stylistic information, etc. | 157 // stylistic information, etc. |
| 161 abstract class TagNode extends UINode { | 158 abstract class TagNode extends UINode { |
| 162 | 159 |
| 163 TagNode(UINode content, { Object key }) : this.content = content, super(key: k
ey); | 160 TagNode(UINode content, { Object key }) : this.content = content, super(key: k
ey); |
| 164 | 161 |
| 165 UINode content; | 162 UINode content; |
| 166 | 163 |
| 167 void _sync(UINode old, dynamic slot) { | 164 void _sync(UINode old, dynamic slot) { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 | 265 |
| 269 void _handleEvent(sky.Event e) { | 266 void _handleEvent(sky.Event e) { |
| 270 sky.EventListener listener = listeners[e.type]; | 267 sky.EventListener listener = listeners[e.type]; |
| 271 if (listener != null) { | 268 if (listener != null) { |
| 272 listener(e); | 269 listener(e); |
| 273 } | 270 } |
| 274 } | 271 } |
| 275 | 272 |
| 276 } | 273 } |
| 277 | 274 |
| 275 |
| 276 abstract class Component extends UINode { |
| 277 |
| 278 Component({ Object key, bool stateful }) |
| 279 : _stateful = stateful != null ? stateful : false, |
| 280 _order = _currentOrder + 1, |
| 281 super(key: key); |
| 282 |
| 283 Component.fromArgs(Object key, bool stateful) |
| 284 : this(key: key, stateful: stateful); |
| 285 |
| 286 static Component _currentlyBuilding; |
| 287 bool get _isBuilding => _currentlyBuilding == this; |
| 288 |
| 289 bool _stateful; |
| 290 bool _dirty = true; |
| 291 bool _disqualifiedFromEverAppearingAgain = false; |
| 292 |
| 293 UINode _built; |
| 294 dynamic _slot; // cached slot from the last time we were synced |
| 295 |
| 296 void didMount() { |
| 297 assert(!_disqualifiedFromEverAppearingAgain); |
| 298 super.didMount(); |
| 299 } |
| 300 |
| 301 void remove() { |
| 302 assert(_built != null); |
| 303 assert(root != null); |
| 304 removeChild(_built); |
| 305 _built = null; |
| 306 super.remove(); |
| 307 } |
| 308 |
| 309 bool _retainStatefulNodeIfPossible(UINode old) { |
| 310 assert(!_disqualifiedFromEverAppearingAgain); |
| 311 |
| 312 Component oldComponent = old as Component; |
| 313 if (oldComponent == null || !oldComponent._stateful) |
| 314 return false; |
| 315 |
| 316 assert(key == oldComponent.key); |
| 317 |
| 318 // Make |this|, the newly-created object, into the "old" Component, and kill
it |
| 319 _stateful = false; |
| 320 _built = oldComponent._built; |
| 321 assert(_built != null); |
| 322 _disqualifiedFromEverAppearingAgain = true; |
| 323 |
| 324 // Make |oldComponent| the "new" component |
| 325 oldComponent._built = null; |
| 326 oldComponent._dirty = true; |
| 327 oldComponent.syncFields(this); |
| 328 return true; |
| 329 } |
| 330 |
| 331 // This is called by _retainStatefulNodeIfPossible(), during |
| 332 // syncChild(), just before _sync() is called. |
| 333 // This must be implemented on any subclass that can become stateful |
| 334 // (but don't call super.syncFields() if you inherit directly from |
| 335 // Component, since that'll fire an assert). |
| 336 // If you don't ever become stateful, then don't override this. |
| 337 void syncFields(Component source) { |
| 338 assert(false); |
| 339 } |
| 340 |
| 341 final int _order; |
| 342 static int _currentOrder = 0; |
| 343 |
| 344 /* There are three cases here: |
| 345 * 1) Building for the first time: |
| 346 * assert(_built == null && old == null) |
| 347 * 2) Re-building (because a dirty flag got set): |
| 348 * assert(_built != null && old == null) |
| 349 * 3) Syncing against an old version |
| 350 * assert(_built == null && old != null) |
| 351 */ |
| 352 void _sync(UINode old, dynamic slot) { |
| 353 assert(_built == null || old == null); |
| 354 assert(!_disqualifiedFromEverAppearingAgain); |
| 355 |
| 356 Component oldComponent = old as Component; |
| 357 |
| 358 _slot = slot; |
| 359 |
| 360 var oldBuilt; |
| 361 if (oldComponent == null) { |
| 362 oldBuilt = _built; |
| 363 } else { |
| 364 assert(_built == null); |
| 365 oldBuilt = oldComponent._built; |
| 366 } |
| 367 |
| 368 int lastOrder = _currentOrder; |
| 369 _currentOrder = _order; |
| 370 _currentlyBuilding = this; |
| 371 _built = build(); |
| 372 assert(_built != null); |
| 373 _currentlyBuilding = null; |
| 374 _currentOrder = lastOrder; |
| 375 |
| 376 _built = syncChild(_built, oldBuilt, slot); |
| 377 assert(_built != null); |
| 378 _dirty = false; |
| 379 _root = _built.root; |
| 380 assert(_root == root); // in case a subclass reintroduces it |
| 381 assert(root != null); |
| 382 } |
| 383 |
| 384 void _buildIfDirty() { |
| 385 assert(!_disqualifiedFromEverAppearingAgain); |
| 386 if (!_dirty || !_mounted) |
| 387 return; |
| 388 |
| 389 assert(root != null); |
| 390 _sync(null, _slot); |
| 391 } |
| 392 |
| 393 void scheduleBuild() { |
| 394 setState(() {}); |
| 395 } |
| 396 |
| 397 void setState(Function fn()) { |
| 398 assert(!_disqualifiedFromEverAppearingAgain); |
| 399 _stateful = true; |
| 400 fn(); |
| 401 if (_isBuilding || _dirty || !_mounted) |
| 402 return; |
| 403 |
| 404 _dirty = true; |
| 405 _scheduleComponentForRender(this); |
| 406 } |
| 407 |
| 408 UINode build(); |
| 409 |
| 410 } |
| 411 |
| 412 Set<Component> _dirtyComponents = new Set<Component>(); |
| 413 bool _buildScheduled = false; |
| 414 bool _inRenderDirtyComponents = false; |
| 415 |
| 416 void _buildDirtyComponents() { |
| 417 //_tracing.begin('fn::_buildDirtyComponents'); |
| 418 |
| 419 Stopwatch sw; |
| 420 if (_shouldLogRenderDuration) |
| 421 sw = new Stopwatch()..start(); |
| 422 |
| 423 try { |
| 424 _inRenderDirtyComponents = true; |
| 425 |
| 426 List<Component> sortedDirtyComponents = _dirtyComponents.toList(); |
| 427 sortedDirtyComponents.sort((Component a, Component b) => a._order - b._order
); |
| 428 for (var comp in sortedDirtyComponents) { |
| 429 comp._buildIfDirty(); |
| 430 } |
| 431 |
| 432 _dirtyComponents.clear(); |
| 433 _buildScheduled = false; |
| 434 } finally { |
| 435 _inRenderDirtyComponents = false; |
| 436 } |
| 437 |
| 438 UINode._notifyMountStatusChanged(); |
| 439 |
| 440 if (_shouldLogRenderDuration) { |
| 441 sw.stop(); |
| 442 print('Render took ${sw.elapsedMicroseconds} microseconds'); |
| 443 } |
| 444 |
| 445 //_tracing.end('fn::_buildDirtyComponents'); |
| 446 } |
| 447 |
| 448 void _scheduleComponentForRender(Component c) { |
| 449 assert(!_inRenderDirtyComponents); |
| 450 _dirtyComponents.add(c); |
| 451 |
| 452 if (!_buildScheduled) { |
| 453 _buildScheduled = true; |
| 454 new Future.microtask(_buildDirtyComponents); |
| 455 } |
| 456 } |
| 457 |
| 458 |
| 278 /* | 459 /* |
| 279 * RenderObjectWrappers correspond to a desired state of a RenderObject. | 460 * RenderObjectWrappers correspond to a desired state of a RenderObject. |
| 280 * They are fully immutable, with one exception: A UINode which is a | 461 * They are fully immutable, with one exception: A UINode which is a |
| 281 * Component which lives within an MultiChildRenderObjectWrapper's | 462 * Component which lives within an MultiChildRenderObjectWrapper's |
| 282 * children list, may be replaced with the "old" instance if it has | 463 * children list, may be replaced with the "old" instance if it has |
| 283 * become stateful. | 464 * become stateful. |
| 284 */ | 465 */ |
| 285 abstract class RenderObjectWrapper extends UINode { | 466 abstract class RenderObjectWrapper extends UINode { |
| 286 | 467 |
| 287 RenderObjectWrapper({ | 468 RenderObjectWrapper({ |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 } | 552 } |
| 372 | 553 |
| 373 void remove() { | 554 void remove() { |
| 374 if (child != null) | 555 if (child != null) |
| 375 removeChild(child); | 556 removeChild(child); |
| 376 super.remove(); | 557 super.remove(); |
| 377 } | 558 } |
| 378 | 559 |
| 379 } | 560 } |
| 380 | 561 |
| 381 class Opacity extends OneChildRenderObjectWrapper { | |
| 382 Opacity({ this.opacity, UINode child, Object key }) | |
| 383 : super(child: child, key: key); | |
| 384 | |
| 385 RenderOpacity get root { RenderOpacity result = super.root; return result; } | |
| 386 final double opacity; | |
| 387 | |
| 388 RenderOpacity createNode() => new RenderOpacity(opacity: opacity); | |
| 389 | |
| 390 void syncRenderObject(Opacity old) { | |
| 391 super.syncRenderObject(old); | |
| 392 root.opacity = opacity; | |
| 393 } | |
| 394 } | |
| 395 | |
| 396 class ClipRect extends OneChildRenderObjectWrapper { | |
| 397 | |
| 398 ClipRect({ UINode child, Object key }) | |
| 399 : super(child: child, key: key); | |
| 400 | |
| 401 RenderClipRect get root { RenderClipRect result = super.root; return result; } | |
| 402 RenderClipRect createNode() => new RenderClipRect(); | |
| 403 } | |
| 404 | |
| 405 class ClipOval extends OneChildRenderObjectWrapper { | |
| 406 | |
| 407 ClipOval({ UINode child, Object key }) | |
| 408 : super(child: child, key: key); | |
| 409 | |
| 410 RenderClipOval get root { RenderClipOval result = super.root; return result; } | |
| 411 RenderClipOval createNode() => new RenderClipOval(); | |
| 412 } | |
| 413 | |
| 414 class Padding extends OneChildRenderObjectWrapper { | |
| 415 | |
| 416 Padding({ this.padding, UINode child, Object key }) | |
| 417 : super(child: child, key: key); | |
| 418 | |
| 419 RenderPadding get root { RenderPadding result = super.root; return result; } | |
| 420 final EdgeDims padding; | |
| 421 | |
| 422 RenderPadding createNode() => new RenderPadding(padding: padding); | |
| 423 | |
| 424 void syncRenderObject(Padding old) { | |
| 425 super.syncRenderObject(old); | |
| 426 root.padding = padding; | |
| 427 } | |
| 428 | |
| 429 } | |
| 430 | |
| 431 class DecoratedBox extends OneChildRenderObjectWrapper { | |
| 432 | |
| 433 DecoratedBox({ this.decoration, UINode child, Object key }) | |
| 434 : super(child: child, key: key); | |
| 435 | |
| 436 RenderDecoratedBox get root { RenderDecoratedBox result = super.root; return r
esult; } | |
| 437 final BoxDecoration decoration; | |
| 438 | |
| 439 RenderDecoratedBox createNode() => new RenderDecoratedBox(decoration: decorati
on); | |
| 440 | |
| 441 void syncRenderObject(DecoratedBox old) { | |
| 442 super.syncRenderObject(old); | |
| 443 root.decoration = decoration; | |
| 444 } | |
| 445 | |
| 446 } | |
| 447 | |
| 448 class SizedBox extends OneChildRenderObjectWrapper { | |
| 449 | |
| 450 SizedBox({ | |
| 451 double width: double.INFINITY, | |
| 452 double height: double.INFINITY, | |
| 453 UINode child, | |
| 454 Object key | |
| 455 }) : desiredSize = new Size(width, height), super(child: child, key: key); | |
| 456 | |
| 457 RenderSizedBox get root { RenderSizedBox result = super.root; return result; } | |
| 458 final Size desiredSize; | |
| 459 | |
| 460 RenderSizedBox createNode() => new RenderSizedBox(desiredSize: desiredSize); | |
| 461 | |
| 462 void syncRenderObject(SizedBox old) { | |
| 463 super.syncRenderObject(old); | |
| 464 root.desiredSize = desiredSize; | |
| 465 } | |
| 466 | |
| 467 } | |
| 468 | |
| 469 class ConstrainedBox extends OneChildRenderObjectWrapper { | |
| 470 | |
| 471 ConstrainedBox({ this.constraints, UINode child, Object key }) | |
| 472 : super(child: child, key: key); | |
| 473 | |
| 474 RenderConstrainedBox get root { RenderConstrainedBox result = super.root; retu
rn result; } | |
| 475 final BoxConstraints constraints; | |
| 476 | |
| 477 RenderConstrainedBox createNode() => new RenderConstrainedBox(additionalConstr
aints: constraints); | |
| 478 | |
| 479 void syncRenderObject(ConstrainedBox old) { | |
| 480 super.syncRenderObject(old); | |
| 481 root.additionalConstraints = constraints; | |
| 482 } | |
| 483 | |
| 484 } | |
| 485 | |
| 486 class ShrinkWrapWidth extends OneChildRenderObjectWrapper { | |
| 487 | |
| 488 ShrinkWrapWidth({ UINode child, Object key }) : super(child: child, key: key); | |
| 489 | |
| 490 RenderShrinkWrapWidth get root { RenderShrinkWrapWidth result = super.root; re
turn result; } | |
| 491 | |
| 492 RenderShrinkWrapWidth createNode() => new RenderShrinkWrapWidth(); | |
| 493 | |
| 494 } | |
| 495 | |
| 496 class Transform extends OneChildRenderObjectWrapper { | |
| 497 | |
| 498 Transform({ this.transform, UINode child, Object key }) | |
| 499 : super(child: child, key: key); | |
| 500 | |
| 501 RenderTransform get root { RenderTransform result = super.root; return result;
} | |
| 502 final Matrix4 transform; | |
| 503 | |
| 504 RenderTransform createNode() => new RenderTransform(transform: transform); | |
| 505 | |
| 506 void syncRenderObject(Transform old) { | |
| 507 super.syncRenderObject(old); | |
| 508 root.transform = transform; | |
| 509 } | |
| 510 | |
| 511 } | |
| 512 | |
| 513 class SizeObserver extends OneChildRenderObjectWrapper { | |
| 514 | |
| 515 SizeObserver({ this.callback, UINode child, Object key }) | |
| 516 : super(child: child, key: key); | |
| 517 | |
| 518 RenderSizeObserver get root { RenderSizeObserver result = super.root; return r
esult; } | |
| 519 final SizeChangedCallback callback; | |
| 520 | |
| 521 RenderSizeObserver createNode() => new RenderSizeObserver(callback: callback); | |
| 522 | |
| 523 void syncRenderObject(SizeObserver old) { | |
| 524 super.syncRenderObject(old); | |
| 525 root.callback = callback; | |
| 526 } | |
| 527 | |
| 528 void remove() { | |
| 529 root.callback = null; | |
| 530 super.remove(); | |
| 531 } | |
| 532 | |
| 533 } | |
| 534 | |
| 535 // TODO(jackson) need a mechanism for marking the RenderCustomPaint as needing p
aint | |
| 536 class CustomPaint extends OneChildRenderObjectWrapper { | |
| 537 | |
| 538 CustomPaint({ this.callback, UINode child, Object key }) | |
| 539 : super(child: child, key: key); | |
| 540 | |
| 541 RenderCustomPaint get root { RenderCustomPaint result = super.root; return res
ult; } | |
| 542 final CustomPaintCallback callback; | |
| 543 | |
| 544 RenderCustomPaint createNode() => new RenderCustomPaint(callback: callback); | |
| 545 | |
| 546 void syncRenderObject(CustomPaint old) { | |
| 547 super.syncRenderObject(old); | |
| 548 root.callback = callback; | |
| 549 } | |
| 550 | |
| 551 void remove() { | |
| 552 root.callback = null; | |
| 553 super.remove(); | |
| 554 } | |
| 555 | |
| 556 } | |
| 557 | |
| 558 abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { | 562 abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
| 559 | 563 |
| 560 // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes | 564 // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes |
| 561 // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() c
alls | 565 // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() c
alls |
| 562 | 566 |
| 563 MultiChildRenderObjectWrapper({ | 567 MultiChildRenderObjectWrapper({ |
| 564 Object key, | 568 Object key, |
| 565 List<UINode> children | 569 List<UINode> children |
| 566 }) : this.children = children == null ? const [] : children, | 570 }) : this.children = children == null ? const [] : children, |
| 567 super(key: key) { | 571 super(key: key) { |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 733 oldNode = oldChildren[oldStartIndex]; | 737 oldNode = oldChildren[oldStartIndex]; |
| 734 removeChild(oldNode); | 738 removeChild(oldNode); |
| 735 advanceOldStartIndex(); | 739 advanceOldStartIndex(); |
| 736 } | 740 } |
| 737 | 741 |
| 738 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 742 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
| 739 } | 743 } |
| 740 | 744 |
| 741 } | 745 } |
| 742 | 746 |
| 743 class Block extends MultiChildRenderObjectWrapper { | |
| 744 | |
| 745 Block(List<UINode> children, { Object key }) | |
| 746 : super(key: key, children: children); | |
| 747 | |
| 748 RenderBlock get root { RenderBlock result = super.root; return result; } | |
| 749 RenderBlock createNode() => new RenderBlock(); | |
| 750 | |
| 751 } | |
| 752 | |
| 753 class Stack extends MultiChildRenderObjectWrapper { | |
| 754 | |
| 755 Stack(List<UINode> children, { Object key }) | |
| 756 : super(key: key, children: children); | |
| 757 | |
| 758 RenderStack get root { RenderStack result = super.root; return result; } | |
| 759 RenderStack createNode() => new RenderStack(); | |
| 760 | |
| 761 } | |
| 762 | |
| 763 class StackPositionedChild extends ParentDataNode { | |
| 764 StackPositionedChild(UINode content, { | |
| 765 double top, double right, double bottom, double left | |
| 766 }) : super(content, new StackParentData()..top = top | |
| 767 ..right = right | |
| 768 ..bottom = bottom | |
| 769 ..left = left); | |
| 770 } | |
| 771 | |
| 772 class Paragraph extends RenderObjectWrapper { | |
| 773 | |
| 774 Paragraph({ Object key, this.text }) : super(key: key); | |
| 775 | |
| 776 RenderParagraph get root { RenderParagraph result = super.root; return result;
} | |
| 777 RenderParagraph createNode() => new RenderParagraph(text: text); | |
| 778 | |
| 779 final String text; | |
| 780 | |
| 781 void syncRenderObject(UINode old) { | |
| 782 super.syncRenderObject(old); | |
| 783 root.text = text; | |
| 784 } | |
| 785 | |
| 786 void insert(RenderObjectWrapper child, dynamic slot) { | |
| 787 assert(false); | |
| 788 // Paragraph does not support having children currently | |
| 789 } | |
| 790 | |
| 791 } | |
| 792 | |
| 793 class Text extends Component { | |
| 794 Text(this.data) : super(key: '*text*'); | |
| 795 final String data; | |
| 796 bool get interchangeable => true; | |
| 797 UINode build() => new Paragraph(text: data); | |
| 798 } | |
| 799 | |
| 800 class Flex extends MultiChildRenderObjectWrapper { | |
| 801 | |
| 802 Flex(List<UINode> children, { | |
| 803 Object key, | |
| 804 this.direction: FlexDirection.horizontal, | |
| 805 this.justifyContent: FlexJustifyContent.flexStart, | |
| 806 this.alignItems: FlexAlignItems.center | |
| 807 }) : super(key: key, children: children); | |
| 808 | |
| 809 RenderFlex get root { RenderFlex result = super.root; return result; } | |
| 810 RenderFlex createNode() => new RenderFlex(direction: this.direction); | |
| 811 | |
| 812 final FlexDirection direction; | |
| 813 final FlexJustifyContent justifyContent; | |
| 814 final FlexAlignItems alignItems; | |
| 815 | |
| 816 void syncRenderObject(UINode old) { | |
| 817 super.syncRenderObject(old); | |
| 818 root.direction = direction; | |
| 819 root.justifyContent = justifyContent; | |
| 820 root.alignItems = alignItems; | |
| 821 } | |
| 822 | |
| 823 } | |
| 824 | |
| 825 class FlexExpandingChild extends ParentDataNode { | |
| 826 FlexExpandingChild(UINode content, { int flex: 1, Object key }) | |
| 827 : super(content, new FlexBoxParentData()..flex = flex, key: key); | |
| 828 } | |
| 829 | |
| 830 class Image extends RenderObjectWrapper { | |
| 831 | |
| 832 Image({ | |
| 833 Object key, | |
| 834 this.src, | |
| 835 this.size | |
| 836 }) : super(key: key); | |
| 837 | |
| 838 RenderImage get root { RenderImage result = super.root; return result; } | |
| 839 RenderImage createNode() => new RenderImage(this.src, this.size); | |
| 840 | |
| 841 final String src; | |
| 842 final Size size; | |
| 843 | |
| 844 void syncRenderObject(UINode old) { | |
| 845 super.syncRenderObject(old); | |
| 846 root.src = src; | |
| 847 root.requestedSize = size; | |
| 848 } | |
| 849 | |
| 850 void insert(RenderObjectWrapper child, dynamic slot) { | |
| 851 assert(false); | |
| 852 // Image does not support having children currently | |
| 853 } | |
| 854 | |
| 855 } | |
| 856 | |
| 857 Set<Component> _dirtyComponents = new Set<Component>(); | |
| 858 bool _buildScheduled = false; | |
| 859 bool _inRenderDirtyComponents = false; | |
| 860 | |
| 861 void _buildDirtyComponents() { | |
| 862 //_tracing.begin('fn::_buildDirtyComponents'); | |
| 863 | |
| 864 Stopwatch sw; | |
| 865 if (_shouldLogRenderDuration) | |
| 866 sw = new Stopwatch()..start(); | |
| 867 | |
| 868 try { | |
| 869 _inRenderDirtyComponents = true; | |
| 870 | |
| 871 List<Component> sortedDirtyComponents = _dirtyComponents.toList(); | |
| 872 sortedDirtyComponents.sort((Component a, Component b) => a._order - b._order
); | |
| 873 for (var comp in sortedDirtyComponents) { | |
| 874 comp._buildIfDirty(); | |
| 875 } | |
| 876 | |
| 877 _dirtyComponents.clear(); | |
| 878 _buildScheduled = false; | |
| 879 } finally { | |
| 880 _inRenderDirtyComponents = false; | |
| 881 } | |
| 882 | |
| 883 UINode._notifyMountStatusChanged(); | |
| 884 | |
| 885 if (_shouldLogRenderDuration) { | |
| 886 sw.stop(); | |
| 887 print('Render took ${sw.elapsedMicroseconds} microseconds'); | |
| 888 } | |
| 889 | |
| 890 //_tracing.end('fn::_buildDirtyComponents'); | |
| 891 } | |
| 892 | |
| 893 void _scheduleComponentForRender(Component c) { | |
| 894 assert(!_inRenderDirtyComponents); | |
| 895 _dirtyComponents.add(c); | |
| 896 | |
| 897 if (!_buildScheduled) { | |
| 898 _buildScheduled = true; | |
| 899 new Future.microtask(_buildDirtyComponents); | |
| 900 } | |
| 901 } | |
| 902 | |
| 903 abstract class Component extends UINode { | |
| 904 | |
| 905 Component({ Object key, bool stateful }) | |
| 906 : _stateful = stateful != null ? stateful : false, | |
| 907 _order = _currentOrder + 1, | |
| 908 super(key: key); | |
| 909 | |
| 910 Component.fromArgs(Object key, bool stateful) | |
| 911 : this(key: key, stateful: stateful); | |
| 912 | |
| 913 static Component _currentlyBuilding; | |
| 914 bool get _isBuilding => _currentlyBuilding == this; | |
| 915 | |
| 916 bool _stateful; | |
| 917 bool _dirty = true; | |
| 918 bool _disqualifiedFromEverAppearingAgain = false; | |
| 919 | |
| 920 UINode _built; | |
| 921 dynamic _slot; // cached slot from the last time we were synced | |
| 922 | |
| 923 void didMount() { | |
| 924 assert(!_disqualifiedFromEverAppearingAgain); | |
| 925 super.didMount(); | |
| 926 } | |
| 927 | |
| 928 void remove() { | |
| 929 assert(_built != null); | |
| 930 assert(root != null); | |
| 931 removeChild(_built); | |
| 932 _built = null; | |
| 933 super.remove(); | |
| 934 } | |
| 935 | |
| 936 bool _retainStatefulNodeIfPossible(UINode old) { | |
| 937 assert(!_disqualifiedFromEverAppearingAgain); | |
| 938 | |
| 939 Component oldComponent = old as Component; | |
| 940 if (oldComponent == null || !oldComponent._stateful) | |
| 941 return false; | |
| 942 | |
| 943 assert(key == oldComponent.key); | |
| 944 | |
| 945 // Make |this|, the newly-created object, into the "old" Component, and kill
it | |
| 946 _stateful = false; | |
| 947 _built = oldComponent._built; | |
| 948 assert(_built != null); | |
| 949 _disqualifiedFromEverAppearingAgain = true; | |
| 950 | |
| 951 // Make |oldComponent| the "new" component | |
| 952 oldComponent._built = null; | |
| 953 oldComponent._dirty = true; | |
| 954 oldComponent.syncFields(this); | |
| 955 return true; | |
| 956 } | |
| 957 | |
| 958 // This is called by _retainStatefulNodeIfPossible(), during | |
| 959 // syncChild(), just before _sync() is called. | |
| 960 // This must be implemented on any subclass that can become stateful | |
| 961 // (but don't call super.syncFields() if you inherit directly from | |
| 962 // Component, since that'll fire an assert). | |
| 963 // If you don't ever become stateful, then don't override this. | |
| 964 void syncFields(Component source) { | |
| 965 assert(false); | |
| 966 } | |
| 967 | |
| 968 final int _order; | |
| 969 static int _currentOrder = 0; | |
| 970 | |
| 971 /* There are three cases here: | |
| 972 * 1) Building for the first time: | |
| 973 * assert(_built == null && old == null) | |
| 974 * 2) Re-building (because a dirty flag got set): | |
| 975 * assert(_built != null && old == null) | |
| 976 * 3) Syncing against an old version | |
| 977 * assert(_built == null && old != null) | |
| 978 */ | |
| 979 void _sync(UINode old, dynamic slot) { | |
| 980 assert(_built == null || old == null); | |
| 981 assert(!_disqualifiedFromEverAppearingAgain); | |
| 982 | |
| 983 Component oldComponent = old as Component; | |
| 984 | |
| 985 _slot = slot; | |
| 986 | |
| 987 var oldBuilt; | |
| 988 if (oldComponent == null) { | |
| 989 oldBuilt = _built; | |
| 990 } else { | |
| 991 assert(_built == null); | |
| 992 oldBuilt = oldComponent._built; | |
| 993 } | |
| 994 | |
| 995 int lastOrder = _currentOrder; | |
| 996 _currentOrder = _order; | |
| 997 _currentlyBuilding = this; | |
| 998 _built = build(); | |
| 999 assert(_built != null); | |
| 1000 _currentlyBuilding = null; | |
| 1001 _currentOrder = lastOrder; | |
| 1002 | |
| 1003 _built = syncChild(_built, oldBuilt, slot); | |
| 1004 assert(_built != null); | |
| 1005 _dirty = false; | |
| 1006 _root = _built.root; | |
| 1007 assert(_root == root); // in case a subclass reintroduces it | |
| 1008 assert(root != null); | |
| 1009 } | |
| 1010 | |
| 1011 void _buildIfDirty() { | |
| 1012 assert(!_disqualifiedFromEverAppearingAgain); | |
| 1013 if (!_dirty || !_mounted) | |
| 1014 return; | |
| 1015 | |
| 1016 assert(root != null); | |
| 1017 _sync(null, _slot); | |
| 1018 } | |
| 1019 | |
| 1020 void scheduleBuild() { | |
| 1021 setState(() {}); | |
| 1022 } | |
| 1023 | |
| 1024 void setState(Function fn()) { | |
| 1025 assert(!_disqualifiedFromEverAppearingAgain); | |
| 1026 _stateful = true; | |
| 1027 fn(); | |
| 1028 if (_isBuilding || _dirty || !_mounted) | |
| 1029 return; | |
| 1030 | |
| 1031 _dirty = true; | |
| 1032 _scheduleComponentForRender(this); | |
| 1033 } | |
| 1034 | |
| 1035 UINode build(); | |
| 1036 | |
| 1037 } | |
| 1038 | |
| 1039 class Container extends Component { | |
| 1040 | |
| 1041 Container({ | |
| 1042 Object key, | |
| 1043 this.child, | |
| 1044 this.constraints, | |
| 1045 this.decoration, | |
| 1046 this.width, | |
| 1047 this.height, | |
| 1048 this.margin, | |
| 1049 this.padding, | |
| 1050 this.transform | |
| 1051 }) : super(key: key); | |
| 1052 | |
| 1053 final UINode child; | |
| 1054 final BoxConstraints constraints; | |
| 1055 final BoxDecoration decoration; | |
| 1056 final EdgeDims margin; | |
| 1057 final EdgeDims padding; | |
| 1058 final Matrix4 transform; | |
| 1059 final double width; | |
| 1060 final double height; | |
| 1061 | |
| 1062 UINode build() { | |
| 1063 UINode current = child; | |
| 1064 | |
| 1065 if (child == null && width == null && height == null) | |
| 1066 current = new SizedBox(); | |
| 1067 | |
| 1068 if (padding != null) | |
| 1069 current = new Padding(padding: padding, child: current); | |
| 1070 | |
| 1071 if (decoration != null) | |
| 1072 current = new DecoratedBox(decoration: decoration, child: current); | |
| 1073 | |
| 1074 if (width != null || height != null) | |
| 1075 current = new SizedBox( | |
| 1076 width: width == null ? double.INFINITY : width, | |
| 1077 height: height == null ? double.INFINITY : height, | |
| 1078 child: current | |
| 1079 ); | |
| 1080 | |
| 1081 if (constraints != null) | |
| 1082 current = new ConstrainedBox(constraints: constraints, child: current); | |
| 1083 | |
| 1084 if (margin != null) | |
| 1085 current = new Padding(padding: margin, child: current); | |
| 1086 | |
| 1087 if (transform != null) | |
| 1088 current = new Transform(transform: transform, child: current); | |
| 1089 | |
| 1090 return current; | |
| 1091 } | |
| 1092 | |
| 1093 } | |
| 1094 | 747 |
| 1095 class UINodeAppView extends AppView { | 748 class UINodeAppView extends AppView { |
| 1096 | 749 |
| 1097 UINodeAppView() { | 750 UINodeAppView() { |
| 1098 assert(_appView == null); | 751 assert(_appView == null); |
| 1099 } | 752 } |
| 1100 | 753 |
| 1101 static UINodeAppView _appView; | 754 static UINodeAppView _appView; |
| 1102 static void initUINodeAppView() { | 755 static void initUINodeAppView() { |
| 1103 if (_appView == null) | 756 if (_appView == null) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1157 // we haven't attached it yet | 810 // we haven't attached it yet |
| 1158 UINodeAppView._appView.root = root; | 811 UINodeAppView._appView.root = root; |
| 1159 } | 812 } |
| 1160 assert(root.parent is RenderView); | 813 assert(root.parent is RenderView); |
| 1161 } | 814 } |
| 1162 | 815 |
| 1163 } | 816 } |
| 1164 | 817 |
| 1165 typedef UINode Builder(); | 818 typedef UINode Builder(); |
| 1166 | 819 |
| 1167 class RenderNodeToUINodeAdapter extends AbstractUINodeRoot { | 820 class RenderObjectToUINodeAdapter extends AbstractUINodeRoot { |
| 1168 | 821 |
| 1169 RenderNodeToUINodeAdapter( | 822 RenderObjectToUINodeAdapter( |
| 1170 RenderObjectWithChildMixin<RenderBox> container, | 823 RenderObjectWithChildMixin<RenderBox> container, |
| 1171 this.builder | 824 this.builder |
| 1172 ) : _container = container { | 825 ) : _container = container { |
| 1173 assert(builder != null); | 826 assert(builder != null); |
| 1174 } | 827 } |
| 1175 | 828 |
| 1176 RenderObjectWithChildMixin<RenderBox> _container; | 829 RenderObjectWithChildMixin<RenderBox> _container; |
| 1177 RenderObjectWithChildMixin<RenderBox> get container => _container; | 830 RenderObjectWithChildMixin<RenderBox> get container => _container; |
| 1178 void set container(RenderObjectWithChildMixin<RenderBox> value) { | 831 void set container(RenderObjectWithChildMixin<RenderBox> value) { |
| 1179 if (_container != value) { | 832 if (_container != value) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1198 // we haven't attached it yet | 851 // we haven't attached it yet |
| 1199 assert(_container.child == null); | 852 assert(_container.child == null); |
| 1200 _container.child = root; | 853 _container.child = root; |
| 1201 } | 854 } |
| 1202 assert(root.parent == _container); | 855 assert(root.parent == _container); |
| 1203 } | 856 } |
| 1204 | 857 |
| 1205 UINode build() => builder(); | 858 UINode build() => builder(); |
| 1206 | 859 |
| 1207 } | 860 } |
| OLD | NEW |