let canvas_element = "";
let ctx = null;
+let canvas_op_buffer = [];
function update_canvas_data() {
let canvas_data = new Int32Array(canvas_shared_buffer);
Atomics.notify(canvas_data, 2);
}
+function canvas_buffer_flush() {
+ canvas_op_buffer.sort((a, b) => a[0] - b[0]);
+
+ for (let op of canvas_op_buffer) {
+ canvas_process(op);
+ }
+
+ canvas_op_buffer = [];
+}
+
function canvas_handler(instr) {
- switch (instr[0]) {
+ if (instr[1] == 'sync' || instr[1] == 'init') {
+ canvas_process(instr);
+ } else {
+ canvas_op_buffer.push(instr);
+ }
+}
+
+function canvas_process(instr) {
+ switch (instr[1]) {
case 'init': {
canvas_element = document.getElementById("render-target");
ctx = canvas_element.getContext('2d');
case 'sync': {
window.requestAnimationFrame(() => {
+ canvas_buffer_flush();
let canvas_data = new Int32Array(canvas_shared_buffer);
Atomics.store(canvas_data, 2, 1);
Atomics.notify(canvas_data, 2);
break;
}
- case 'fill_style': ctx.fillStyle = instr[1]; break;
- case 'font': ctx.font = instr[1]; break;
- case 'image_smoothing_enabled': ctx.imageSmoothingEnabled = instr[1]; break;
- case 'line_join': ctx.lineJoin = instr[1]; break;
- case 'line_width': ctx.lineWidth = instr[1]; break;
- case 'stroke_style': ctx.strokeStyle = instr[1]; break;
- case 'text_align': ctx.textAlign = instr[1]; break;
+ case 'fill_style': ctx.fillStyle = instr[2]; break;
+ case 'font': ctx.font = instr[2]; break;
+ case 'image_smoothing_enabled': ctx.imageSmoothingEnabled = instr[2]; break;
+ case 'line_join': ctx.lineJoin = instr[2]; break;
+ case 'line_width': ctx.lineWidth = instr[2]; break;
+ case 'stroke_style': ctx.strokeStyle = instr[2]; break;
+ case 'text_align': ctx.textAlign = instr[2]; break;
- case 'arc': ctx.arc(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6]); break;
- case 'arc_to': ctx.arcTo(instr[1], instr[2], instr[3], instr[4], instr[5]); break;
+ case 'arc': ctx.arc(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7]); break;
+ case 'arc_to': ctx.arcTo(instr[2], instr[3], instr[4], instr[5], instr[6]); break;
case 'begin_path': ctx.beginPath(); break;
case 'clear': ctx.clearRect(0, 0, canvas_element.width, canvas_element.height); break;
- case 'clear_rect': ctx.clearRect(instr[1], instr[2], instr[3], instr[4]); break;
- case 'clip': ctx.clip(instr[1]); break;
+ case 'clear_rect': ctx.clearRect(instr[2], instr[3], instr[4], instr[5]); break;
+ case 'clip': ctx.clip(instr[2]); break;
case 'close_path': ctx.closePath(); break;
- case 'ellipse': ctx.ellipse(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6], instr[7], instr[8]); break;
- case 'fill': ctx.fill(instr[1]); break;
- case 'fill_rect': ctx.fillRect(instr[1], instr[2], instr[3], instr[4]); break;
- case 'fill_text': ctx.fillText(instr[1], instr[2], instr[3], instr[4]); break;
- case 'line_to': ctx.lineTo(instr[1], instr[2]); break;
- case 'move_to': ctx.moveTo(instr[1], instr[2]); break;
- case 'quadratic_curve_to': ctx.quadraticCurveTo(instr[1], instr[2], instr[3], instr[4]); break;
- case 'rect': ctx.rect(instr[1], instr[2], instr[3], instr[4]); break;
- case 'rotate': ctx.rotate(instr[1]); break;
+ case 'ellipse': ctx.ellipse(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7], instr[8], instr[9]); break;
+ case 'fill': ctx.fill(instr[2]); break;
+ case 'fill_rect': ctx.fillRect(instr[2], instr[3], instr[4], instr[5]); break;
+ case 'fill_text': ctx.fillText(instr[2], instr[3], instr[4], instr[5]); break;
+ case 'line_to': ctx.lineTo(instr[2], instr[3]); break;
+ case 'move_to': ctx.moveTo(instr[2], instr[3]); break;
+ case 'quadratic_curve_to': ctx.quadraticCurveTo(instr[2], instr[3], instr[4], instr[5]); break;
+ case 'rect': ctx.rect(instr[2], instr[3], instr[4], instr[5]); break;
+ case 'rotate': ctx.rotate(instr[2]); break;
case 'save': ctx.save(); break;
- case 'scale': ctx.scale(instr[1], instr[2]); break;
- case 'set_transform': ctx.setTransform(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6]); break;
+ case 'scale': ctx.scale(instr[2], instr[3]); break;
+ case 'set_transform': ctx.setTransform(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7]); break;
case 'stroke': ctx.stroke(); break;
- case 'stroke_rect': ctx.strokeRect(instr[1], instr[2], instr[3], instr[4]); break;
- case 'stroke_text': ctx.strokeText(instr[1], instr[2], instr[3], instr[4]); break;
- case 'transform': ctx.transform(instr[1], instr[2], instr[3], instr[4], instr[5], instr[6]); break;
- case 'translate': ctx.translate(instr[1], instr[2]); break;
+ case 'stroke_rect': ctx.strokeRect(instr[2], instr[3], instr[4], instr[5]); break;
+ case 'stroke_text': ctx.strokeText(instr[2], instr[3], instr[4], instr[5]); break;
+ case 'transform': ctx.transform(instr[2], instr[3], instr[4], instr[5], instr[6], instr[7]); break;
+ case 'translate': ctx.translate(instr[2], instr[3]); break;
}
}
return new TextDecoder().decode(strdata);
}
+let canvas_order_id = 0;
+
let import_obj = {
host: {
print_str(strptr, strlen) {
canvas: {
init() {
- self.postMessage({ type: 'canvas', data: [ 'init' ] });
+ self.postMessage({ type: 'canvas', data: [ 0, 'init' ] });
+ canvas_order_id = 0;
// Issue a synchronization because the data needs to be correct
// before control should be handed back to the running program.
},
sync() {
- self.postMessage({ type: 'canvas', data: [ 'sync'] });
+ self.postMessage({ type: 'canvas', data: [ 0, 'sync'] });
let canvas_data = new Int32Array(canvas_data_buffer);
Atomics.wait(canvas_data, 2, 0);
},
// Settings
- fill_style(styleptr, stylelen) { self.postMessage({ type: 'canvas', data: [ 'fill_style', S(styleptr, stylelen) ] }); },
- font(p, l) { self.postMessage({ type: 'canvas', data: [ 'font', S(p, l) ] }); },
- image_smoothing_enabled(e) { self.postMessage({ type: 'canvas', data: [ 'image_smoothing_enabled', e != 0 ] }); },
+ fill_style(styleptr, stylelen) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill_style', S(styleptr, stylelen) ] }); },
+ font(p, l) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'font', S(p, l) ] }); },
+ image_smoothing_enabled(e) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'image_smoothing_enabled', e != 0 ] }); },
line_join(join) {
let method = "";
switch (join) {
}
if (method != "") {
- self.postMessage({ type: 'canvas', data: [ 'line_join' , method ] });
+ self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'line_join' , method ] });
}
},
- line_width(width) { self.postMessage({ type: 'canvas', data: [ 'line_width', width ] }); },
- stroke_style(s, l) { self.postMessage({ type: 'canvas', data: [ 'stroke_style', S(s, l) ] }); },
+ line_width(width) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'line_width', width ] }); },
+ stroke_style(s, l) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke_style', S(s, l) ] }); },
text_align(align) {
let method = "";
switch (align) {
}
if (method != "") {
- self.postMessage({ type: 'canvas', data: [ 'text_align' , method ] });
+ self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'text_align' , method ] });
}
},
// Drawing
- arc(x, y, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ 'arc', x, y, r, sa, ea, cc != 0 ] }); },
- arc_to(x1, y1, x2, y2, r) { self.postMessage({ type: 'canvas', data: [ 'arc_to', x1, y1, x2, y2, r ] }); },
- begin_path() { self.postMessage({ type: 'canvas', data: [ 'begin_path' ] }); },
- clear() { self.postMessage({ type: 'canvas', data: [ 'clear' ] }); },
- clear_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'clear_rect', x, y, w, h ] }); },
+ arc(x, y, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'arc', x, y, r, sa, ea, cc != 0 ] }); },
+ arc_to(x1, y1, x2, y2, r) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'arc_to', x1, y1, x2, y2, r ] }); },
+ begin_path() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'begin_path' ] }); },
+ clear() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'clear' ] }); },
+ clear_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'clear_rect', x, y, w, h ] }); },
clip(cliprule) {
let method = "";
switch (cliprule) {
}
if (method != "") {
- self.postMessage({ type: 'canvas', data: [ 'clip', method ] });
+ self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'clip', method ] });
}
},
- close_path() { self.postMessage({ type: 'canvas', data: [ 'close_path' ] }); },
- ellipse(x, y, rx, ry, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ 'ellipse', x, y, rx, ry, r, sa, ea, cc != 0 ] }); },
+ close_path() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'close_path' ] }); },
+ ellipse(x, y, rx, ry, r, sa, ea, cc) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'ellipse', x, y, rx, ry, r, sa, ea, cc != 0 ] }); },
fill(fillrule) {
let method = "";
switch (fillrule) {
}
if (method != "") {
- self.postMessage({ type: 'canvas', data: [ 'fill', method ] });
+ self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill', method ] });
}
},
- fill_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'fill_rect', x, y, w, h ] }); },
+ fill_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill_rect', x, y, w, h ] }); },
fill_text(textptr, textlen, x, y, max_width) {
- self.postMessage({ type: 'canvas', data: [ 'fill_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] });
+ self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'fill_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] });
},
- line_to(x, y) { self.postMessage({ type: 'canvas', data: [ 'line_to', x, y ] }); },
- move_to(x, y) { self.postMessage({ type: 'canvas', data: [ 'move_to', x, y ] }); },
- quadratic_curve_to(cpx, cpy, x, y) { self.postMessage({ type: 'canvas', data: [ 'quadratic_curve_to', cpx, cpy, x, y ] }); },
- rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'rect', x, y, w, h ] }); },
- restore() { self.postMessage({ type: 'canvas', data: [ 'restore' ] }); },
- rotate(angle) { self.postMessage({ type: 'canvas', data: [ 'rotate', angle ] }); },
- save() { self.postMessage({ type: 'canvas', data: [ 'save' ] }); },
- scale(x, y) { self.postMessage({ type: 'canvas', data: [ 'scale', x, y ] }); },
- set_transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ 'set_transform', a, b, c, d, e, f ] }); },
- stroke() { self.postMessage({ type: 'canvas', data: [ 'stroke' ] }); },
- stroke_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ 'stroke_rect', x, y, w, h ] }); },
- stroke_text(textptr, textlen, x, y, max_width) { self.postMessage({ type: 'canvas', data: [ 'stroke_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] }); },
- transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ 'transform', a, b, c, d, e, f ] }); },
- translate(x, y) { self.postMessage({ type: 'canvas', data: [ 'translate', x, y ] }); },
+ line_to(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'line_to', x, y ] }); },
+ move_to(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'move_to', x, y ] }); },
+ quadratic_curve_to(cpx, cpy, x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'quadratic_curve_to', cpx, cpy, x, y ] }); },
+ rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'rect', x, y, w, h ] }); },
+ restore() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'restore' ] }); },
+ rotate(angle) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'rotate', angle ] }); },
+ save() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'save' ] }); },
+ scale(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'scale', x, y ] }); },
+ set_transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'set_transform', a, b, c, d, e, f ] }); },
+ stroke() { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke' ] }); },
+ stroke_rect(x, y, w, h) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke_rect', x, y, w, h ] }); },
+ stroke_text(textptr, textlen, x, y, max_width) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'stroke_text', S(textptr, textlen), x, y, max_width > 0 ? max_width : null ] }); },
+ transform(a, b, c, d, e, f) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'transform', a, b, c, d, e, f ] }); },
+ translate(x, y) { self.postMessage({ type: 'canvas', data: [ canvas_order_id++, 'translate', x, y ] }); },
}
};
self.postMessage({ type: 'errored', data: e.toString() });
}
+ self.postMessage({ type: 'canvas', data: [ 0, 'sync' ] });
self.postMessage({ type: 'terminated' });
self.close();
});
}
case 'stop':
+ self.postMessage({ type: 'canvas', data: [ 0, 'sync' ] });
self.postMessage({ type: 'terminated' });
self.close();
break;