Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: sky/sdk/lib/framework/fn2.dart

Issue 1177243002: Refactor fn2.dart, since it breached our 1000-line threshold. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/sdk/lib/framework/fn.md ('k') | sky/sdk/lib/framework/rendering/box.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 library fn;
6
7 import 'app.dart';
8 import 'dart:async';
9 import 'dart:collection';
10 import 'dart:mirrors';
11 import 'dart:sky' as sky;
12 import 'package:vector_math/vector_math.dart';
13 import 'rendering/block.dart';
14 import 'rendering/box.dart';
15 import 'rendering/flex.dart';
16 import 'rendering/object.dart';
17 import 'rendering/paragraph.dart';
18 import 'rendering/stack.dart';
19 export 'rendering/object.dart' show Point, Size, Rect, Color, Paint, Path;
20 export 'rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSi de, EdgeDims;
21 export 'rendering/flex.dart' show FlexDirection;
22
23 // final sky.Tracing _tracing = sky.window.tracing;
24
25 final bool _shouldLogRenderDuration = false;
26
27 /*
28 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and
29 * can be sync'd.
30 */
31 abstract class UINode {
32
33 UINode({ Object key }) {
34 _key = key == null ? "$runtimeType" : "$runtimeType-$key";
35 assert(this is App || _inRenderDirtyComponents); // you should not build the UI tree ahead of time, build it only during build()
36 }
37
38 String _key;
39 String get key => _key;
40
41 UINode _parent;
42 UINode get parent => _parent;
43
44 bool _mounted = false;
45 bool _wasMounted = false;
46 bool get mounted => _mounted;
47 static bool _notifyingMountStatus = false;
48 static Set<UINode> _mountedChanged = new HashSet<UINode>();
49
50 void setParent(UINode newParent) {
51 assert(!_notifyingMountStatus);
52 _parent = newParent;
53 if (newParent == null) {
54 if (_mounted) {
55 _mounted = false;
56 _mountedChanged.add(this);
57 }
58 } else {
59 assert(newParent._mounted);
60 if (_parent._mounted != _mounted) {
61 _mounted = _parent._mounted;
62 _mountedChanged.add(this);
63 }
64 }
65 }
66
67 static void _notifyMountStatusChanged() {
68 try {
69 _notifyingMountStatus = true;
70 for (UINode node in _mountedChanged) {
71 if (node._wasMounted != node._mounted) {
72 if (node._mounted)
73 node.didMount();
74 else
75 node.didUnmount();
76 node._wasMounted = node._mounted;
77 }
78 }
79 _mountedChanged.clear();
80 } finally {
81 _notifyingMountStatus = false;
82 }
83 }
84 void didMount() { }
85 void didUnmount() { }
86
87 RenderObject _root;
88 RenderObject get root => _root;
89
90 // Subclasses which implements Nodes that become stateful may return true
91 // if the |old| node has become stateful and should be retained.
92 // This is called immediately before _sync().
93 // Component._retainStatefulNodeIfPossible() calls syncFields().
94 bool _retainStatefulNodeIfPossible(UINode old) => false;
95
96 bool get interchangeable => false; // if true, then keys can be duplicated
97
98 void _sync(UINode old, dynamic slot);
99 // 'slot' is the identifier that the parent RenderObjectWrapper uses to know
100 // where to put this descendant
101
102 void remove() {
103 _root = null;
104 setParent(null);
105 }
106
107 UINode findAncestor(Type targetType) {
108 var ancestor = _parent;
109 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r eflectClass(targetType)))
110 ancestor = ancestor._parent;
111 return ancestor;
112 }
113
114 void removeChild(UINode node) {
115 node.remove();
116 }
117
118 // Returns the child which should be retained as the child of this node.
119 UINode syncChild(UINode node, UINode oldNode, dynamic slot) {
120
121 assert(oldNode is! Component || !oldNode._disqualifiedFromEverAppearingAgain );
122
123 if (node == oldNode) {
124 assert(node == null || node.mounted);
125 return node; // Nothing to do. Subtrees must be identical.
126 }
127
128 if (node == null) {
129 // the child in this slot has gone away
130 assert(oldNode.mounted);
131 removeChild(oldNode);
132 assert(!oldNode.mounted);
133 return null;
134 }
135
136 if (oldNode != null && node._key == oldNode._key && node._retainStatefulNode IfPossible(oldNode)) {
137 assert(oldNode.mounted);
138 assert(!node.mounted);
139 oldNode._sync(node, slot);
140 assert(oldNode.root is RenderObject);
141 return oldNode;
142 }
143
144 if (oldNode != null && node._key != oldNode._key) {
145 assert(oldNode.mounted);
146 removeChild(oldNode);
147 oldNode = null;
148 }
149
150 assert(!node.mounted);
151 node.setParent(this);
152 node._sync(oldNode, slot);
153 assert(node.root is RenderObject);
154 return node;
155 }
156 }
157
158 // Descendants of TagNode provide a way to tag RenderObjectWrapper and
159 // Component nodes with annotations, such as event listeners,
160 // stylistic information, etc.
161 abstract class TagNode extends UINode {
162
163 TagNode(UINode content, { Object key }) : this.content = content, super(key: k ey);
164
165 UINode content;
166
167 void _sync(UINode old, dynamic slot) {
168 UINode oldContent = old == null ? null : (old as TagNode).content;
169 content = syncChild(content, oldContent, slot);
170 assert(content.root != null);
171 _root = content.root;
172 assert(_root == root); // in case a subclass reintroduces it
173 }
174
175 void remove() {
176 if (content != null)
177 removeChild(content);
178 super.remove();
179 }
180
181 }
182
183 class ParentDataNode extends TagNode {
184 ParentDataNode(UINode content, this.parentData, { Object key }): super(content , key: key);
185 final ParentData parentData;
186 }
187
188 typedef void GestureEventListener(sky.GestureEvent e);
189 typedef void PointerEventListener(sky.PointerEvent e);
190 typedef void EventListener(sky.Event e);
191
192 class EventListenerNode extends TagNode {
193
194 EventListenerNode(UINode content, {
195 EventListener onWheel,
196 GestureEventListener onGestureFlingCancel,
197 GestureEventListener onGestureFlingStart,
198 GestureEventListener onGestureScrollStart,
199 GestureEventListener onGestureScrollUpdate,
200 GestureEventListener onGestureTap,
201 GestureEventListener onGestureTapDown,
202 PointerEventListener onPointerCancel,
203 PointerEventListener onPointerDown,
204 PointerEventListener onPointerMove,
205 PointerEventListener onPointerUp,
206 Map<String, sky.EventListener> custom
207 }) : listeners = _createListeners(
208 onWheel: onWheel,
209 onGestureFlingCancel: onGestureFlingCancel,
210 onGestureFlingStart: onGestureFlingStart,
211 onGestureScrollUpdate: onGestureScrollUpdate,
212 onGestureScrollStart: onGestureScrollStart,
213 onGestureTap: onGestureTap,
214 onGestureTapDown: onGestureTapDown,
215 onPointerCancel: onPointerCancel,
216 onPointerDown: onPointerDown,
217 onPointerMove: onPointerMove,
218 onPointerUp: onPointerUp,
219 custom: custom
220 ),
221 super(content);
222
223 final Map<String, sky.EventListener> listeners;
224
225 static Map<String, sky.EventListener> _createListeners({
226 EventListener onWheel,
227 GestureEventListener onGestureFlingCancel,
228 GestureEventListener onGestureFlingStart,
229 GestureEventListener onGestureScrollStart,
230 GestureEventListener onGestureScrollUpdate,
231 GestureEventListener onGestureTap,
232 GestureEventListener onGestureTapDown,
233 PointerEventListener onPointerCancel,
234 PointerEventListener onPointerDown,
235 PointerEventListener onPointerMove,
236 PointerEventListener onPointerUp,
237 Map<String, sky.EventListener> custom
238 }) {
239 var listeners = custom != null ?
240 new HashMap<String, sky.EventListener>.from(custom) :
241 new HashMap<String, sky.EventListener>();
242
243 if (onWheel != null)
244 listeners['wheel'] = onWheel;
245 if (onGestureFlingCancel != null)
246 listeners['gestureflingcancel'] = onGestureFlingCancel;
247 if (onGestureFlingStart != null)
248 listeners['gestureflingstart'] = onGestureFlingStart;
249 if (onGestureScrollStart != null)
250 listeners['gesturescrollstart'] = onGestureScrollStart;
251 if (onGestureScrollUpdate != null)
252 listeners['gesturescrollupdate'] = onGestureScrollUpdate;
253 if (onGestureTap != null)
254 listeners['gesturetap'] = onGestureTap;
255 if (onGestureTapDown != null)
256 listeners['gesturetapdown'] = onGestureTapDown;
257 if (onPointerCancel != null)
258 listeners['pointercancel'] = onPointerCancel;
259 if (onPointerDown != null)
260 listeners['pointerdown'] = onPointerDown;
261 if (onPointerMove != null)
262 listeners['pointermove'] = onPointerMove;
263 if (onPointerUp != null)
264 listeners['pointerup'] = onPointerUp;
265
266 return listeners;
267 }
268
269 void _handleEvent(sky.Event e) {
270 sky.EventListener listener = listeners[e.type];
271 if (listener != null) {
272 listener(e);
273 }
274 }
275
276 }
277
278 /*
279 * RenderObjectWrappers correspond to a desired state of a RenderObject.
280 * They are fully immutable, with one exception: A UINode which is a
281 * Component which lives within an MultiChildRenderObjectWrapper's
282 * children list, may be replaced with the "old" instance if it has
283 * become stateful.
284 */
285 abstract class RenderObjectWrapper extends UINode {
286
287 RenderObjectWrapper({
288 Object key
289 }) : super(key: key);
290
291 RenderObject createNode();
292
293 void insert(RenderObjectWrapper child, dynamic slot);
294
295 static final Map<RenderObject, RenderObjectWrapper> _nodeMap =
296 new HashMap<RenderObject, RenderObjectWrapper>();
297
298 static RenderObjectWrapper _getMounted(RenderObject node) => _nodeMap[node];
299
300 void _sync(UINode old, dynamic slot) {
301 assert(parent != null);
302 if (old == null) {
303 _root = createNode();
304 var ancestor = findAncestor(RenderObjectWrapper);
305 if (ancestor is RenderObjectWrapper)
306 ancestor.insert(this, slot);
307 } else {
308 _root = old.root;
309 }
310 assert(_root == root); // in case a subclass reintroduces it
311 assert(root != null);
312 assert(mounted);
313 _nodeMap[root] = this;
314 syncRenderObject(old);
315 }
316
317 void syncRenderObject(RenderObjectWrapper old) {
318 ParentData parentData = null;
319 UINode ancestor = parent;
320 while (ancestor != null && ancestor is! RenderObjectWrapper) {
321 if (ancestor is ParentDataNode && ancestor.parentData != null) {
322 if (parentData != null)
323 parentData.merge(ancestor.parentData); // this will throw if the types aren't the same
324 else
325 parentData = ancestor.parentData;
326 }
327 ancestor = ancestor.parent;
328 }
329 if (parentData != null) {
330 assert(root.parentData != null);
331 root.parentData.merge(parentData); // this will throw if the types aren't appropriate
332 if (parent.root != null)
333 parent.root.markNeedsLayout();
334 }
335 }
336
337 void remove() {
338 assert(root != null);
339 _nodeMap.remove(root);
340 super.remove();
341 }
342 }
343
344 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {
345
346 OneChildRenderObjectWrapper({ UINode child, Object key }) : _child = child, su per(key: key);
347
348 UINode _child;
349 UINode get child => _child;
350
351 void syncRenderObject(RenderObjectWrapper old) {
352 super.syncRenderObject(old);
353 UINode oldChild = old == null ? null : (old as OneChildRenderObjectWrapper). child;
354 _child = syncChild(child, oldChild, null);
355 }
356
357 void insert(RenderObjectWrapper child, dynamic slot) {
358 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
359 assert(slot == null);
360 assert(root is RenderObjectWithChildMixin);
361 root.child = child.root;
362 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
363 }
364
365 void removeChild(UINode node) {
366 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
367 assert(root is RenderObjectWithChildMixin);
368 root.child = null;
369 super.removeChild(node);
370 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
371 }
372
373 void remove() {
374 if (child != null)
375 removeChild(child);
376 super.remove();
377 }
378
379 }
380
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 {
559
560 // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes
561 // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() c alls
562
563 MultiChildRenderObjectWrapper({
564 Object key,
565 List<UINode> children
566 }) : this.children = children == null ? const [] : children,
567 super(key: key) {
568 assert(!_debugHasDuplicateIds());
569 }
570
571 final List<UINode> children;
572
573 void insert(RenderObjectWrapper child, dynamic slot) {
574 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
575 assert(slot == null || slot is RenderObject);
576 assert(root is ContainerRenderObjectMixin);
577 root.add(child.root, before: slot);
578 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
579 }
580
581 void removeChild(UINode node) {
582 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
583 assert(root is ContainerRenderObjectMixin);
584 assert(node.root.parent == root);
585 root.remove(node.root);
586 super.removeChild(node);
587 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
588 }
589
590 void remove() {
591 assert(children != null);
592 for (var child in children) {
593 assert(child != null);
594 removeChild(child);
595 }
596 super.remove();
597 }
598
599 bool _debugHasDuplicateIds() {
600 var idSet = new HashSet<String>();
601 for (var child in children) {
602 assert(child != null);
603 if (child.interchangeable)
604 continue; // when these nodes are reordered, we just reassign the data
605
606 if (!idSet.add(child._key)) {
607 throw '''If multiple non-interchangeable nodes of the same type exist as children
608 of another node, they must have unique keys.
609 Duplicate: "${child._key}"''';
610 }
611 }
612 return false;
613 }
614
615 void syncRenderObject(MultiChildRenderObjectWrapper old) {
616 super.syncRenderObject(old);
617
618 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
619 if (root is! ContainerRenderObjectMixin)
620 return;
621
622 var startIndex = 0;
623 var endIndex = children.length;
624
625 var oldChildren = old == null ? [] : old.children;
626 var oldStartIndex = 0;
627 var oldEndIndex = oldChildren.length;
628
629 RenderObject nextSibling = null;
630 UINode currentNode = null;
631 UINode oldNode = null;
632
633 void sync(int atIndex) {
634 children[atIndex] = syncChild(currentNode, oldNode, nextSibling);
635 assert(children[atIndex] != null);
636 }
637
638 // Scan backwards from end of list while nodes can be directly synced
639 // without reordering.
640 while (endIndex > startIndex && oldEndIndex > oldStartIndex) {
641 currentNode = children[endIndex - 1];
642 oldNode = oldChildren[oldEndIndex - 1];
643
644 if (currentNode._key != oldNode._key) {
645 break;
646 }
647
648 endIndex--;
649 oldEndIndex--;
650 sync(endIndex);
651 }
652
653 HashMap<String, UINode> oldNodeIdMap = null;
654
655 bool oldNodeReordered(String key) {
656 return oldNodeIdMap != null &&
657 oldNodeIdMap.containsKey(key) &&
658 oldNodeIdMap[key] == null;
659 }
660
661 void advanceOldStartIndex() {
662 oldStartIndex++;
663 while (oldStartIndex < oldEndIndex &&
664 oldNodeReordered(oldChildren[oldStartIndex]._key)) {
665 oldStartIndex++;
666 }
667 }
668
669 void ensureOldIdMap() {
670 if (oldNodeIdMap != null)
671 return;
672
673 oldNodeIdMap = new HashMap<String, UINode>();
674 for (int i = oldStartIndex; i < oldEndIndex; i++) {
675 var node = oldChildren[i];
676 if (!node.interchangeable)
677 oldNodeIdMap.putIfAbsent(node._key, () => node);
678 }
679 }
680
681 bool searchForOldNode() {
682 if (currentNode.interchangeable)
683 return false; // never re-order these nodes
684
685 ensureOldIdMap();
686 oldNode = oldNodeIdMap[currentNode._key];
687 if (oldNode == null)
688 return false;
689
690 oldNodeIdMap[currentNode._key] = null; // mark it reordered
691 assert(root is ContainerRenderObjectMixin);
692 assert(old.root is ContainerRenderObjectMixin);
693 assert(oldNode.root != null);
694
695 (old.root as ContainerRenderObjectMixin).remove(oldNode.root); // TODO(ian h): Remove cast once the analyzer is cleverer
696 root.add(oldNode.root, before: nextSibling);
697
698 return true;
699 }
700
701 // Scan forwards, this time we may re-order;
702 nextSibling = root.firstChild;
703 while (startIndex < endIndex && oldStartIndex < oldEndIndex) {
704 currentNode = children[startIndex];
705 oldNode = oldChildren[oldStartIndex];
706
707 if (currentNode._key == oldNode._key) {
708 assert(currentNode.runtimeType == oldNode.runtimeType);
709 nextSibling = root.childAfter(nextSibling);
710 sync(startIndex);
711 startIndex++;
712 advanceOldStartIndex();
713 continue;
714 }
715
716 oldNode = null;
717 searchForOldNode();
718 sync(startIndex);
719 startIndex++;
720 }
721
722 // New insertions
723 oldNode = null;
724 while (startIndex < endIndex) {
725 currentNode = children[startIndex];
726 sync(startIndex);
727 startIndex++;
728 }
729
730 // Removals
731 currentNode = null;
732 while (oldStartIndex < oldEndIndex) {
733 oldNode = oldChildren[oldStartIndex];
734 removeChild(oldNode);
735 advanceOldStartIndex();
736 }
737
738 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
739 }
740
741 }
742
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
1095 class UINodeAppView extends AppView {
1096
1097 UINodeAppView() {
1098 assert(_appView == null);
1099 }
1100
1101 static UINodeAppView _appView;
1102 static void initUINodeAppView() {
1103 if (_appView == null)
1104 _appView = new UINodeAppView();
1105 }
1106
1107 void dispatchEvent(sky.Event event, HitTestResult result) {
1108 assert(_appView == this);
1109 super.dispatchEvent(event, result);
1110 for (HitTestEntry entry in result.path.reversed) {
1111 UINode target = RenderObjectWrapper._getMounted(entry.target);
1112 if (target == null)
1113 continue;
1114 RenderObject targetRoot = target.root;
1115 while (target != null && target.root == targetRoot) {
1116 if (target is EventListenerNode)
1117 target._handleEvent(event);
1118 target = target._parent;
1119 }
1120 }
1121 }
1122
1123 }
1124
1125 abstract class AbstractUINodeRoot extends Component {
1126
1127 AbstractUINodeRoot() : super(stateful: true) {
1128 UINodeAppView.initUINodeAppView();
1129 _mounted = true;
1130 _scheduleComponentForRender(this);
1131 }
1132
1133 void syncFields(AbstractUINodeRoot source) {
1134 assert(false);
1135 // if we get here, it implies that we have a parent
1136 }
1137
1138 void _buildIfDirty() {
1139 assert(_dirty);
1140 assert(_mounted);
1141 assert(parent == null);
1142 _sync(null, null);
1143 }
1144
1145 }
1146
1147 abstract class App extends AbstractUINodeRoot {
1148
1149 App();
1150
1151 AppView get appView => UINodeAppView._appView;
1152
1153 void _buildIfDirty() {
1154 super._buildIfDirty();
1155
1156 if (root.parent == null) {
1157 // we haven't attached it yet
1158 UINodeAppView._appView.root = root;
1159 }
1160 assert(root.parent is RenderView);
1161 }
1162
1163 }
1164
1165 typedef UINode Builder();
1166
1167 class RenderNodeToUINodeAdapter extends AbstractUINodeRoot {
1168
1169 RenderNodeToUINodeAdapter(
1170 RenderObjectWithChildMixin<RenderBox> container,
1171 this.builder
1172 ) : _container = container {
1173 assert(builder != null);
1174 }
1175
1176 RenderObjectWithChildMixin<RenderBox> _container;
1177 RenderObjectWithChildMixin<RenderBox> get container => _container;
1178 void set container(RenderObjectWithChildMixin<RenderBox> value) {
1179 if (_container != value) {
1180 assert(value.child == null);
1181 if (root != null) {
1182 assert(_container.child == root);
1183 _container.child = null;
1184 }
1185 _container = value;
1186 if (root != null) {
1187 _container.child = root;
1188 assert(_container.child == root);
1189 }
1190 }
1191 }
1192
1193 final Builder builder;
1194
1195 void _buildIfDirty() {
1196 super._buildIfDirty();
1197 if (root.parent == null) {
1198 // we haven't attached it yet
1199 assert(_container.child == null);
1200 _container.child = root;
1201 }
1202 assert(root.parent == _container);
1203 }
1204
1205 UINode build() => builder();
1206
1207 }
OLDNEW
« no previous file with comments | « sky/sdk/lib/framework/fn.md ('k') | sky/sdk/lib/framework/rendering/box.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698