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

Side by Side Diff: sky/framework/fn.dart

Issue 1117143003: [Effen] Port fn.dart from the legacy sky.Node backend to the RenderNode backend, which is currently… (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 7 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
OLDNEW
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; 5 library fn;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:sky' as sky; 9 import 'dart:sky' as sky;
10 import 'reflect.dart' as reflect; 10 import 'reflect.dart' as reflect;
11 import 'layout.dart';
12
13 export 'layout.dart' show Style;
11 14
12 final sky.Tracing _tracing = sky.window.tracing; 15 final sky.Tracing _tracing = sky.window.tracing;
13 16
14 final bool _shouldLogRenderDuration = false; 17 final bool _shouldLogRenderDuration = false;
15 final bool _shouldTrace = false; 18 final bool _shouldTrace = false;
16 19
17 class Style {
18 final String _className;
19 static final Map<String, Style> _cache = new HashMap<String, Style>();
20
21 static int _nextStyleId = 1;
22
23 static String _getNextClassName() { return "style${_nextStyleId++}"; }
24
25 Style extend(Style other) {
26 var className = "$_className ${other._className}";
27
28 return _cache.putIfAbsent(className, () {
29 return new Style._internal(className);
30 });
31 }
32
33 factory Style(String styles) {
34 return _cache.putIfAbsent(styles, () {
35 var className = _getNextClassName();
36 sky.Element styleNode = sky.document.createElement('style');
37 styleNode.setChild(new sky.Text(".$className { $styles }"));
38 sky.document.appendChild(styleNode);
39 return new Style._internal(className);
40 });
41 }
42
43 Style._internal(this._className);
44 }
45
46 void _parentInsertBefore(sky.ParentNode parent,
47 sky.Node node,
48 sky.Node ref) {
49 if (ref != null) {
50 ref.insertBefore([node]);
51 } else {
52 parent.appendChild(node);
53 }
54 }
55
56 enum _SyncOperation { IDENTICAL, INSERTION, STATEFUL, STATELESS, REMOVAL } 20 enum _SyncOperation { IDENTICAL, INSERTION, STATEFUL, STATELESS, REMOVAL }
57 21
58 /* 22 /*
59 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and 23 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and
60 * can be sync'd. 24 * can be sync'd.
61 */ 25 */
62 abstract class UINode { 26 abstract class UINode {
63 String _key; 27 String _key;
64 UINode _parent; 28 UINode _parent;
65 UINode get parent => _parent; 29 UINode get parent => _parent;
66 sky.Node _root; 30 RenderCSS _root;
67 bool _defunct = false; 31 bool _defunct = false;
68 32
69 UINode({ Object key }) { 33 UINode({ Object key }) {
70 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; 34 _key = key == null ? "$runtimeType" : "$runtimeType-$key";
71 } 35 }
72 36
73 // Subclasses which implements Nodes that become stateful may return true 37 // Subclasses which implements Nodes that become stateful may return true
74 // if the |old| node has become stateful and should be retained. 38 // if the |old| node has become stateful and should be retained.
75 bool _willSync(UINode old) => false; 39 bool _willSync(UINode old) => false;
76 40
77 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore); 41 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore);
78 42
79 void _remove() { 43 void _remove() {
80 _defunct = true; 44 _defunct = true;
81 _root = null; 45 _root = null;
82 handleRemoved(); 46 handleRemoved();
83 } 47 }
84 void handleRemoved() { } 48 void handleRemoved() { }
85 49
86 int _nodeDepth; 50 int _nodeDepth;
87 void _ensureDepth() { 51 void _ensureDepth() {
(...skipping 23 matching lines...) Expand all
111 String outString = opString.substring(opString.indexOf('.') + 1); 75 String outString = opString.substring(opString.indexOf('.') + 1);
112 _trace('_sync($outString) $key'); 76 _trace('_sync($outString) $key');
113 } 77 }
114 78
115 void _removeChild(UINode node) { 79 void _removeChild(UINode node) {
116 _traceSync(_SyncOperation.REMOVAL, node._key); 80 _traceSync(_SyncOperation.REMOVAL, node._key);
117 node._remove(); 81 node._remove();
118 } 82 }
119 83
120 // Returns the child which should be retained as the child of this node. 84 // Returns the child which should be retained as the child of this node.
121 UINode _syncChild(UINode node, UINode oldNode, sky.ParentNode host, 85 UINode _syncChild(UINode node, UINode oldNode, RenderCSSContainer host,
122 sky.Node insertBefore) { 86 RenderCSS insertBefore) {
123 87
124 assert(oldNode == null || node._key == oldNode._key); 88 assert(oldNode == null || node._key == oldNode._key);
125 89
126 if (node == oldNode) { 90 if (node == oldNode) {
127 _traceSync(_SyncOperation.IDENTICAL, node._key); 91 _traceSync(_SyncOperation.IDENTICAL, node._key);
128 return node; // Nothing to do. Subtrees must be identical. 92 return node; // Nothing to do. Subtrees must be identical.
129 } 93 }
130 94
131 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a 95 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a
132 // new component was built that could re-use some of it. Consider 96 // new component was built that could re-use some of it. Consider
133 // syncing the new VDOM against the old one. 97 // syncing the new VDOM against the old one.
134 if (oldNode != null && node._key != oldNode._key) { 98 if (oldNode != null && node._key != oldNode._key) {
135 _removeChild(oldNode); 99 _removeChild(oldNode);
136 } 100 }
137 101
138 if (node._willSync(oldNode)) { 102 if (node._willSync(oldNode)) {
139 _traceSync(_SyncOperation.STATEFUL, node._key); 103 _traceSync(_SyncOperation.STATEFUL, node._key);
140 oldNode._sync(node, host, insertBefore); 104 oldNode._sync(node, host, insertBefore);
141 node._defunct = true; 105 node._defunct = true;
142 assert(oldNode._root is sky.Node); 106 assert(oldNode._root is RenderCSS);
143 return oldNode; 107 return oldNode;
144 } 108 }
145 109
146 node._parent = this; 110 node._parent = this;
147 111
148 if (oldNode == null) { 112 if (oldNode == null) {
149 _traceSync(_SyncOperation.INSERTION, node._key); 113 _traceSync(_SyncOperation.INSERTION, node._key);
150 } else { 114 } else {
151 _traceSync(_SyncOperation.STATELESS, node._key); 115 _traceSync(_SyncOperation.STATELESS, node._key);
152 } 116 }
153 node._sync(oldNode, host, insertBefore); 117 node._sync(oldNode, host, insertBefore);
154 if (oldNode != null) 118 if (oldNode != null)
155 oldNode._defunct = true; 119 oldNode._defunct = true;
156 120
157 assert(node._root is sky.Node); 121 assert(node._root is RenderCSS);
158 return node; 122 return node;
159 } 123 }
160 } 124 }
161 125
162 abstract class ContentNode extends UINode { 126 abstract class ContentNode extends UINode {
163 UINode content; 127 UINode content;
164 128
165 ContentNode(UINode content) : this.content = content, super(key: content._key) ; 129 ContentNode(UINode content) : this.content = content, super(key: content._key) ;
166 130
167 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { 131 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) {
168 UINode oldContent = old == null ? null : (old as ContentNode).content; 132 UINode oldContent = old == null ? null : (old as ContentNode).content;
169 content = _syncChild(content, oldContent, host, insertBefore); 133 content = _syncChild(content, oldContent, host, insertBefore);
134 assert(content._root != null);
170 _root = content._root; 135 _root = content._root;
171 } 136 }
172 137
173 void _remove() { 138 void _remove() {
174 _removeChild(content); 139 if (content != null)
140 _removeChild(content);
175 super._remove(); 141 super._remove();
176 } 142 }
177 } 143 }
178 144
179 class StyleNode extends ContentNode { 145 class StyleNode extends ContentNode {
180 final Style style; 146 final Style style;
181 147
182 StyleNode(UINode content, this.style): super(content); 148 StyleNode(UINode content, this.style): super(content);
183 } 149 }
184 150
185 /* 151 /*
186 * SkyNodeWrappers correspond to a desired state of a sky.Node. They are fully 152 * SkyNodeWrappers correspond to a desired state of a RenderCSS. They are fully
187 * immutable, with one exception: A UINode which is a Component which lives with in 153 * immutable, with one exception: A UINode which is a Component which lives with in
188 * an SkyElementWrapper's children list, may be replaced with the "old" instance if it 154 * an SkyElementWrapper's children list, may be replaced with the "old" instance if it
189 * has become stateful. 155 * has become stateful.
190 */ 156 */
191 abstract class SkyNodeWrapper extends UINode { 157 abstract class SkyNodeWrapper extends UINode {
192 158
193 static final Map<sky.Node, SkyNodeWrapper> _nodeMap = 159 static final Map<RenderCSS, SkyNodeWrapper> _nodeMap =
194 new HashMap<sky.Node, SkyNodeWrapper>(); 160 new HashMap<RenderCSS, SkyNodeWrapper>();
195 161
196 static SkyNodeWrapper _getMounted(sky.Node node) => _nodeMap[node]; 162 static SkyNodeWrapper _getMounted(RenderCSS node) => _nodeMap[node];
197 163
198 SkyNodeWrapper({ Object key }) : super(key: key); 164 SkyNodeWrapper({ Object key }) : super(key: key);
199 165
200 SkyNodeWrapper get _emptyNode; 166 SkyNodeWrapper get _emptyNode;
201 167
202 sky.Node _createNode(); 168 RenderCSS _createNode();
203 169
204 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { 170 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) {
205 if (old == null) { 171 if (old == null) {
206 _root = _createNode(); 172 _root = _createNode();
207 _parentInsertBefore(host, _root, insertBefore); 173 assert(_root != null);
174 host.add(_root, before: insertBefore);
208 old = _emptyNode; 175 old = _emptyNode;
209 } else { 176 } else {
210 _root = old._root; 177 _root = old._root;
178 assert(_root != null);
211 } 179 }
212 180
213 _nodeMap[_root] = this; 181 _nodeMap[_root] = this;
214 _syncNode(old); 182 _syncNode(old);
215 } 183 }
216 184
217 void _syncNode(SkyNodeWrapper old); 185 void _syncNode(SkyNodeWrapper old);
218 186
187 void _removeChild(UINode node) {
188 assert(_root is RenderCSSContainer);
189 _root.remove(node._root);
190 super._removeChild(node);
191 }
192
219 void _remove() { 193 void _remove() {
220 assert(_root != null); 194 assert(_root != null);
221 _root.remove();
222 _nodeMap.remove(_root); 195 _nodeMap.remove(_root);
223 super._remove(); 196 super._remove();
224 } 197 }
225 } 198 }
226 199
227 typedef GestureEventListener(sky.GestureEvent e); 200 typedef GestureEventListener(sky.GestureEvent e);
228 typedef PointerEventListener(sky.PointerEvent e); 201 typedef PointerEventListener(sky.PointerEvent e);
229 typedef EventListener(sky.Event e); 202 typedef EventListener(sky.Event e);
230 203
231 class EventListenerNode extends ContentNode { 204 class EventListenerNode extends ContentNode {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 super(content); 280 super(content);
308 281
309 void _handleEvent(sky.Event e) { 282 void _handleEvent(sky.Event e) {
310 sky.EventListener listener = listeners[e.type]; 283 sky.EventListener listener = listeners[e.type];
311 if (listener != null) { 284 if (listener != null) {
312 listener(e); 285 listener(e);
313 } 286 }
314 } 287 }
315 288
316 static void _dispatchEvent(sky.Event e) { 289 static void _dispatchEvent(sky.Event e) {
317 UINode target = SkyNodeWrapper._getMounted(e.target); 290 UINode target = SkyNodeWrapper._getMounted(bridgeEventTargetToRenderNode(e.t arget));
318 291
319 // TODO(rafaelw): StopPropagation? 292 // TODO(rafaelw): StopPropagation?
320 while (target != null) { 293 while (target != null) {
321 if (target is EventListenerNode) { 294 if (target is EventListenerNode) {
322 (target as EventListenerNode)._handleEvent(e); 295 target._handleEvent(e);
323 } 296 }
324 297
325 target = target._parent; 298 target = target._parent;
326 } 299 }
327 } 300 }
328 301
329 static void _ensureDocumentListener(String eventType) { 302 static void _ensureDocumentListener(String eventType) {
330 if (_registeredEvents.add(eventType)) { 303 if (_registeredEvents.add(eventType)) {
331 sky.document.addEventListener(eventType, _dispatchEvent); 304 sky.document.addEventListener(eventType, _dispatchEvent);
332 } 305 }
333 } 306 }
334 307
335 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { 308 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) {
336 for (var type in listeners.keys) { 309 for (var type in listeners.keys) {
337 _ensureDocumentListener(type); 310 _ensureDocumentListener(type);
338 } 311 }
339 312
340 super._sync(old, host, insertBefore); 313 super._sync(old, host, insertBefore);
341 } 314 }
342 } 315 }
343 316
344 class Text extends SkyNodeWrapper { 317 class Text extends SkyNodeWrapper {
345 final String data; 318 final String data;
346 319
347 // Text nodes are special cases of having non-unique keys (which don't need 320 // Text nodes are special cases of having non-unique keys (which don't need
348 // to be assigned as part of the API). Since they are unique in not having 321 // to be assigned as part of the API). Since they are unique in not having
349 // children, there's little point to reordering, so we always just re-assign 322 // children, there's little point to reordering, so we always just re-assign
350 // the data. 323 // the data.
351 Text(this.data) : super(key:'*text*'); 324 Text(this.data) : super(key:'*text*');
352 325
353 static final Text _emptyText = new Text(null); 326 static final Text _emptyText = new Text(null);
354 327
355 SkyNodeWrapper get _emptyNode => _emptyText; 328 SkyNodeWrapper get _emptyNode => _emptyText;
356 329
357 static final Style _displayParagraph = new Style('display:paragraph'); 330 RenderCSSText _root;
358 331 RenderCSS _createNode() {
359 sky.Node _createNode() { 332 return new RenderCSSText(this, this.data);
360 return sky.document.createElement('div')
361 ..setChild(new sky.Text(this.data))
362 ..setAttribute('class', _displayParagraph._className) ;
363 } 333 }
364 334
365 void _syncNode(SkyNodeWrapper old) { 335 void _syncNode(SkyNodeWrapper old) {
366 if (old == _emptyText) 336 if (old == _emptyText)
367 return; // we set inside _createNode(); 337 return; // we set inside _createNode();
368 338 _root.data = data;
369 (_root.firstChild as sky.Text).data = data;
370 } 339 }
371 } 340 }
372 341
373 final List<UINode> _emptyList = new List<UINode>(); 342 final List<UINode> _emptyList = new List<UINode>();
374 343
375 abstract class SkyElementWrapper extends SkyNodeWrapper { 344 abstract class SkyElementWrapper extends SkyNodeWrapper {
376 345
377 String get _tagName;
378
379 sky.Node _createNode() => sky.document.createElement(_tagName);
380
381 final List<UINode> children; 346 final List<UINode> children;
382 final Style style; 347 final Style style;
383 final String inlineStyle; 348 final String inlineStyle;
384 349
385 String _class;
386
387 SkyElementWrapper({ 350 SkyElementWrapper({
388 Object key, 351 Object key,
389 List<UINode> children, 352 List<UINode> children,
390 this.style, 353 this.style,
391 this.inlineStyle 354 this.inlineStyle
392 }) : this.children = children == null ? _emptyList : children, 355 }) : this.children = children == null ? _emptyList : children,
393 super(key:key) { 356 super(key:key) {
394 357
395 assert(!_debugHasDuplicateIds()); 358 assert(!_debugHasDuplicateIds());
396 } 359 }
397 360
398 void _remove() { 361 void _remove() {
362 assert(children != null);
363 for (var child in children) {
364 assert(child != null);
365 _removeChild(child);
366 }
399 super._remove(); 367 super._remove();
400 if (children != null) {
401 for (var child in children) {
402 _removeChild(child);
403 }
404 }
405 } 368 }
406 369
407 bool _debugHasDuplicateIds() { 370 bool _debugHasDuplicateIds() {
408 var idSet = new HashSet<String>(); 371 var idSet = new HashSet<String>();
409 for (var child in children) { 372 for (var child in children) {
373 assert(child != null);
410 if (child is Text) { 374 if (child is Text) {
411 continue; // Text nodes all have the same key and are never reordered. 375 continue; // Text nodes all have the same key and are never reordered.
412 } 376 }
413 377
414 if (!idSet.add(child._key)) { 378 if (!idSet.add(child._key)) {
415 throw '''If multiple (non-Text) nodes of the same type exist as children 379 throw '''If multiple (non-Text) nodes of the same type exist as children
416 of another node, they must have unique keys.'''; 380 of another node, they must have unique keys.''';
417 } 381 }
418 } 382 }
419 return false; 383 return false;
420 } 384 }
421 385
422 void _ensureClass() {
423 if (_class == null) {
424 List<Style> styles = new List<Style>();
425 if (style != null) {
426 styles.add(style);
427 }
428
429 UINode parent = _parent;
430 while (parent != null && parent is! SkyNodeWrapper) {
431 if (parent is StyleNode && (parent as StyleNode).style != null)
432 styles.add((parent as StyleNode).style);
433
434 parent = parent._parent;
435 }
436
437 _class = styles.map((s) => s._className).join(' ');
438 }
439 }
440
441 void _syncNode(SkyNodeWrapper old) { 386 void _syncNode(SkyNodeWrapper old) {
442 SkyElementWrapper oldSkyElementWrapper = old as SkyElementWrapper; 387 SkyElementWrapper oldSkyElementWrapper = old as SkyElementWrapper;
443 sky.Element root = _root as sky.Element;
444 388
445 _ensureClass(); 389 List<Style> styles = new List<Style>();
446 if (_class != oldSkyElementWrapper._class && _class != '') 390 if (style != null)
447 root.setAttribute('class', _class); 391 styles.add(style);
392 UINode parent = _parent;
393 while (parent != null && parent is! SkyNodeWrapper) {
394 if (parent is StyleNode && parent.style != null)
395 styles.add(parent.style);
396 parent = parent._parent;
397 }
398 _root.updateStyles(styles);
448 399
449 if (inlineStyle != oldSkyElementWrapper.inlineStyle) 400 _root.updateInlineStyle(inlineStyle);
450 root.setAttribute('style', inlineStyle);
451 401
452 _syncChildren(oldSkyElementWrapper); 402 _syncChildren(oldSkyElementWrapper);
453 } 403 }
454 404
455 void _syncChildren(SkyElementWrapper oldSkyElementWrapper) { 405 void _syncChildren(SkyElementWrapper oldSkyElementWrapper) {
456 sky.Element root = _root as sky.Element; 406 if (_root is! RenderCSSContainer)
457 assert(root != null); 407 return;
458 408
459 var startIndex = 0; 409 var startIndex = 0;
460 var endIndex = children.length; 410 var endIndex = children.length;
461 411
462 var oldChildren = oldSkyElementWrapper.children; 412 var oldChildren = oldSkyElementWrapper.children;
463 var oldStartIndex = 0; 413 var oldStartIndex = 0;
464 var oldEndIndex = oldChildren.length; 414 var oldEndIndex = oldChildren.length;
465 415
466 sky.Node nextSibling = null; 416 RenderCSS nextSibling = null;
467 UINode currentNode = null; 417 UINode currentNode = null;
468 UINode oldNode = null; 418 UINode oldNode = null;
469 419
470 void sync(int atIndex) { 420 void sync(int atIndex) {
471 children[atIndex] = _syncChild(currentNode, oldNode, _root, nextSibling); 421 children[atIndex] = _syncChild(currentNode, oldNode, _root, nextSibling);
422 assert(children[atIndex] != null);
472 } 423 }
473 424
474 // Scan backwards from end of list while nodes can be directly synced 425 // Scan backwards from end of list while nodes can be directly synced
475 // without reordering. 426 // without reordering.
476 while (endIndex > startIndex && oldEndIndex > oldStartIndex) { 427 while (endIndex > startIndex && oldEndIndex > oldStartIndex) {
477 currentNode = children[endIndex - 1]; 428 currentNode = children[endIndex - 1];
478 oldNode = oldChildren[oldEndIndex - 1]; 429 oldNode = oldChildren[oldEndIndex - 1];
479 430
480 if (currentNode._key != oldNode._key) { 431 if (currentNode._key != oldNode._key) {
481 break; 432 break;
482 } 433 }
483 434
484 endIndex--; 435 endIndex--;
485 oldEndIndex--; 436 oldEndIndex--;
486 sync(endIndex); 437 sync(endIndex);
487 nextSibling = currentNode._root;
488 } 438 }
489 439
490 HashMap<String, UINode> oldNodeIdMap = null; 440 HashMap<String, UINode> oldNodeIdMap = null;
491 441
492 bool oldNodeReordered(String key) { 442 bool oldNodeReordered(String key) {
493 return oldNodeIdMap != null && 443 return oldNodeIdMap != null &&
494 oldNodeIdMap.containsKey(key) && 444 oldNodeIdMap.containsKey(key) &&
495 oldNodeIdMap[key] == null; 445 oldNodeIdMap[key] == null;
496 } 446 }
497 447
(...skipping 21 matching lines...) Expand all
519 bool searchForOldNode() { 469 bool searchForOldNode() {
520 if (currentNode is Text) 470 if (currentNode is Text)
521 return false; // Never re-order Text nodes. 471 return false; // Never re-order Text nodes.
522 472
523 ensureOldIdMap(); 473 ensureOldIdMap();
524 oldNode = oldNodeIdMap[currentNode._key]; 474 oldNode = oldNodeIdMap[currentNode._key];
525 if (oldNode == null) 475 if (oldNode == null)
526 return false; 476 return false;
527 477
528 oldNodeIdMap[currentNode._key] = null; // mark it reordered. 478 oldNodeIdMap[currentNode._key] = null; // mark it reordered.
529 _parentInsertBefore(root, oldNode._root, nextSibling); 479 assert(_root is RenderCSSContainer);
480 assert(oldNode._root is RenderCSSContainer);
481 oldSkyElementWrapper._root.remove(oldNode._root);
482 _root.add(oldNode._root, before: nextSibling);
530 return true; 483 return true;
531 } 484 }
532 485
533 // Scan forwards, this time we may re-order; 486 // Scan forwards, this time we may re-order;
534 nextSibling = root.firstChild; 487 nextSibling = _root.firstChild;
535 while (startIndex < endIndex && oldStartIndex < oldEndIndex) { 488 while (startIndex < endIndex && oldStartIndex < oldEndIndex) {
536 currentNode = children[startIndex]; 489 currentNode = children[startIndex];
537 oldNode = oldChildren[oldStartIndex]; 490 oldNode = oldChildren[oldStartIndex];
538 491
539 if (currentNode._key == oldNode._key) { 492 if (currentNode._key == oldNode._key) {
540 assert(currentNode.runtimeType == oldNode.runtimeType); 493 assert(currentNode.runtimeType == oldNode.runtimeType);
541 nextSibling = nextSibling.nextSibling; 494 nextSibling = _root.childAfter(nextSibling);
542 sync(startIndex); 495 sync(startIndex);
543 startIndex++; 496 startIndex++;
544 advanceOldStartIndex(); 497 advanceOldStartIndex();
545 continue; 498 continue;
546 } 499 }
547 500
548 oldNode = null; 501 oldNode = null;
549 searchForOldNode(); 502 searchForOldNode();
550 sync(startIndex); 503 sync(startIndex);
551 startIndex++; 504 startIndex++;
(...skipping 12 matching lines...) Expand all
564 while (oldStartIndex < oldEndIndex) { 517 while (oldStartIndex < oldEndIndex) {
565 oldNode = oldChildren[oldStartIndex]; 518 oldNode = oldChildren[oldStartIndex];
566 _removeChild(oldNode); 519 _removeChild(oldNode);
567 advanceOldStartIndex(); 520 advanceOldStartIndex();
568 } 521 }
569 } 522 }
570 } 523 }
571 524
572 class Container extends SkyElementWrapper { 525 class Container extends SkyElementWrapper {
573 526
574 String get _tagName => 'div'; 527 RenderCSS _createNode() => new RenderCSSContainer(this);
575 528
576 static final Container _emptyContainer = new Container(); 529 static final Container _emptyContainer = new Container();
577 530
578 SkyNodeWrapper get _emptyNode => _emptyContainer; 531 SkyNodeWrapper get _emptyNode => _emptyContainer;
579 532
580 Container({ 533 Container({
581 Object key, 534 Object key,
582 List<UINode> children, 535 List<UINode> children,
583 Style style, 536 Style style,
584 String inlineStyle 537 String inlineStyle
585 }) : super( 538 }) : super(
586 key: key, 539 key: key,
587 children: children, 540 children: children,
588 style: style, 541 style: style,
589 inlineStyle: inlineStyle 542 inlineStyle: inlineStyle
590 ); 543 );
591 } 544 }
592 545
593 abstract class LayoutContainer extends Container {
594
595 LayoutContainer({
596 Object key,
597 List<UINode> children,
598 Style style,
599 String inlineStyle
600 }) : super(
601 key: key,
602 children: children,
603 style: style,
604 inlineStyle: inlineStyle
605 );
606
607 sky.Node _createNode() {
608 var result = super._createNode();
609 result.setLayoutManager(() => layout(_root));
610 return result;
611 }
612
613 // If we ever reuse sky nodes for different classes, then we should
614 // call _root.setLayoutManager(null) during _remove() here.
615
616 void _syncNode(SkyNodeWrapper old) {
617 super._syncNode(old);
618 _root.setLayoutManager(() => layout(_root));
619 _root.setNeedsLayout();
620 }
621
622 void layout(sky.Element skyNode);
623 // set skyNode.width (e.g., set it to skyNode.parentNode.width)
624 // for each skyNode.getChildNodes()[i]:
625 // call .layout()
626 // set .x, .y
627 // set .width if you want to force a width
628 // set .height if you want to force a height
629 // set skyNode.height
630
631 }
632
633 class Image extends SkyElementWrapper { 546 class Image extends SkyElementWrapper {
634 547
635 String get _tagName => 'img'; 548 RenderCSSImage _root;
549 RenderCSSImage _createNode() => new RenderCSSImage(this, this.src, this.width, this.height);
636 550
637 static final Image _emptyImage = new Image(); 551 static final Image _emptyImage = new Image();
638 552
639 SkyNodeWrapper get _emptyNode => _emptyImage; 553 SkyNodeWrapper get _emptyNode => _emptyImage;
640 554
641 final String src; 555 final String src;
642 final int width; 556 final int width;
643 final int height; 557 final int height;
644 558
645 Image({ 559 Image({
646 Object key, 560 Object key,
647 List<UINode> children, 561 List<UINode> children,
648 Style style, 562 Style style,
649 String inlineStyle, 563 String inlineStyle,
650 this.width, 564 this.width,
651 this.height, 565 this.height,
652 this.src 566 this.src
653 }) : super( 567 }) : super(
654 key: key, 568 key: key,
655 children: children, 569 children: children,
656 style: style, 570 style: style,
657 inlineStyle: inlineStyle 571 inlineStyle: inlineStyle
658 ); 572 );
659 573
660 void _syncNode(UINode old) { 574 void _syncNode(UINode old) {
661 super._syncNode(old); 575 super._syncNode(old);
662 576 _root.configure(this.src, this.width, this.height);
663 Image oldImage = old as Image;
664 sky.HTMLImageElement skyImage = _root as sky.HTMLImageElement;
665
666 if (src != oldImage.src)
667 skyImage.src = src;
668
669 if (width != oldImage.width)
670 skyImage.style['width'] = '${width}px';
671
672 if (height != oldImage.height)
673 skyImage.style['height'] = '${height}px';
674 } 577 }
675 } 578 }
676 579
677 class Anchor extends SkyElementWrapper {
678
679 String get _tagName => 'a';
680
681 static final Anchor _emptyAnchor = new Anchor();
682
683 UINode get _emptyNode => _emptyAnchor;
684
685 final String href;
686 final int width;
687 final int height;
688
689 Anchor({
690 Object key,
691 List<UINode> children,
692 Style style,
693 String inlineStyle,
694 this.width,
695 this.height,
696 this.href
697 }) : super(
698 key: key,
699 children: children,
700 style: style,
701 inlineStyle: inlineStyle
702 );
703
704 void _syncNode(UINode old) {
705 super._syncNode(old);
706
707 Anchor oldAnchor = old as Anchor;
708 sky.HTMLAnchorElement skyAnchor = _root as sky.HTMLAnchorElement;
709
710 if (href != oldAnchor.href)
711 skyAnchor.href = href;
712 }
713 }
714
715 580
716 Set<Component> _mountedComponents = new HashSet<Component>(); 581 Set<Component> _mountedComponents = new HashSet<Component>();
717 Set<Component> _unmountedComponents = new HashSet<Component>(); 582 Set<Component> _unmountedComponents = new HashSet<Component>();
718 583
719 void _enqueueDidMount(Component c) { 584 void _enqueueDidMount(Component c) {
720 assert(!_notifingMountStatus); 585 assert(!_notifingMountStatus);
721 _mountedComponents.add(c); 586 _mountedComponents.add(c);
722 } 587 }
723 588
724 void _enqueueDidUnmount(Component c) { 589 void _enqueueDidUnmount(Component c) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
782 if (!_buildScheduled) { 647 if (!_buildScheduled) {
783 _buildScheduled = true; 648 _buildScheduled = true;
784 new Future.microtask(_buildDirtyComponents); 649 new Future.microtask(_buildDirtyComponents);
785 } 650 }
786 } 651 }
787 652
788 abstract class Component extends UINode { 653 abstract class Component extends UINode {
789 bool get _isBuilding => _currentlyBuilding == this; 654 bool get _isBuilding => _currentlyBuilding == this;
790 bool _dirty = true; 655 bool _dirty = true;
791 656
792 sky.Node get _host => _root.parentNode;
793 sky.Node get _insertionPoint => _root == null ? _root : _root.nextSibling;
794
795 UINode _built; 657 UINode _built;
796 final int _order; 658 final int _order;
797 static int _currentOrder = 0; 659 static int _currentOrder = 0;
798 bool _stateful; 660 bool _stateful;
799 static Component _currentlyBuilding; 661 static Component _currentlyBuilding;
800 List<Function> _mountCallbacks; 662 List<Function> _mountCallbacks;
801 List<Function> _unmountCallbacks; 663 List<Function> _unmountCallbacks;
802 664
803 void onDidMount(Function fn) { 665 void onDidMount(Function fn) {
804 if (_mountCallbacks == null) 666 if (_mountCallbacks == null)
(...skipping 23 matching lines...) Expand all
828 _mountCallbacks.forEach((fn) => fn()); 690 _mountCallbacks.forEach((fn) => fn());
829 } 691 }
830 692
831 void _didUnmount() { 693 void _didUnmount() {
832 if (_unmountCallbacks != null) 694 if (_unmountCallbacks != null)
833 _unmountCallbacks.forEach((fn) => fn()); 695 _unmountCallbacks.forEach((fn) => fn());
834 } 696 }
835 697
836 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently 698 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently
837 // needed to get sizing info. 699 // needed to get sizing info.
838 sky.Node getRoot() => _root; 700 RenderCSS getRoot() => _root;
839 701
840 void _remove() { 702 void _remove() {
841 assert(_built != null); 703 assert(_built != null);
842 assert(_root != null); 704 assert(_root != null);
843 _removeChild(_built); 705 _removeChild(_built);
844 _built = null; 706 _built = null;
845 _enqueueDidUnmount(this); 707 _enqueueDidUnmount(this);
846 super._remove(); 708 super._remove();
847 } 709 }
848 710
(...skipping 15 matching lines...) Expand all
864 } 726 }
865 727
866 /* There are three cases here: 728 /* There are three cases here:
867 * 1) Building for the first time: 729 * 1) Building for the first time:
868 * assert(_built == null && old == null) 730 * assert(_built == null && old == null)
869 * 2) Re-building (because a dirty flag got set): 731 * 2) Re-building (because a dirty flag got set):
870 * assert(_built != null && old == null) 732 * assert(_built != null && old == null)
871 * 3) Syncing against an old version 733 * 3) Syncing against an old version
872 * assert(_built == null && old != null) 734 * assert(_built == null && old != null)
873 */ 735 */
874 void _sync(UINode old, sky.ParentNode host, sky.Node insertBefore) { 736 void _sync(UINode old, RenderCSSContainer host, RenderCSS insertBefore) {
875 assert(!_defunct); 737 assert(!_defunct);
876 assert(_built == null || old == null); 738 assert(_built == null || old == null);
877 739
878 Component oldComponent = old as Component; 740 Component oldComponent = old as Component;
879 741
880 var oldBuilt; 742 var oldBuilt;
881 if (oldComponent == null) { 743 if (oldComponent == null) {
882 oldBuilt = _built; 744 oldBuilt = _built;
883 } else { 745 } else {
884 assert(_built == null); 746 assert(_built == null);
885 oldBuilt = oldComponent._built; 747 oldBuilt = oldComponent._built;
886 } 748 }
887 749
888 if (oldBuilt == null) 750 if (oldBuilt == null)
889 _enqueueDidMount(this); 751 _enqueueDidMount(this);
890 752
891 int lastOrder = _currentOrder; 753 int lastOrder = _currentOrder;
892 _currentOrder = _order; 754 _currentOrder = _order;
893 _currentlyBuilding = this; 755 _currentlyBuilding = this;
894 _built = build(); 756 _built = build();
895 _currentlyBuilding = null; 757 _currentlyBuilding = null;
896 _currentOrder = lastOrder; 758 _currentOrder = lastOrder;
897 759
898 _built = _syncChild(_built, oldBuilt, host, insertBefore); 760 _built = _syncChild(_built, oldBuilt, host, insertBefore);
899 _dirty = false; 761 _dirty = false;
900 _root = _built._root; 762 _root = _built._root;
763 assert(_root != null);
901 } 764 }
902 765
903 void _buildIfDirty() { 766 void _buildIfDirty() {
904 if (!_dirty || _defunct) 767 if (!_dirty || _defunct)
905 return; 768 return;
906 769
907 assert(_host != null);
908 _trace('$_key rebuilding...'); 770 _trace('$_key rebuilding...');
909 _sync(null, _host, _insertionPoint); 771 _sync(null, null, null); // TODO(ianh): figure out how passing "null, null, null" here is ok
910 } 772 }
911 773
912 void scheduleBuild() { 774 void scheduleBuild() {
913 setState(() {}); 775 setState(() {});
914 } 776 }
915 777
916 void setState(Function fn()) { 778 void setState(Function fn()) {
917 _stateful = true; 779 _stateful = true;
918 fn(); 780 fn();
919 if (_isBuilding || _dirty || _defunct) 781 if (_isBuilding || _dirty || _defunct)
920 return; 782 return;
921 783
922 _dirty = true; 784 _dirty = true;
923 _scheduleComponentForRender(this); 785 _scheduleComponentForRender(this);
924 } 786 }
925 787
926 UINode build(); 788 UINode build();
927 } 789 }
928 790
929 abstract class App extends Component { 791 abstract class App extends Component {
930 sky.Node _host; 792 RenderCSS _host;
931 793
932 App() : super(stateful: true) { 794 App() : super(stateful: true) {
933 _host = sky.document.createElement('div'); 795 _host = new RenderCSSRoot(this);
934 sky.document.appendChild(_host);
935 _scheduleComponentForRender(this); 796 _scheduleComponentForRender(this);
936 } 797 }
798
799 void _buildIfDirty() {
800 if (!_dirty || _defunct)
801 return;
802
803 _trace('$_key rebuilding...');
804 _sync(null, _host, _root);
805 }
937 } 806 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698