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

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

Issue 1019633004: Change how events are handled in Effen (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: cr changes Created 5 years, 9 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/framework/components/scrollable.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 11
12 bool _initIsInCheckedMode() { 12 bool _initIsInCheckedMode() {
13 String testFn(i) { double d = i; return d.toString(); } 13 String testFn(i) { double d = i; return d.toString(); }
14 try { 14 try {
15 testFn('not a double'); 15 testFn('not a double');
16 } catch (ex) { 16 } catch (ex) {
17 return true; 17 return true;
18 } 18 }
19 return false; 19 return false;
20 } 20 }
21 21
22 final bool _isInCheckedMode = _initIsInCheckedMode(); 22 final bool _isInCheckedMode = _initIsInCheckedMode();
23 final bool _shouldLogRenderDuration = false; 23 final bool _shouldLogRenderDuration = true;
24
25 class EventHandler {
26 final String type;
27 final sky.EventListener listener;
28
29 EventHandler(this.type, this.listener);
30 }
31
32 class EventMap {
33 final List<EventHandler> _handlers = new List<EventHandler>();
34
35 void listen(String type, sky.EventListener listener) {
36 assert(listener != null);
37 _handlers.add(new EventHandler(type, listener));
38 }
39
40 void addAll(EventMap events) {
41 _handlers.addAll(events._handlers);
42 }
43 }
44 24
45 class Style { 25 class Style {
46 final String _className; 26 final String _className;
47 static final Map<String, Style> _cache = new HashMap<String, Style>(); 27 static final Map<String, Style> _cache = new HashMap<String, Style>();
48 28
49 static int _nextStyleId = 1; 29 static int _nextStyleId = 1;
50 30
51 static String _getNextClassName() { return "style${_nextStyleId++}"; } 31 static String _getNextClassName() { return "style${_nextStyleId++}"; }
52 32
53 Style extend(Style other) { 33 Style extend(Style other) {
(...skipping 30 matching lines...) Expand all
84 /* 64 /*
85 * All Effen nodes derive from Node. All nodes have a _parent, a _key and 65 * All Effen nodes derive from Node. All nodes have a _parent, a _key and
86 * can be sync'd. 66 * can be sync'd.
87 */ 67 */
88 abstract class Node { 68 abstract class Node {
89 String _key; 69 String _key;
90 Node _parent; 70 Node _parent;
91 sky.Node _root; 71 sky.Node _root;
92 bool _defunct = false; 72 bool _defunct = false;
93 73
94 // TODO(abarth): Both Elements and Components have |events| but |Text|
95 // doesn't. Should we add a common base class to contain |events|?
96 final EventMap events = new EventMap();
97
98 Node({ Object key }) { 74 Node({ Object key }) {
99 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; 75 _key = key == null ? "$runtimeType" : "$runtimeType-$key";
100 } 76 }
101 77
102 // Subclasses which implements Nodes that become stateful may return true 78 // Subclasses which implements Nodes that become stateful may return true
103 // if the |old| node has become stateful and should be retained. 79 // if the |old| node has become stateful and should be retained.
104 bool _willSync(Node old) => false; 80 bool _willSync(Node old) => false;
105 81
106 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore); 82 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore);
107 83
(...skipping 23 matching lines...) Expand all
131 } 107 }
132 108
133 node._parent = this; 109 node._parent = this;
134 node._sync(oldNode, host, insertBefore); 110 node._sync(oldNode, host, insertBefore);
135 if (oldNode != null) 111 if (oldNode != null)
136 oldNode._defunct = true; 112 oldNode._defunct = true;
137 113
138 assert(node._root is sky.Node); 114 assert(node._root is sky.Node);
139 return node; 115 return node;
140 } 116 }
141
142 void _syncEvents(EventMap oldEventMap) {
143 List<EventHandler> newHandlers = events._handlers;
144 int newStartIndex = 0;
145 int newEndIndex = newHandlers.length;
146
147 List<EventHandler> oldHandlers = oldEventMap._handlers;
148 int oldStartIndex = 0;
149 int oldEndIndex = oldHandlers.length;
150
151 // Skip over leading handlers that match.
152 while (newStartIndex < newEndIndex && oldStartIndex < oldEndIndex) {
153 EventHandler newHandler = newHandlers[newStartIndex];
154 EventHandler oldHandler = oldHandlers[oldStartIndex];
155 if (newHandler.type != oldHandler.type
156 || newHandler.listener != oldHandler.listener)
157 break;
158 ++newStartIndex;
159 ++oldStartIndex;
160 }
161
162 // Skip over trailing handlers that match.
163 while (newStartIndex < newEndIndex && oldStartIndex < oldEndIndex) {
164 EventHandler newHandler = newHandlers[newEndIndex - 1];
165 EventHandler oldHandler = oldHandlers[oldEndIndex - 1];
166 if (newHandler.type != oldHandler.type
167 || newHandler.listener != oldHandler.listener)
168 break;
169 --newEndIndex;
170 --oldEndIndex;
171 }
172
173 sky.Element root = _root as sky.Element;
174
175 for (int i = oldStartIndex; i < oldEndIndex; ++i) {
176 EventHandler oldHandler = oldHandlers[i];
177 root.removeEventListener(oldHandler.type, oldHandler.listener);
178 }
179
180 for (int i = newStartIndex; i < newEndIndex; ++i) {
181 EventHandler newHandler = newHandlers[i];
182 root.addEventListener(newHandler.type, newHandler.listener);
183 }
184 }
185
186 } 117 }
187 118
188 /* 119 /*
189 * RenderNodes correspond to a desired state of a sky.Node. They are fully 120 * RenderNodes correspond to a desired state of a sky.Node. They are fully
190 * immutable, with one exception: A Node which is a Component which lives within 121 * immutable, with one exception: A Node which is a Component which lives within
191 * an Element's children list, may be replaced with the "old" instance if it 122 * an Element's children list, may be replaced with the "old" instance if it
192 * has become stateful. 123 * has become stateful.
193 */ 124 */
194 abstract class RenderNode extends Node { 125 abstract class RenderNode extends Node {
195 126
127 static final Map<sky.Node, RenderNode> _nodeMap =
128 new HashMap<sky.Node, RenderNode>();
129
130 static RenderNode _getMounted(sky.Node node) => _nodeMap[node];
131
196 RenderNode({ Object key }) : super(key: key); 132 RenderNode({ Object key }) : super(key: key);
197 133
198 RenderNode get _emptyNode; 134 RenderNode get _emptyNode;
199 135
200 sky.Node _createNode(); 136 sky.Node _createNode();
201 137
202 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) { 138 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) {
203 if (old == null) { 139 if (old == null) {
204 _root = _createNode(); 140 _root = _createNode();
205 _parentInsertBefore(host, _root, insertBefore); 141 _parentInsertBefore(host, _root, insertBefore);
206 old = _emptyNode; 142 old = _emptyNode;
207 } else { 143 } else {
208 _root = old._root; 144 _root = old._root;
209 } 145 }
210 146
147 _nodeMap[_root] = this;
211 _syncNode(old); 148 _syncNode(old);
212 } 149 }
213 150
214 void _syncNode(RenderNode old); 151 void _syncNode(RenderNode old);
215 152
216 void _remove() { 153 void _remove() {
217 assert(_root != null); 154 assert(_root != null);
218 _root.remove(); 155 _root.remove();
156 _nodeMap.remove(_root);
219 super._remove(); 157 super._remove();
220 } 158 }
221 } 159 }
160
161 typedef GestureEventListener(sky.GestureEvent e);
162 typedef PointerEventListener(sky.PointerEvent e);
163 typedef EventListener(sky.Event e);
164
165 class EventTarget extends Node {
166 Node content;
167 final Map<String, sky.EventListener> listeners;
168
169 static final Set<String> _registeredEvents = new HashSet<String>();
170
171 static Map<String, sky.EventListener> _createListeners({
172 EventListener onWheel,
173 GestureEventListener onGestureFlingCancel,
174 GestureEventListener onGestureFlingStart,
175 GestureEventListener onGestureScrollStart,
176 GestureEventListener onGestureScrollUpdate,
177 GestureEventListener onGestureTap,
178 PointerEventListener onPointerCancel,
179 PointerEventListener onPointerDown,
180 PointerEventListener onPointerMove,
181 PointerEventListener onPointerUp,
182 Map<String, sky.EventListener> custom
183 }) {
184 var listeners = custom != null ?
185 new HashMap<String, sky.EventListener>.from(custom) :
186 new HashMap<String, sky.EventListener>();
187
188 if (onWheel != null)
189 listeners['wheel'] = onWheel;
190 if (onGestureFlingCancel != null)
191 listeners['gestureflingcancel'] = onGestureFlingCancel;
192 if (onGestureFlingStart != null)
193 listeners['gestureflingstart'] = onGestureFlingStart;
194 if (onGestureScrollStart != null)
195 listeners['gesturescrollstart'] = onGestureScrollStart;
196 if (onGestureScrollUpdate != null)
197 listeners['gesturescrollupdate'] = onGestureScrollUpdate;
198 if (onGestureTap != null)
199 listeners['gesturetap'] = onGestureTap;
200 if (onPointerCancel != null)
201 listeners['pointercancel'] = onPointerCancel;
202 if (onPointerDown != null)
203 listeners['pointerdown'] = onPointerDown;
204 if (onPointerMove != null)
205 listeners['pointermove'] = onPointerMove;
206 if (onPointerUp != null)
207 listeners['pointerup'] = onPointerUp;
208
209 return listeners;
210 }
211
212 EventTarget(Node content, {
213 EventListener onWheel,
214 GestureEventListener onGestureFlingCancel,
215 GestureEventListener onGestureFlingStart,
216 GestureEventListener onGestureScrollStart,
217 GestureEventListener onGestureScrollUpdate,
218 GestureEventListener onGestureTap,
219 PointerEventListener onPointerCancel,
220 PointerEventListener onPointerDown,
221 PointerEventListener onPointerMove,
222 PointerEventListener onPointerUp,
223 Map<String, sky.EventListener> custom
224 }) : this.content = content,
225 listeners = _createListeners(
226 onWheel: onWheel,
227 onGestureFlingCancel: onGestureFlingCancel,
228 onGestureFlingStart: onGestureFlingStart,
229 onGestureScrollUpdate: onGestureScrollUpdate,
230 onGestureScrollStart: onGestureScrollStart,
231 onGestureTap: onGestureTap,
232 onPointerCancel: onPointerCancel,
233 onPointerDown: onPointerDown,
234 onPointerMove: onPointerMove,
235 onPointerUp: onPointerUp,
236 custom: custom
237 ),
238 super(key: content._key);
239
240 void _handleEvent(sky.Event e) {
241 sky.EventListener listener = listeners[e.type];
242 if (listener != null) {
243 listener(e);
244 }
245 }
246
247 static void _dispatchEvent(sky.Event e) {
248 Node target = RenderNode._getMounted(e.target);
249
250 // TODO(rafaelw): StopPropagation?
251 while (target != null) {
252 if (target is EventTarget) {
253 (target as EventTarget)._handleEvent(e);
254 }
255
256 target = target._parent;
257 }
258 }
259
260 static void _ensureDocumentListener(String eventType) {
261 if (_registeredEvents.add(eventType)) {
262 sky.document.addEventListener(eventType, _dispatchEvent);
263 }
264 }
265
266 void _sync(Node old, sky.ParentNode host, sky.Node insertBefore) {
267 for (var type in listeners.keys) {
268 _ensureDocumentListener(type);
269 }
270
271 Node oldContent = old == null ? null : (old as EventTarget).content;
272 content = _syncChild(content, oldContent , host, insertBefore);
273 _root = content._root;
274 }
275
276 void _remove() {
277 content._remove();
278 super._remove();
279 }
280 }
222 281
223 class Text extends RenderNode { 282 class Text extends RenderNode {
224 final String data; 283 final String data;
225 284
226 // Text nodes are special cases of having non-unique keys (which don't need 285 // Text nodes are special cases of having non-unique keys (which don't need
227 // to be assigned as part of the API). Since they are unique in not having 286 // to be assigned as part of the API). Since they are unique in not having
228 // children, there's little point to reordering, so we always just re-assign 287 // children, there's little point to reordering, so we always just re-assign
229 // the data. 288 // the data.
230 Text(this.data) : super(key:'*text*'); 289 Text(this.data) : super(key:'*text*');
231 290
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 throw '''If multiple (non-Text) nodes of the same type exist as children 351 throw '''If multiple (non-Text) nodes of the same type exist as children
293 of another node, they must have unique keys.'''; 352 of another node, they must have unique keys.''';
294 } 353 }
295 } 354 }
296 } 355 }
297 356
298 void _syncNode(RenderNode old) { 357 void _syncNode(RenderNode old) {
299 Element oldElement = old as Element; 358 Element oldElement = old as Element;
300 sky.Element root = _root as sky.Element; 359 sky.Element root = _root as sky.Element;
301 360
302 _syncEvents(oldElement.events);
303
304 if (_class != oldElement._class) 361 if (_class != oldElement._class)
305 root.setAttribute('class', _class); 362 root.setAttribute('class', _class);
306 363
307 if (inlineStyle != oldElement.inlineStyle) 364 if (inlineStyle != oldElement.inlineStyle)
308 root.setAttribute('style', inlineStyle); 365 root.setAttribute('style', inlineStyle);
309 366
310 _syncChildren(oldElement); 367 _syncChildren(oldElement);
311 } 368 }
312 369
313 void _syncChildren(Element oldElement) { 370 void _syncChildren(Element oldElement) {
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 void _scheduleComponentForRender(Component c) { 631 void _scheduleComponentForRender(Component c) {
575 assert(!_inRenderDirtyComponents); 632 assert(!_inRenderDirtyComponents);
576 _dirtyComponents.add(c); 633 _dirtyComponents.add(c);
577 634
578 if (!_buildScheduled) { 635 if (!_buildScheduled) {
579 _buildScheduled = true; 636 _buildScheduled = true;
580 new Future.microtask(_buildDirtyComponents); 637 new Future.microtask(_buildDirtyComponents);
581 } 638 }
582 } 639 }
583 640
584 EventMap _emptyEventMap = new EventMap();
585
586 abstract class Component extends Node { 641 abstract class Component extends Node {
587 bool get _isBuilding => _currentlyBuilding == this; 642 bool get _isBuilding => _currentlyBuilding == this;
588 bool _dirty = true; 643 bool _dirty = true;
589 644
590 Node _built; 645 Node _built;
591 final int _order; 646 final int _order;
592 static int _currentOrder = 0; 647 static int _currentOrder = 0;
593 bool _stateful; 648 bool _stateful;
594 static Component _currentlyBuilding; 649 static Component _currentlyBuilding;
595 650
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 int lastOrder = _currentOrder; 714 int lastOrder = _currentOrder;
660 _currentOrder = _order; 715 _currentOrder = _order;
661 _currentlyBuilding = this; 716 _currentlyBuilding = this;
662 _built = build(); 717 _built = build();
663 _currentlyBuilding = null; 718 _currentlyBuilding = null;
664 _currentOrder = lastOrder; 719 _currentOrder = lastOrder;
665 720
666 _built = _syncChild(_built, oldBuilt, host, insertBefore); 721 _built = _syncChild(_built, oldBuilt, host, insertBefore);
667 _dirty = false; 722 _dirty = false;
668 _root = _built._root; 723 _root = _built._root;
669
670 _built.events.addAll(events);
671 _syncEvents(oldComponent != null ? oldComponent.events : _emptyEventMap);
672 } 724 }
673 725
674 void _buildIfDirty() { 726 void _buildIfDirty() {
675 if (!_dirty || _defunct) 727 if (!_dirty || _defunct)
676 return; 728 return;
677 729
678 assert(_root != null); 730 assert(_root != null);
679 _sync(null, _root.parentNode, _root.nextSibling); 731 _sync(null, _root.parentNode, _root.nextSibling);
680 } 732 }
681 733
(...skipping 25 matching lines...) Expand all
707 759
708 _sync(null, _host, null); 760 _sync(null, _host, null);
709 assert(_root is sky.Node); 761 assert(_root is sky.Node);
710 762
711 sw.stop(); 763 sw.stop();
712 if (_shouldLogRenderDuration) 764 if (_shouldLogRenderDuration)
713 print("Initial build: ${sw.elapsedMicroseconds} microseconds"); 765 print("Initial build: ${sw.elapsedMicroseconds} microseconds");
714 }); 766 });
715 } 767 }
716 } 768 }
OLDNEW
« no previous file with comments | « sky/framework/components/scrollable.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698