13
0
livetrax/share/web_surfaces/builtin/mixer/toolkit/G.js
2020-07-21 06:49:27 +02:00

219 lines
5.8 KiB
JavaScript

/*
* This file is part of Toolkit.
*
* Toolkit is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* Toolkit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General
* Public License along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
"use strict";
(function(w) {
function Scheduler() {
this.Q_next = this.Q = [];
this.Q_tmp = [];
this.tmp = [];
this.debug = 0;
this.after_frame_cbs = [];
this.frame_count = 0;
this.current_priority = -1;
this.current_cycle = 0;
};
function low_add(Q, o, prio) {
prio = prio << 1;
var q = Q[prio];
var len = Q[prio+1];
if (!q) {
Q[prio] = q = [];
len = 0;
}
q[len++] = o;
Q[prio+1] = len;
}
function low_remove(Q, o, prio) {
prio = prio << 1;
var q = Q[prio];
var len = Q[prio+1]
if (!q) return;
for (var i = 0; i < len; i++) {
if (o !== q[i]) continue;
/* NOTE: this looks odd, but it's correct */
q[i] = null;
q[i] = q[--len];
}
Q[prio+1] = len;
}
function low_has(Q, o, prio) {
prio = prio << 1;
var q = Q[prio];
var len = Q[prio+1];
if (!q) return false;
for (var i = 0; i < len; i++) {
if (o === q[i]) return true;
}
return false;
}
Scheduler.prototype = {
run : function() {
var Q = this.Q;
this.Q_next = this.Q_tmp;
var empty;
var runs = 0;
var debug = this.debug;
var calls = 0;
var t;
var i;
if (debug) t = performance.now();
while (!empty) {
runs++;
this.current_cycle = runs;
if (runs > 20) throw("something is not right");
empty = true;
for (i = 0; i < Q.length; i+=2) {
var q = Q[i];
var len = Q[i+1];
if (!q || !len) continue;
empty = false;
this.current_priority = i>>1;
Q[i] = this.tmp;
Q[i+1] = 0;
this.tmp = q;
for (var j = 0; j < len; j++) {
try { q[j](); } catch (e) {
TK.warn(q[j], "threw an error", e);
}
q[j] = null;
calls++;
}
}
var after_frame_cbs = this.after_frame_cbs;
if (after_frame_cbs.length) {
this.after_frame_cbs = [];
empty = false;
for (i = 0; i < after_frame_cbs.length; i++)
after_frame_cbs[i]();
}
}
this.Q = this.Q_next;
this.Q_tmp = Q;
if (debug) {
t = performance.now() - t;
if (t > debug)
TK.log("DOMScheduler did %d runs and %d calls: %f ms", runs, calls, t);
}
this.running = false;
this.current_priority = -1;
this.frame_count++;
return runs;
},
add : function(o, prio) {
low_add(this.Q, o, prio);
},
add_next : function(o, prio) {
low_add(this.Q_next, o, prio);
},
remove : function(o, prio) {
low_remove(this.Q, o, prio);
},
remove_next : function(o, prio) {
low_remove(this.Q_next, o, prio);
},
has: function(o, prio) {
return low_has(this.Q, o, prio);
},
has_next: function(o, prio) {
return low_has(this.Q_next, o, prio);
},
after_frame: function(fun) {
this.after_frame_cbs.push(fun);
},
get_frame_count: function() {
return this.frame_count;
},
get_current_priority: function() {
return this.current_priority;
},
get_current_cycle: function() {
return this.current_cycle;
},
describe_now: function() {
if (this.running) {
return TK.sprintf("<frame: %d, prio: %d, cycle: %d>",
this.get_frame_count(),
this.get_current_priority(),
this.get_current_cycle());
} else {
return "<not scheduled>";
}
},
};
function DOMScheduler() {
Scheduler.call(this);
this.will_render = false;
this.running = false;
this.bound_run = this.run.bind(this);
};
DOMScheduler.prototype = Object.create(Scheduler.prototype);
DOMScheduler.prototype.add_next = function(o, prio) {
Scheduler.prototype.add_next.call(this, o, prio);
if (this.will_render) return;
this.will_render = true;
if (this.running) return;
window.requestAnimationFrame(this.bound_run);
};
DOMScheduler.prototype.add = function(o, prio) {
Scheduler.prototype.add.call(this, o, prio);
if (this.will_render) return;
if (this.running) return;
this.will_render = true;
window.requestAnimationFrame(this.bound_run);
};
DOMScheduler.prototype.run = function() {
this.will_render = false;
this.running = true;
Scheduler.prototype.run.call(this);
this.running = false;
if (this.will_render)
window.requestAnimationFrame(this.bound_run);
};
DOMScheduler.prototype.after_frame = function(fun) {
Scheduler.prototype.after_frame.call(this, fun);
if (this.will_render) return;
if (this.running) return;
this.will_render = true;
window.requestAnimationFrame(this.bound_run);
};
w.Scheduler = Scheduler;
w.DOMScheduler = DOMScheduler;
})(this);