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

Side by Side Diff: sdk/lib/html/src/Measurement.dart

Issue 11691009: Moved most of html lib generating scripts into tools. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 11 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
« no previous file with comments | « sdk/lib/html/src/KeyboardEventController.dart ('k') | sdk/lib/html/src/ReadyState.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 (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 Object ComputeValue();
8
9 class _MeasurementRequest<T> {
10 final ComputeValue computeValue;
11 final Completer<T> completer;
12 Object value;
13 bool exception = false;
14 _MeasurementRequest(this.computeValue, this.completer);
15 }
16
17 typedef void _MeasurementCallback();
18
19 /**
20 * This class attempts to invoke a callback as soon as the current event stack
21 * unwinds, but before the browser repaints.
22 */
23 abstract class _MeasurementScheduler {
24 bool _nextMeasurementFrameScheduled = false;
25 _MeasurementCallback _callback;
26
27 _MeasurementScheduler(this._callback);
28
29 /**
30 * Creates the best possible measurement scheduler for the current platform.
31 */
32 factory _MeasurementScheduler.best(_MeasurementCallback callback) {
33 if (MutationObserver.supported) {
34 return new _MutationObserverScheduler(callback);
35 }
36 return new _PostMessageScheduler(callback);
37 }
38
39 /**
40 * Schedules a measurement callback if one has not been scheduled already.
41 */
42 void maybeSchedule() {
43 if (this._nextMeasurementFrameScheduled) {
44 return;
45 }
46 this._nextMeasurementFrameScheduled = true;
47 this._schedule();
48 }
49
50 /**
51 * Does the actual scheduling of the callback.
52 */
53 void _schedule();
54
55 /**
56 * Handles the measurement callback and forwards it if necessary.
57 */
58 void _onCallback() {
59 // Ignore spurious messages.
60 if (!_nextMeasurementFrameScheduled) {
61 return;
62 }
63 _nextMeasurementFrameScheduled = false;
64 this._callback();
65 }
66 }
67
68 /**
69 * Scheduler which uses window.postMessage to schedule events.
70 */
71 class _PostMessageScheduler extends _MeasurementScheduler {
72 const _MEASUREMENT_MESSAGE = "DART-MEASURE";
73
74 _PostMessageScheduler(_MeasurementCallback callback): super(callback) {
75 // Messages from other windows do not cause a security risk as
76 // all we care about is that _handleMessage is called
77 // after the current event loop is unwound and calling the function is
78 // a noop when zero requests are pending.
79 window.on.message.add(this._handleMessage);
80 }
81
82 void _schedule() {
83 window.postMessage(_MEASUREMENT_MESSAGE, "*");
84 }
85
86 _handleMessage(e) {
87 this._onCallback();
88 }
89 }
90
91 /**
92 * Scheduler which uses a MutationObserver to schedule events.
93 */
94 class _MutationObserverScheduler extends _MeasurementScheduler {
95 MutationObserver _observer;
96 Element _dummy;
97
98 _MutationObserverScheduler(_MeasurementCallback callback): super(callback) {
99 // Mutation events get fired as soon as the current event stack is unwound
100 // so we just make a dummy event and listen for that.
101 _observer = new MutationObserver(this._handleMutation);
102 _dummy = new DivElement();
103 _observer.observe(_dummy, attributes: true);
104 }
105
106 void _schedule() {
107 // Toggle it to trigger the mutation event.
108 _dummy.hidden = !_dummy.hidden;
109 }
110
111 _handleMutation(List<MutationRecord> mutations, MutationObserver observer) {
112 this._onCallback();
113 }
114 }
115
116
117 List<_MeasurementRequest> _pendingRequests;
118 List<TimeoutHandler> _pendingMeasurementFrameCallbacks;
119 _MeasurementScheduler _measurementScheduler = null;
120
121 void _maybeScheduleMeasurementFrame() {
122 if (_measurementScheduler == null) {
123 _measurementScheduler =
124 new _MeasurementScheduler.best(_completeMeasurementFutures);
125 }
126 _measurementScheduler.maybeSchedule();
127 }
128
129 /**
130 * Registers a [callback] which is called after the next batch of measurements
131 * completes. Even if no measurements completed, the callback is triggered
132 * when they would have completed to avoid confusing bugs if it happened that
133 * no measurements were actually requested.
134 */
135 void _addMeasurementFrameCallback(TimeoutHandler callback) {
136 if (_pendingMeasurementFrameCallbacks == null) {
137 _pendingMeasurementFrameCallbacks = <TimeoutHandler>[];
138 _maybeScheduleMeasurementFrame();
139 }
140 _pendingMeasurementFrameCallbacks.add(callback);
141 }
142
143 /**
144 * Returns a [Future] whose value will be the result of evaluating
145 * [computeValue] during the next safe measurement interval.
146 * The next safe measurement interval is after the current event loop has
147 * unwound but before the browser has rendered the page.
148 * It is important that the [computeValue] function only queries the html
149 * layout and html in any way.
150 */
151 Future _createMeasurementFuture(ComputeValue computeValue,
152 Completer completer) {
153 if (_pendingRequests == null) {
154 _pendingRequests = <_MeasurementRequest>[];
155 _maybeScheduleMeasurementFrame();
156 }
157 _pendingRequests.add(new _MeasurementRequest(computeValue, completer));
158 return completer.future;
159 }
160
161 /**
162 * Complete all pending measurement futures evaluating them in a single batch
163 * so that the the browser is guaranteed to avoid multiple layouts.
164 */
165 void _completeMeasurementFutures() {
166 // We must compute all new values before fulfilling the futures as
167 // the onComplete callbacks for the futures could modify the DOM making
168 // subsequent measurement calculations expensive to compute.
169 if (_pendingRequests != null) {
170 for (_MeasurementRequest request in _pendingRequests) {
171 try {
172 request.value = request.computeValue();
173 } catch (e) {
174 request.value = e;
175 request.exception = true;
176 }
177 }
178 }
179
180 final completedRequests = _pendingRequests;
181 final readyMeasurementFrameCallbacks = _pendingMeasurementFrameCallbacks;
182 _pendingRequests = null;
183 _pendingMeasurementFrameCallbacks = null;
184 if (completedRequests != null) {
185 for (_MeasurementRequest request in completedRequests) {
186 if (request.exception) {
187 request.completer.completeException(request.value);
188 } else {
189 request.completer.complete(request.value);
190 }
191 }
192 }
193
194 if (readyMeasurementFrameCallbacks != null) {
195 for (TimeoutHandler handler in readyMeasurementFrameCallbacks) {
196 // TODO(jacobr): wrap each call to a handler in a try-catch block.
197 handler();
198 }
199 }
200 }
OLDNEW
« no previous file with comments | « sdk/lib/html/src/KeyboardEventController.dart ('k') | sdk/lib/html/src/ReadyState.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698