1 /**
  2  * Copyright (C) 2010-2014 KO GmbH <copyright@kogmbh.com>
  3  *
  4  * @licstart
  5  * This file is part of WebODF.
  6  *
  7  * WebODF is free software: you can redistribute it and/or modify it
  8  * under the terms of the GNU Affero General Public License (GNU AGPL)
  9  * as published by the Free Software Foundation, either version 3 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * WebODF is distributed in the hope that it will be useful, but
 13  * WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU Affero General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Affero General Public License
 18  * along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 19  * @licend
 20  *
 21  * @source: http://www.webodf.org/
 22  * @source: https://github.com/kogmbh/WebODF/
 23  */
 24 
 25 /*global core, runtime*/
 26 
 27 (function() {
 28     "use strict";
 29     /** @type {!RedrawTasks} */
 30     var redrawTasks;
 31 
 32     /**
 33      * FF doesn't execute requestAnimationFrame requests before it's next repaint,
 34      * causing flickering when performing some types of updates (e.g., recomputing Style2CSS).
 35      * To workaround this, sometimes we force animation callbacks to redraw ourselves
 36      * at certain points.
 37      *
 38      * This object collects animation frame requests and provides
 39      * a safe way of executing any outstanding requests
 40      *
 41      * @constructor
 42      */
 43     function RedrawTasks() {
 44         var callbacks = {};
 45 
 46         /**
 47          * Schedule a callback to be invoked on the next animation frame, or
 48          * when performRedraw is called.
 49          *
 50          * @param {!function():undefined} callback
 51          * @return {!number}
 52          */
 53         this.requestRedrawTask = function(callback) {
 54             var id = runtime.requestAnimationFrame(function() {
 55                 callback();
 56                 delete callbacks[id];
 57             });
 58             callbacks[id] = callback;
 59             return id;
 60         };
 61 
 62         /**
 63          * Execute any pending animation frame callbacks and cancel their
 64          * browser animation frame request.
 65          *
 66          * @return {undefined}
 67          */
 68         this.performRedraw = function() {
 69             Object.keys(callbacks).forEach(function(id) {
 70                 callbacks[id]();
 71                 runtime.cancelAnimationFrame(parseInt(id, 10));
 72             });
 73             callbacks = {};
 74         };
 75 
 76         /**
 77          * Cancel a pending animation frame callback
 78          * @param {!number} id
 79          * @return {undefined}
 80          */
 81         this.cancelRedrawTask = function(id) {
 82             runtime.cancelAnimationFrame(id);
 83             delete callbacks[id];
 84         };
 85     }
 86 
 87     /**
 88      * @type {!Object}
 89      */
 90     core.Task =  {};
 91 
 92     /**
 93      * Disable manually processing of tasks when core.Task.processTasks is called.
 94      * This is only used during benchmarks to prevent caret redraws from skewing
 95      * the resulting numbers
 96      * @type {!boolean}
 97      */
 98     core.Task.SUPPRESS_MANUAL_PROCESSING = false;
 99 
100     /**
101      * Process any outstanding redraw tasks that may be queued up
102      * waiting for an animation frame
103      * 
104      * @return {undefined}
105      */
106     core.Task.processTasks = function() {
107         if (!core.Task.SUPPRESS_MANUAL_PROCESSING) {
108             redrawTasks.performRedraw();
109         }
110     };
111 
112     /**
113      * Creates a new task that will execute the specified callback once
114      * when redrawing the next animation frame. Triggering the task multiple
115      * times before the execution occurs will still only result in a single
116      * call being made.
117      *
118      * @param {!Function} callback
119      * @return {!core.ScheduledTask}
120      */
121     core.Task.createRedrawTask = function (callback) {
122         return new core.ScheduledTask(callback,
123             redrawTasks.requestRedrawTask,
124             redrawTasks.cancelRedrawTask
125         );
126     };
127 
128     /**
129      * Creates a new task that will execute the specified callback once
130      * within the specified delay period. Triggering the task multiple
131      * times before the execution occurs will still only result in a single
132      * call being made.
133      *
134      * @param {!Function} callback
135      * @param {!number} delay
136      * @return {!core.ScheduledTask}
137      */
138     core.Task.createTimeoutTask = function (callback, delay) {
139         return new core.ScheduledTask(callback,
140             function(callback) {
141                 return runtime.setTimeout(callback, delay);
142             },
143             runtime.clearTimeout
144         );
145     };
146 
147     function init() {
148         redrawTasks = new RedrawTasks();
149     }
150     init();
151 }());