Index: runtime/observatory/lib/src/elements/helpers/rendering_queue.dart |
diff --git a/runtime/observatory/lib/src/elements/helpers/rendering_queue.dart b/runtime/observatory/lib/src/elements/helpers/rendering_queue.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a6062c38ebd64201b88518d6397e5c505f15d19b |
--- /dev/null |
+++ b/runtime/observatory/lib/src/elements/helpers/rendering_queue.dart |
@@ -0,0 +1,72 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+import 'dart:html'; |
+import 'dart:collection'; |
+import 'dart:async'; |
+ |
+/// A generic rendering task that can be scheduled. |
+abstract class RenderingTask { |
+ /// Rendering synchronous callback. |
+ void render(); |
+} |
+ |
+/// A generic synchronization system for rendering operations. |
+abstract class RenderingBarrier { |
+ /// Future to the next synchronization barrier (ms from application start). |
+ Future<num> get next; |
+} |
+ |
+/// Synchronization system based on the AnimationFrame. |
+class NextAnimationFrameBarrier implements RenderingBarrier { |
+ Future<num> get next => window.animationFrame; |
+} |
+ |
+/// MOCK synchronization system for manual barrier triggering. |
+class RenderingBarrierMock implements RenderingBarrier { |
+ final StreamController<num> _stream = new StreamController<num>.broadcast(); |
+ num _ms = 0; |
+ |
+ Future<num> get next => _stream.stream.first; |
+ |
+ /// Trigger the next barrier with an optional numer of ms elapsed. |
+ void triggerRenderingBarrier({num step: 20}) { |
+ assert(step != null); |
+ _stream.add(_ms += step); |
+ } |
+} |
+ |
+/// RenderingTask queuing and synchronization system. |
+class RenderingQueue { |
+ final RenderingBarrier _barrier; |
+ final Queue<RenderingTask> _queue = new Queue<RenderingTask>(); |
+ |
+ bool get isEmpty => _queue.isEmpty; |
+ bool get isNotEmpty => _queue.isNotEmpty; |
+ |
+ /// Creates a RenderingQueue with the default synchronization barrier. |
+ RenderingQueue() : this.fromBarrier(new NextAnimationFrameBarrier()); |
+ |
+ /// Creates a RenderingQueue with a custom synchronization barrier. |
+ RenderingQueue.fromBarrier(this._barrier) { |
+ assert(this._barrier != null); |
+ } |
+ |
+ /// Add a task to the queue. |
+ /// If the current rendering phase is running it will be executed during this |
+ /// rendering cycle, otherwise it will be queued for the next one. |
+ void enqueue(RenderingTask r) { |
+ assert(r != null); |
+ // If no task are in the queue there is no rendering phase scheduled. |
+ if (isEmpty) _render(); |
+ _queue.addLast(r); |
+ } |
+ |
+ Future _render() async { |
+ await _barrier.next; |
+ while (_queue.isNotEmpty) { |
+ _queue.removeFirst().render(); |
+ } |
+ } |
+} |