aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler.js1
-rw-r--r--src/intertyper.js147
-rw-r--r--src/jsifier.js5
-rw-r--r--src/library_fs.js34
-rw-r--r--src/library_gl.js6
-rw-r--r--src/library_glut.js37
-rw-r--r--src/library_sdl.js2
-rw-r--r--src/preamble.js25
-rw-r--r--src/proxyClient.js10
9 files changed, 169 insertions, 98 deletions
diff --git a/src/compiler.js b/src/compiler.js
index d490f454..ac1b0ec8 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -318,4 +318,5 @@ if (ll_file) {
//var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] });
//printErr(dump(M.slice(M.length-10)));
+//printErr('hits: ' + hits);
diff --git a/src/intertyper.js b/src/intertyper.js
index 781c8187..9414a1d4 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -6,12 +6,12 @@
var fastPaths = 0, slowPaths = 0;
var tokenCache = {};
-['=', 'i32', 'label', ';', '4', '0', '1', '2', '255', 'align', 'i8*', 'i8', 'i16', 'getelementptr', 'inbounds', 'unnamed_addr', 'x', 'load', 'preds', 'br', 'i32*', 'i1', 'store', '<label>', 'constant', 'c', 'private', 'null', 'internal', 'to', 'bitcast', 'define', 'nounwind', 'nocapture', '%this', 'call', '...'].forEach(function(text) { tokenCache[text] = { text: text } });
+[',', 'i32', 'label', ';', '4', '0', '1', '2', '255', 'align', 'i8*', 'i8', 'i16', 'getelementptr', 'inbounds', 'unnamed_addr', 'x', 'load', 'preds', 'br', 'i32*', 'i1', 'store', '<label>', 'constant', 'c', 'private', 'null', 'internal', 'to', 'bitcast', 'define', 'nounwind', 'nocapture', '%this', 'call', '...'].forEach(function(text) { tokenCache[text] = { text: text } });
//var tokenCacheMisses = {};
// Line tokenizer
-function tokenize(text, lineNum) {
+function tokenize(text, lineNum, indent) {
var tokens = [];
var quotes = 0;
var lastToken = null;
@@ -63,12 +63,7 @@ function tokenize(text, lineNum) {
tokens.splice(openBrace, tokens.length-openBrace+1);
tokens.push(token);
token.type = '{';
- token.text = '{ ' + token.text + ' }';
- var pointingLevelsToAdd = pointingLevels(text) - pointingLevels(token.text);
- while (pointingLevelsToAdd > 0) {
- token.text += '*';
- pointingLevelsToAdd--;
- }
+ token.text = '{ ' + token.text + ' ' + text;
lastToken = token;
} else {
tokens.push(token);
@@ -82,78 +77,67 @@ function tokenize(text, lineNum) {
segments.pop();
var len = segments.length;
var i = -1;
- var curr = '';
+ var start = 0;
var segment, letter;
for (var s = 0; s < len; s++) {
segment = segments[s];
i += segment.length + 1;
letter = lineText[i];
- curr += segment;
switch (letter) {
case ' ':
if (totalEnclosing == 0 && quotes == 0) {
- makeToken(curr);
- curr = '';
+ makeToken(lineText.substring(start, i));
+ start = i+1;
} else {
- curr += ' ';
}
break;
case '"':
if (totalEnclosing == 0) {
if (quotes == 0) {
- if (curr == '@' || curr == '%') {
- curr += '"';
+ if (start === i-1 && (lineText[start] == '@' || lineText[start] == '%')) {
} else {
- makeToken(curr);
- curr = '"';
+ makeToken(lineText.substring(start, i));
+ start = i;
}
} else {
- makeToken(curr + '"');
- curr = '';
+ makeToken(lineText.substring(start, i+1));
+ start = i+1;
}
- } else {
- curr += '"';
}
quotes = 1-quotes;
break;
case ',':
if (totalEnclosing == 0 && quotes == 0) {
- makeToken(curr);
- curr = '';
- tokens.push({ text: ',' });
- } else {
- curr += ',';
+ makeToken(lineText.substring(start, i));
+ start = i+1;
+ tokens.push(tokenCache[',']);
}
break;
default:
assert(letter in enclosers);
if (quotes) {
- curr += letter;
break;
}
if (letter in ENCLOSER_STARTERS) {
if (totalEnclosing == 0) {
- makeToken(curr);
- curr = '';
+ makeToken(lineText.substring(start, i));
+ start = i;
}
- curr += letter;
enclosers[letter]++;
totalEnclosing++;
} else {
enclosers[enclosers[letter]]--;
totalEnclosing--;
if (totalEnclosing == 0) {
- makeToken(curr + letter);
- curr = '';
- } else {
- curr += letter;
+ makeToken(lineText.substring(start, i+1));
+ start = i+1;
}
}
}
}
var newItem = {
tokens: tokens,
- indent: lineText.search(/[^ ]/),
+ indent: indent || lineText.search(/[^ ]/),
lineNum: lineNum || 0
};
return newItem;
@@ -291,10 +275,6 @@ function intertyper(lines, sidePass, baseLineNums) {
function triager(item) {
assert(!item.intertype);
- if (item.indent == 2 && (eq = findTokenText(item, '=')) >= 0) {
- item.assignTo = toNiceIdent(combineTokens(item.tokens.slice(0, eq)).text);
- item.tokens = item.tokens.slice(eq+1);
- }
var token0Text = item.tokens[0].text;
var token1Text = item.tokens[1] ? item.tokens[1].text : null;
var tokensLength = item.tokens.length;
@@ -345,7 +325,7 @@ function intertyper(lines, sidePass, baseLineNums) {
return labelHandler(item);
if (tokensLength >= 4 && token0Text == 'declare')
return externalHandler(item);
- if (tokensLength >= 3 && token1Text == '=')
+ if (item.assignTo)
return globalHandler(item);
if (tokensLength >= 4 && token0Text == 'define' &&
item.tokens.slice(-1)[0].text == '{')
@@ -458,15 +438,15 @@ function intertyper(lines, sidePass, baseLineNums) {
}
}
- cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 2);
- if (item.tokens[2].text == 'alias') {
- cleanOutTokens(LLVM.LINKAGES, item.tokens, 3);
- cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 3);
+ cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 0);
+ if (item.tokens[0].text == 'alias') {
+ cleanOutTokens(LLVM.LINKAGES, item.tokens, 1);
+ cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 1);
var last = getTokenIndexByText(item.tokens, ';');
var ret = {
intertype: 'alias',
- ident: toNiceIdent(item.tokens[0].text),
- value: parseLLVMSegment(item.tokens.slice(3, last)),
+ ident: item.assignTo,
+ value: parseLLVMSegment(item.tokens.slice(1, last)),
lineNum: item.lineNum
};
ret.type = ret.value.type;
@@ -476,18 +456,18 @@ function intertyper(lines, sidePass, baseLineNums) {
}
return ret;
}
- if (item.tokens[2].text == 'type') {
+ if (item.tokens[0].text == 'type') {
var fields = [];
var packed = false;
- if (Runtime.isNumberType(item.tokens[3].text)) {
+ if (Runtime.isNumberType(item.tokens[1].text)) {
// Clang sometimes has |= i32| instead of |= { i32 }|
- fields = [item.tokens[3].text];
- } else if (item.tokens[3].text != 'opaque') {
- if (item.tokens[3].type == '<') {
+ fields = [item.tokens[1].text];
+ } else if (item.tokens[1].text != 'opaque') {
+ if (item.tokens[1].type == '<') {
packed = true;
- item.tokens[3] = item.tokens[3].item.tokens[0];
+ item.tokens[1] = item.tokens[1].item.tokens[0];
}
- var subTokens = item.tokens[3].tokens;
+ var subTokens = item.tokens[1].tokens;
if (subTokens) {
subTokens.push({text:','});
while (subTokens[0]) {
@@ -500,38 +480,40 @@ function intertyper(lines, sidePass, baseLineNums) {
}
return {
intertype: 'type',
- name_: item.tokens[0].text,
+ name_: item.assignTo,
fields: fields,
packed: packed,
lineNum: item.lineNum
};
} else {
// variable
- var ident = item.tokens[0].text;
+ var ident = item.assignTo;
var private_ = findTokenText(item, 'private') >= 0 || findTokenText(item, 'internal') >= 0;
var named = findTokenText(item, 'unnamed_addr') < 0;
- cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [2, 3]);
+ cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [0, 1]);
var external = false;
- if (item.tokens[2].text === 'external') {
+ if (item.tokens[0].text === 'external') {
external = true;
- item.tokens.splice(2, 1);
+ item.tokens.splice(0, 1);
}
var ret = {
intertype: 'globalVariable',
- ident: toNiceIdent(ident),
- type: item.tokens[2].text,
+ ident: ident,
+ type: item.tokens[0].text,
external: external,
private_: private_,
named: named,
lineNum: item.lineNum
};
noteGlobalVariable(ret);
- if (ident == '@llvm.global_ctors') {
+ if (ident == '_llvm_global_ctors') {
ret.ctors = [];
- if (item.tokens[3].item) {
- var subTokens = item.tokens[3].item.tokens;
+ if (item.tokens[1].item) {
+ var subTokens = item.tokens[1].item.tokens;
splitTokenList(subTokens).forEach(function(segment) {
- var ctor = toNiceIdent(segment[1].tokens.slice(-1)[0].text);
+ var parsed = parseLLVMSegment(segment);
+ assert(parsed.intertype === 'structvalue');
+ var ctor = toNiceIdent(parsed.params[1].ident);
ret.ctors.push(ctor);
if (ASM_JS) { // must export the global constructors from asm.js module, so mark as implemented and exported
Functions.implementedFunctions[ctor] = 'v';
@@ -540,14 +522,14 @@ function intertyper(lines, sidePass, baseLineNums) {
});
}
} else if (!external) {
- if (item.tokens[3] && item.tokens[3].text != ';') {
- if (item.tokens[3].text == 'c') {
- item.tokens.splice(3, 1);
+ if (item.tokens[1] && item.tokens[1].text != ';') {
+ if (item.tokens[1].text == 'c') {
+ item.tokens.splice(1, 1);
}
- if (item.tokens[3].text in PARSABLE_LLVM_FUNCTIONS) {
- ret.value = parseLLVMFunctionCall(item.tokens.slice(2));
+ if (item.tokens[1].text in PARSABLE_LLVM_FUNCTIONS) {
+ ret.value = parseLLVMFunctionCall(item.tokens);
} else {
- ret.value = scanConst(item.tokens[3], ret.type);
+ ret.value = scanConst(item.tokens[1], ret.type);
}
} else {
ret.value = { intertype: 'value', ident: '0', value: '0', type: ret.type };
@@ -1131,7 +1113,27 @@ function intertyper(lines, sidePass, baseLineNums) {
//var time = Date.now();
- var t = tokenize(line.lineText, line.lineNum);
+ // parse out the assignment
+ var indent = 0, assignTo = null;
+ if (phase === 'pre') {
+ var m = /^([%@\w\d\._\-]+|[%@]"[^"]+") = (.*)/.exec(line.lineText);
+ if (m) {
+ assignTo = m[1];
+ line.lineText = m[2];
+ }
+ } else if (phase === 'funcs') {
+ var m = /^ ([%@\w\d\._\-]+|[%@]"[^"]+") = (.*)/.exec(line.lineText);
+ if (m) {
+ indent = 2;
+ assignTo = m[1];
+ line.lineText = m[2];
+ }
+ }
+
+ var t = tokenize(line.lineText, line.lineNum, indent);
+ if (assignTo) {
+ t.assignTo = t.tokens[0].text !== 'type' ? toNiceIdent(assignTo) : assignTo;
+ }
item = triager(t);
/*
@@ -1148,7 +1150,7 @@ function intertyper(lines, sidePass, baseLineNums) {
return finalResults;
}
-// intertyper profiler
+// intertyper profiling
/*
var interProf = {};
@@ -1156,4 +1158,5 @@ function dumpInterProf() {
printErr('\nintertyper/' + phase + ' (ms | n): ' + JSON.stringify(keys(interProf).sort(function(x, y) { return interProf[y].ms - interProf[x].ms }).map(function(x) { return x + ' : ' + interProf[x].ms + ' | ' + interProf[x].n }), null, ' ') + '\n');
}
*/
+//var hits = 0;
diff --git a/src/jsifier.js b/src/jsifier.js
index a126994b..e84de3ee 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -407,6 +407,9 @@ function JSify(data, functionsOnly, givenFunctions) {
var snippet = LibraryManager.library[ident];
var redirectedIdent = null;
var deps = LibraryManager.library[ident + '__deps'] || [];
+ deps.forEach(function(dep) {
+ if (typeof snippet === 'string' && !(dep in LibraryManager.library)) warn('missing library dependency ' + dep + ', make sure you are compiling with the right options (see #ifdefs in src/library*.js)');
+ });
var isFunction = false;
if (typeof snippet === 'string') {
@@ -1372,7 +1375,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// store current list offset in tempInt, advance list offset by STACK_ALIGN, return list entry stored at tempInt
return '(tempInt=' + makeGetValue(ident, Runtime.QUANTUM_SIZE, '*') + ',' +
- makeSetValue(ident, Runtime.QUANTUM_SIZE, 'tempInt + ' + move, '*') + ',' +
+ makeSetValue(ident, Runtime.QUANTUM_SIZE, 'tempInt + ' + move, '*', null, null, null, null, ',') + ',' +
makeGetValue(makeGetValue(ident, 0, '*'), 'tempInt', item.type) + ')';
}
diff --git a/src/library_fs.js b/src/library_fs.js
index 5adbe6b7..bd1522a8 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -1,5 +1,5 @@
mergeInto(LibraryManager.library, {
- $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$VFS', '$PATH', '$TTY', '$MEMFS', '$IDBFS', '$NODEFS', 'stdin', 'stdout', 'stderr', 'fflush'],
+ $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$PATH', '$TTY', '$MEMFS', '$IDBFS', '$NODEFS', 'stdin', 'stdout', 'stderr', 'fflush'],
$FS__postset: 'FS.staticInit();' +
'__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
'__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' +
@@ -1064,19 +1064,8 @@ mergeInto(LibraryManager.library, {
{{{ makeSetValue(makeGlobalUse('_stderr'), 0, 'stderr.fd', 'void*') }}};
assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')');
},
- staticInit: function() {
- FS.nameTable = new Array(4096);
-
- FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
- FS.mount(MEMFS, {}, '/');
-
- FS.createDefaultDirectories();
- FS.createDefaultDevices();
- },
- init: function(input, output, error) {
- assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
- FS.init.initialized = true;
-
+ ensureErrnoError: function() {
+ if (FS.ErrnoError) return;
FS.ErrnoError = function ErrnoError(errno) {
this.errno = errno;
for (var key in ERRNO_CODES) {
@@ -1090,6 +1079,23 @@ mergeInto(LibraryManager.library, {
};
FS.ErrnoError.prototype = new Error();
FS.ErrnoError.prototype.constructor = FS.ErrnoError;
+ },
+ staticInit: function() {
+ FS.ensureErrnoError();
+
+ FS.nameTable = new Array(4096);
+
+ FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
+ FS.mount(MEMFS, {}, '/');
+
+ FS.createDefaultDirectories();
+ FS.createDefaultDevices();
+ },
+ init: function(input, output, error) {
+ assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
+ FS.init.initialized = true;
+
+ FS.ensureErrnoError();
// Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
Module['stdin'] = input || Module['stdin'];
diff --git a/src/library_gl.js b/src/library_gl.js
index 6e0e04dc..1ea8efc2 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -4047,7 +4047,10 @@ var LibraryGL = {
_glColor4f({{{ makeGetValue('p', '0', 'float') }}}, {{{ makeGetValue('p', '4', 'float') }}}, {{{ makeGetValue('p', '8', 'float') }}}, {{{ makeGetValue('p', '12', 'float') }}});
},
- glColor4ubv: function() { throw 'glColor4ubv not implemented' },
+ glColor4ubv__deps: ['glColor4ub'],
+ glColor4ubv: function(p) {
+ _glColor4ub({{{ makeGetValue('p', '0', 'i8') }}}, {{{ makeGetValue('p', '1', 'i8') }}}, {{{ makeGetValue('p', '2', 'i8') }}}, {{{ makeGetValue('p', '3', 'i8') }}});
+ },
glFogf: function(pname, param) { // partial support, TODO
switch(pname) {
@@ -4470,6 +4473,7 @@ var LibraryGL = {
return 1 /* GL_TRUE */;
},
+ gluOrtho2D__deps: ['glOrtho'],
gluOrtho2D: function(left, right, bottom, top) {
_glOrtho(left, right, bottom, top, -1, 1);
},
diff --git a/src/library_glut.js b/src/library_glut.js
index 79c586c6..722ea85c 100644
--- a/src/library_glut.js
+++ b/src/library_glut.js
@@ -190,12 +190,12 @@ var LibraryGLUT = {
}
},
- onMouseButtonDown: function(event){
+ onMouseButtonDown: function(event) {
Browser.calculateMouseEvent(event);
GLUT.buttons |= (1 << event['button']);
- if(event.target == Module["canvas"] && GLUT.mouseFunc){
+ if (event.target == Module["canvas"] && GLUT.mouseFunc) {
try {
event.target.setCapture();
} catch (e) {}
@@ -205,21 +205,40 @@ var LibraryGLUT = {
}
},
- onMouseButtonUp: function(event){
+ onMouseButtonUp: function(event) {
Browser.calculateMouseEvent(event);
GLUT.buttons &= ~(1 << event['button']);
- if(GLUT.mouseFunc) {
+ if (GLUT.mouseFunc) {
event.preventDefault();
GLUT.saveModifiers(event);
Runtime.dynCall('viiii', GLUT.mouseFunc, [event['button'], 1/*GLUT_UP*/, Browser.mouseX, Browser.mouseY]);
}
},
+ onMouseWheel: function(event) {
+ Browser.calculateMouseEvent(event);
+
+ // cross-browser wheel delta
+ var e = window.event || event; // old IE support
+ var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
+
+ var button = 3; // wheel up
+ if (delta < 0) {
+ button = 4; // wheel down
+ }
+
+ if (GLUT.mouseFunc) {
+ event.preventDefault();
+ GLUT.saveModifiers(event);
+ Runtime.dynCall('viiii', GLUT.mouseFunc, [button, 0/*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY]);
+ }
+ },
+
// TODO add fullscreen API ala:
// http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
- onFullScreenEventChange: function(event){
+ onFullScreenEventChange: function(event) {
var width;
var height;
if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) {
@@ -280,6 +299,10 @@ var LibraryGLUT = {
window.addEventListener("mousemove", GLUT.onMousemove, true);
window.addEventListener("mousedown", GLUT.onMouseButtonDown, true);
window.addEventListener("mouseup", GLUT.onMouseButtonUp, true);
+ // IE9, Chrome, Safari, Opera
+ window.addEventListener("mousewheel", GLUT.onMouseWheel, true);
+ // Firefox
+ window.addEventListener("DOMMouseScroll", GLUT.onMouseWheel, true);
}
Browser.resizeListeners.push(function(width, height) {
@@ -299,6 +322,10 @@ var LibraryGLUT = {
window.removeEventListener("mousemove", GLUT.onMousemove, true);
window.removeEventListener("mousedown", GLUT.onMouseButtonDown, true);
window.removeEventListener("mouseup", GLUT.onMouseButtonUp, true);
+ // IE9, Chrome, Safari, Opera
+ window.removeEventListener("mousewheel", GLUT.onMouseWheel, true);
+ // Firefox
+ window.removeEventListener("DOMMouseScroll", GLUT.onMouseWheel, true);
}
Module["canvas"].width = Module["canvas"].height = 1;
} });
diff --git a/src/library_sdl.js b/src/library_sdl.js
index bb7e9264..a0689343 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -1149,7 +1149,7 @@ var LibrarySDL = {
var ret = SDL.makeSurface(diagonal, diagonal, srcData.flags, false, 'rotozoomSurface');
var dstData = SDL.surfaces[ret];
dstData.ctx.translate(diagonal / 2, diagonal / 2);
- dstData.ctx.rotate(angle * Math.PI / 180);
+ dstData.ctx.rotate(-angle * Math.PI / 180);
dstData.ctx.drawImage(srcData.canvas, -w / 2, -h / 2, w, h);
return ret;
},
diff --git a/src/preamble.js b/src/preamble.js
index 33e80217..ee273f6a 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -656,7 +656,16 @@ function demangle(func) {
'i': 'int',
'l': 'long',
'f': 'float',
- 'd': 'double'
+ 'd': 'double',
+ 'w': 'wchar_t',
+ 'a': 'signed char',
+ 'h': 'unsigned char',
+ 't': 'unsigned short',
+ 'j': 'unsigned int',
+ 'm': 'unsigned long',
+ 'x': 'long long',
+ 'y': 'unsigned long long',
+ 'z': '...'
};
function dump(x) {
//return;
@@ -729,6 +738,7 @@ function demangle(func) {
} else {
switch (c) {
case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer
+ case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference
case 'L': { // literal
i++; // skip basic type
var end = func.indexOf('E', i);
@@ -737,6 +747,14 @@ function demangle(func) {
i += size + 2; // size + 'EE'
break;
}
+ case 'A': { // array
+ var size = parseInt(func.substr(i));
+ i += size.toString().length;
+ if (func[i] !== '_') throw '?';
+ i++; // skip _
+ list.push(parse(true, 1, true)[0] + ' [' + size + ']');
+ break;
+ }
case 'E': break paramLoop;
default: ret += '?' + c; break paramLoop;
}
@@ -752,11 +770,12 @@ function demangle(func) {
}
function demangleAll(text) {
- return text.replace(/__Z[\w\d_]+/, function(x) { var y = demangle(x); return x === y ? x : (x + ' (' + y + ')') });
+ return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') });
}
function stackTrace() {
- return demangleAll(new Error().stack);
+ var stack = new Error().stack;
+ return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6.
}
// Memory management
diff --git a/src/proxyClient.js b/src/proxyClient.js
index 04f7ed11..38ea5771 100644
--- a/src/proxyClient.js
+++ b/src/proxyClient.js
@@ -30,7 +30,15 @@ worker.onmessage = function(event) {
break;
}
case 'render': {
- Module.canvasData.data.set(data.image.data);
+ var src = data.image.data;
+ var dst = Module.canvasData.data;
+ if (dst.set) {
+ dst.set(src);
+ } else {
+ for (var i = 0; i < src.length; i++) {
+ dst[i] = src[i];
+ }
+ }
Module.ctx.putImageData(Module.canvasData, 0, 0);
break;
}