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

Side by Side Diff: tools/dom/src/Microtask.dart

Issue 12087004: Changing window.requestLayoutFrame into a microtask API (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of html;
6
7 typedef void _MicrotaskCallback();
8
9 /**
10 * This class attempts to invoke a callback as soon as the current event stack
11 * unwinds, but before the browser repaints.
12 */
13 abstract class _MicrotaskScheduler {
14 bool _nextMicrotaskFrameScheduled = false;
15 _MicrotaskCallback _callback;
16
17 _MicrotaskScheduler(this._callback);
18
19 /**
20 * Creates the best possible measurement scheduler for the current platform.
21 */
22 factory _MicrotaskScheduler.best(_MicrotaskCallback callback) {
23 if (Window._supportsSetImmediate) {
24 return new _SetImmediateScheduler(callback);
25 } else if (MutationObserver.supported) {
26 return new _MutationObserverScheduler(callback);
27 }
28 return new _PostMessageScheduler(callback);
29 }
30
31 /**
32 * Schedules a measurement callback if one has not been scheduled already.
33 */
34 void maybeSchedule() {
35 if (this._nextMicrotaskFrameScheduled) {
36 return;
37 }
38 this._nextMicrotaskFrameScheduled = true;
39 this._schedule();
40 }
41
42 /**
43 * Does the actual scheduling of the callback.
44 */
45 void _schedule();
46
47 /**
48 * Handles the measurement callback and forwards it if necessary.
49 */
50 void _onCallback() {
51 // Ignore spurious messages.
52 if (!_nextMicrotaskFrameScheduled) {
53 return;
54 }
55 _nextMicrotaskFrameScheduled = false;
56 this._callback();
57 }
58 }
59
60 /**
61 * Scheduler which uses window.postMessage to schedule events.
62 */
63 class _PostMessageScheduler extends _MicrotaskScheduler {
64 const _MEASUREMENT_MESSAGE = "DART-MEASURE";
65
66 _PostMessageScheduler(_MicrotaskCallback callback): super(callback) {
67 // Messages from other windows do not cause a security risk as
68 // all we care about is that _handleMessage is called
69 // after the current event loop is unwound and calling the function is
70 // a noop when zero requests are pending.
71 window.onMessage.listen(this._handleMessage);
72 }
73
74 void _schedule() {
75 window.postMessage(_MEASUREMENT_MESSAGE, "*");
76 }
77
78 void _handleMessage(e) {
79 this._onCallback();
80 }
81 }
82
83 /**
84 * Scheduler which uses a MutationObserver to schedule events.
85 */
86 class _MutationObserverScheduler extends _MicrotaskScheduler {
87 MutationObserver _observer;
88 Element _dummy;
89
90 _MutationObserverScheduler(_MicrotaskCallback callback): super(callback) {
91 // Mutation events get fired as soon as the current event stack is unwound
92 // so we just make a dummy event and listen for that.
93 _observer = new MutationObserver(this._handleMutation);
94 _dummy = new DivElement();
95 _observer.observe(_dummy, attributes: true);
96 }
97
98 void _schedule() {
99 // Toggle it to trigger the mutation event.
100 _dummy.hidden = !_dummy.hidden;
101 }
102
103 _handleMutation(List<MutationRecord> mutations, MutationObserver observer) {
104 this._onCallback();
105 }
106 }
107
108 /**
109 * Scheduler which uses window.setImmediate to schedule events.
110 */
111 class _SetImmediateScheduler extends _MicrotaskScheduler {
112 _SetImmediateScheduler(_MicrotaskCallback callback): super(callback);
113
114 void _schedule() {
115 window._setImmediate(_handleImmediate);
116 }
117
118 void _handleImmediate() {
119 this._onCallback();
120 }
121 }
122
123 List<TimeoutHandler> _pendingMicrotasks;
124 _MicrotaskScheduler _microtaskScheduler = null;
125
126 void _maybeScheduleMicrotaskFrame() {
127 if (_microtaskScheduler == null) {
128 _microtaskScheduler =
129 new _MicrotaskScheduler.best(_completeMicrotasks);
130 }
131 _microtaskScheduler.maybeSchedule();
132 }
133
134 /**
135 * Registers a [callback] which is called after the next batch of measurements
136 * completes. Even if no measurements completed, the callback is triggered
137 * when they would have completed to avoid confusing bugs if it happened that
138 * no measurements were actually requested.
139 */
140 void _addMicrotaskCallback(TimeoutHandler callback) {
141 if (_pendingMicrotasks == null) {
142 _pendingMicrotasks = <TimeoutHandler>[];
143 _maybeScheduleMicrotaskFrame();
144 }
145 _pendingMicrotasks.add(callback);
146 }
147
148
149 /**
150 * Complete all pending measurement futures evaluating them in a single batch
151 * so that the the browser is guaranteed to avoid multiple layouts.
152 */
153 void _completeMicrotasks() {
154 var callbacks = _pendingMicrotasks;
155 _pendingMicrotasks = null;
156 for (var callback in callbacks) {
157 callback();
158 }
159 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698