aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/closure-externs.js60
-rw-r--r--src/headlessCanvas.js4
-rw-r--r--src/intertyper.js10
-rw-r--r--src/jsifier.js14
-rw-r--r--src/library.js31
-rw-r--r--src/library_browser.js185
-rw-r--r--src/library_fs.js137
-rw-r--r--src/library_gc.js2
-rw-r--r--src/library_gl.js7
-rw-r--r--src/library_glut.js5
-rw-r--r--src/library_html5.js18
-rw-r--r--src/library_openal.js9
-rw-r--r--src/library_sdl.js6
-rw-r--r--src/parseTools.js6
-rw-r--r--src/postamble.js16
-rw-r--r--src/preamble.js14
-rw-r--r--src/relooper/README.markdown14
-rw-r--r--src/relooper/README.md12
-rw-r--r--src/relooper/Relooper.cpp6
-rw-r--r--src/runtime.js9
-rw-r--r--src/settings.js10
-rw-r--r--src/shell.html1653
-rw-r--r--src/shell.js2
-rw-r--r--src/struct_info.json6
24 files changed, 1503 insertions, 733 deletions
diff --git a/src/closure-externs.js b/src/closure-externs.js
index a82aa669..fe6d84aa 100644
--- a/src/closure-externs.js
+++ b/src/closure-externs.js
@@ -108,3 +108,63 @@ var flags = {};
flags.binary;
+/**
+ * @fileoverview Definitions for W3C's Gamepad specification.
+ * @see http://www.w3.org/TR/gamepad/
+ * @externs
+ */
+
+/**
+ * @typedef {{id: string, index: number, timestamp: number, axes: Array.<number>, buttons: Array.<number>}}
+ */
+var Gamepad;
+
+/**
+* @type {Array.<number>}
+*/
+Gamepad.buttons;
+
+/**
+* @type {Array.<number>}
+*/
+Gamepad.axes;
+
+/**
+* @type {number}
+*/
+Gamepad.index;
+
+/**
+* @type {string}
+*/
+Gamepad.id;
+
+/**
+* @type {number}
+*/
+Gamepad.timestamp;
+
+/**
+ * @return {Array.<Gamepad>}
+ */
+navigator.getGamepads = function() {};
+
+/**
+ * @return {Array.<Gamepad>}
+ */
+navigator.webkitGetGamepads = function() {};
+
+/**
+ * @return {Array.<Gamepad>}
+ */
+navigator.webkitGamepads = function() {};
+
+/**
+ * @return {Array.<Gamepad>}
+ */
+navigator.mozGamepads = function() {};
+
+/**
+ * @return {Array.<Gamepad>}
+ */
+navigator.gamepads = function() {};
diff --git a/src/headlessCanvas.js b/src/headlessCanvas.js
index 4bd17a7b..1eefe48e 100644
--- a/src/headlessCanvas.js
+++ b/src/headlessCanvas.js
@@ -598,7 +598,9 @@ function headlessCanvas() {
});
},
exitPointerLock: function(){},
- style: {},
+ style: {
+ setProperty: function(){}
+ },
eventListeners: {},
addEventListener: function(){},
removeEventListener: function(){},
diff --git a/src/intertyper.js b/src/intertyper.js
index 10822e48..323787ac 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -348,9 +348,11 @@ function intertyper(lines, sidePass, baseLineNums) {
if (token1Text == 'triple') {
var triple = item.tokens[3].text;
triple = triple.substr(1, triple.length-2);
- var expected = TARGET_LE32 ? 'le32-unknown-nacl' : 'i386-pc-linux-gnu';
+ var expected = TARGET_ASMJS_UNKNOWN_EMSCRIPTEN ? 'asmjs-unknown-emscripten' : 'i386-pc-linux-gnu';
if (triple !== expected) {
- warn('using an unexpected LLVM triple: ' + [triple, ' !== ', expected] + ' (are you using emcc for everything and not clang?)');
+ if (!(TARGET_ASMJS_UNKNOWN_EMSCRIPTEN && triple === 'le32-unknown-nacl')) {
+ warn('using an unexpected LLVM triple: ' + [triple, ' !== ', expected] + ' (are you using emcc for everything and not clang?)');
+ }
}
}
return null;
@@ -688,7 +690,7 @@ function intertyper(lines, sidePass, baseLineNums) {
Types.hasInlineJS = true;
warnOnce('inline JavaScript using asm() will cause the code to no longer fall in the asm.js subset of JavaScript, which can reduce performance - consider using emscripten_run_script');
}
- assert(TARGET_LE32, 'inline js is only supported in le32');
+ assert(TARGET_ASMJS_UNKNOWN_EMSCRIPTEN, 'inline js is only supported in asmjs-unknown-emscripten');
// Inline assembly is just JavaScript that we paste into the code
item.intertype = 'value';
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
@@ -848,7 +850,7 @@ function intertyper(lines, sidePass, baseLineNums) {
}).filter(function(param) { return param.value && param.value.ident != 'undef' });
return item;
}
- // 'phi'
+ // 'va_arg'
function va_argHandler(item) {
item.intertype = 'va_arg';
var segments = splitTokenList(item.tokens.slice(1));
diff --git a/src/jsifier.js b/src/jsifier.js
index c1ca893b..503f0b71 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -384,7 +384,7 @@ function JSify(data, functionsOnly) {
functionStubSigs[item.ident] = Functions.getSignature(item.returnType.text, item.params.map(function(arg) { return arg.type }), false);
}
- function addFromLibrary(ident) {
+ function addFromLibrary(ident, notDep) {
if (ident in addedLibraryItems) return '';
addedLibraryItems[ident] = true;
@@ -396,8 +396,10 @@ function JSify(data, functionsOnly) {
if (('_' + ident) in Functions.implementedFunctions) return '';
if (!LibraryManager.library.hasOwnProperty(ident) && !LibraryManager.library.hasOwnProperty(ident + '__inline')) {
- if (ERROR_ON_UNDEFINED_SYMBOLS) error('unresolved symbol: ' + ident);
- else if (VERBOSE || (WARN_ON_UNDEFINED_SYMBOLS && !LINKABLE)) warn('unresolved symbol: ' + ident);
+ if (notDep) {
+ if (ERROR_ON_UNDEFINED_SYMBOLS) error('unresolved symbol: ' + ident);
+ else if (VERBOSE || (WARN_ON_UNDEFINED_SYMBOLS && !LINKABLE)) warn('unresolved symbol: ' + ident);
+ }
// emit a stub that will fail at runtime
LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);");
}
@@ -502,7 +504,7 @@ function JSify(data, functionsOnly) {
delete LibraryManager.library[shortident + '__deps'];
}
}
- item.JS = addFromLibrary(shortident);
+ item.JS = addFromLibrary(shortident, true);
}
}
@@ -1413,7 +1415,7 @@ function JSify(data, functionsOnly) {
}
}
function va_argHandler(item) {
- assert(TARGET_LE32);
+ assert(TARGET_ASMJS_UNKNOWN_EMSCRIPTEN);
var ident = item.value.ident;
var move = Runtime.STACK_ALIGN;
@@ -1710,7 +1712,7 @@ function JSify(data, functionsOnly) {
if ((phase == 'pre' || phase == 'glue') && !Variables.generatedGlobalBase && !BUILD_AS_SHARED_LIB) {
Variables.generatedGlobalBase = true;
// Globals are done, here is the rest of static memory
- assert((TARGET_LE32 && Runtime.GLOBAL_BASE == 8) || (TARGET_X86 && Runtime.GLOBAL_BASE == 4)); // this is assumed in e.g. relocations for linkable modules
+ assert((TARGET_ASMJS_UNKNOWN_EMSCRIPTEN && Runtime.GLOBAL_BASE == 8) || (TARGET_X86 && Runtime.GLOBAL_BASE == 4)); // this is assumed in e.g. relocations for linkable modules
if (!SIDE_MODULE) {
print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n');
print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n');
diff --git a/src/library.js b/src/library.js
index 91d5f925..2c3d5e03 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1861,14 +1861,14 @@ LibraryManager.library = {
// int x = 4; printf("%c\n", (char)x);
var ret;
if (type === 'double') {
-#if TARGET_LE32 == 2
+#if TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 2
ret = {{{ makeGetValue('varargs', 'argIndex', 'double', undefined, undefined, true, 4) }}};
#else
ret = {{{ makeGetValue('varargs', 'argIndex', 'double', undefined, undefined, true) }}};
#endif
#if USE_TYPED_ARRAYS == 2
} else if (type == 'i64') {
-#if TARGET_LE32 == 1
+#if TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1
ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
{{{ makeGetValue('varargs', 'argIndex+8', 'i32', undefined, undefined, true) }}}];
argIndex += {{{ STACK_ALIGN }}}; // each 32-bit chunk is in a 64-bit block
@@ -1885,7 +1885,7 @@ LibraryManager.library = {
type = 'i32'; // varargs are always i32, i64, or double
ret = {{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}};
}
-#if TARGET_LE32 == 2
+#if TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 2
argIndex += Runtime.getNativeFieldSize(type);
#else
argIndex += Math.max(Runtime.getNativeFieldSize(type), Runtime.getAlignSize(type, null, true));
@@ -2420,7 +2420,9 @@ LibraryManager.library = {
fileno: function(stream) {
// int fileno(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fileno.html
- return FS.getStreamFromPtr(stream).fd;
+ stream = FS.getStreamFromPtr(stream);
+ if (!stream) return -1;
+ return stream.fd;
},
ftrylockfile: function() {
// int ftrylockfile(FILE *file);
@@ -2859,7 +2861,7 @@ LibraryManager.library = {
vsscanf: 'sscanf',
#endif
-#if TARGET_LE32
+#if TARGET_ASMJS_UNKNOWN_EMSCRIPTEN
// convert va_arg into varargs
vfprintf__deps: ['fprintf'],
vfprintf: function(s, f, va_arg) {
@@ -4178,7 +4180,7 @@ LibraryManager.library = {
#if TARGET_X86
return makeSetValue(ptr, 0, 'varrp', 'void*');
#endif
-#if TARGET_LE32
+#if TARGET_ASMJS_UNKNOWN_EMSCRIPTEN
// 2-word structure: struct { void* start; void* currentOffset; }
return makeSetValue(ptr, 0, 'varrp', 'void*') + ';' + makeSetValue(ptr, Runtime.QUANTUM_SIZE, 0, 'void*');
#endif
@@ -4584,6 +4586,7 @@ LibraryManager.library = {
// Destructors for std::exception since we don't have them implemented in libcxx as we aren't using libcxxabi.
// These are also needed for the dlmalloc tests.
+ _ZNSt9exceptionD0Ev: function() {},
_ZNSt9exceptionD1Ev: function() {},
_ZNSt9exceptionD2Ev: function() {},
@@ -8941,7 +8944,8 @@ LibraryManager.library = {
// Process all lines:
lines = callstack.split('\n');
callstack = '';
- var firefoxRe = new RegExp('\\s*(.*?)@(.*):(.*)'); // Extract components of form ' Object._main@http://server.com:4324'
+ var newFirefoxRe = new RegExp('\\s*(.*?)@(.*?):([0-9]+):([0-9]+)'); // New FF30 with column info: extract components of form ' Object._main@http://server.com:4324:12'
+ var firefoxRe = new RegExp('\\s*(.*?)@(.*):(.*)(:(.*))?'); // Old FF without column info: extract components of form ' Object._main@http://server.com:4324'
var chromeRe = new RegExp('\\s*at (.*?) \\\((.*):(.*):(.*)\\\)'); // Extract components of form ' at Object._main (http://server.com/file.html:4324:12)'
for(l in lines) {
@@ -8959,12 +8963,13 @@ LibraryManager.library = {
lineno = parts[3];
column = parts[4];
} else {
- parts = firefoxRe.exec(line);
- if (parts && parts.length == 4) {
+ parts = newFirefoxRe.exec(line);
+ if (!parts) parts = firefoxRe.exec(line);
+ if (parts && parts.length >= 4) {
jsSymbolName = parts[1];
file = parts[2];
lineno = parts[3];
- column = 0; // Firefox doesn't carry column information. See https://bugzilla.mozilla.org/show_bug.cgi?id=762556
+ column = parts[4]|0; // Old Firefox doesn't carry column information, but in new FF30, it is present. See https://bugzilla.mozilla.org/show_bug.cgi?id=762556
} else {
// Was not able to extract this line for demangling/sourcemapping purposes. Output it as-is.
callstack += line + '\n';
@@ -9020,7 +9025,7 @@ LibraryManager.library = {
}
// Truncate output to avoid writing past bounds.
if (callstack.length > maxbytes-1) {
- callstack.slice(0, maxbytes-1);
+ callstack = callstack.slice(0, maxbytes-1);
}
// Output callstack string as C string to HEAP.
writeStringToMemory(callstack, str, false);
@@ -9109,6 +9114,10 @@ LibraryManager.library = {
#endif
#endif
+ emscripten_debugger: function() {
+ debugger;
+ },
+
//============================
// emscripten vector ops
//============================
diff --git a/src/library_browser.js b/src/library_browser.js
index b800292c..0808b9f0 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -1,7 +1,6 @@
//"use strict";
// Utilities for browser environments
-
mergeInto(LibraryManager.library, {
$Browser__deps: ['$PATH'],
$Browser__postset: 'Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports
@@ -197,24 +196,33 @@ mergeInto(LibraryManager.library, {
// Canvas event setup
var canvas = Module['canvas'];
+
+ // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
+ // Module['forcedAspectRatio'] = 4 / 3;
+
canvas.requestPointerLock = canvas['requestPointerLock'] ||
canvas['mozRequestPointerLock'] ||
- canvas['webkitRequestPointerLock'];
+ canvas['webkitRequestPointerLock'] ||
+ canvas['msRequestPointerLock'] ||
+ function(){};
canvas.exitPointerLock = document['exitPointerLock'] ||
document['mozExitPointerLock'] ||
document['webkitExitPointerLock'] ||
+ document['msExitPointerLock'] ||
function(){}; // no-op if function does not exist
canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
function pointerLockChange() {
Browser.pointerLock = document['pointerLockElement'] === canvas ||
document['mozPointerLockElement'] === canvas ||
- document['webkitPointerLockElement'] === canvas;
+ document['webkitPointerLockElement'] === canvas ||
+ document['msPointerLockElement'] === canvas;
}
document.addEventListener('pointerlockchange', pointerLockChange, false);
document.addEventListener('mozpointerlockchange', pointerLockChange, false);
document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+ document.addEventListener('mspointerlockchange', pointerLockChange, false);
if (Module['elementPointerLock']) {
canvas.addEventListener("click", function(ev) {
@@ -342,20 +350,32 @@ mergeInto(LibraryManager.library, {
var canvas = Module['canvas'];
function fullScreenChange() {
Browser.isFullScreen = false;
+ var canvasContainer = canvas.parentNode;
if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
- document['fullScreenElement'] || document['fullscreenElement']) === canvas) {
+ document['fullScreenElement'] || document['fullscreenElement'] ||
+ document['msFullScreenElement'] || document['msFullscreenElement'] ||
+ document['webkitCurrentFullScreenElement']) === canvasContainer) {
canvas.cancelFullScreen = document['cancelFullScreen'] ||
document['mozCancelFullScreen'] ||
- document['webkitCancelFullScreen'];
+ document['webkitCancelFullScreen'] ||
+ document['msExitFullscreen'] ||
+ document['exitFullscreen'] ||
+ function() {};
canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
if (Browser.lockPointer) canvas.requestPointerLock();
Browser.isFullScreen = true;
if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
- } else if (Browser.resizeCanvas){
- Browser.setWindowedCanvasSize();
+ } else {
+
+ // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
+ canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
+ canvasContainer.parentNode.removeChild(canvasContainer);
+
+ if (Browser.resizeCanvas) Browser.setWindowedCanvasSize();
}
if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
+ Browser.updateCanvasDimensions(canvas);
}
if (!Browser.fullScreenHandlersInstalled) {
@@ -363,12 +383,20 @@ mergeInto(LibraryManager.library, {
document.addEventListener('fullscreenchange', fullScreenChange, false);
document.addEventListener('mozfullscreenchange', fullScreenChange, false);
document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+ document.addEventListener('MSFullscreenChange', fullScreenChange, false);
}
- canvas.requestFullScreen = canvas['requestFullScreen'] ||
- canvas['mozRequestFullScreen'] ||
- (canvas['webkitRequestFullScreen'] ? function() { canvas['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
- canvas.requestFullScreen();
+ // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
+ var canvasContainer = document.createElement("div");
+ canvas.parentNode.insertBefore(canvasContainer, canvas);
+ canvasContainer.appendChild(canvas);
+
+ // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
+ canvasContainer.requestFullScreen = canvasContainer['requestFullScreen'] ||
+ canvasContainer['mozRequestFullScreen'] ||
+ canvasContainer['msRequestFullscreen'] ||
+ (canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+ canvasContainer.requestFullScreen();
},
requestAnimationFrame: function requestAnimationFrame(func) {
@@ -565,19 +593,13 @@ mergeInto(LibraryManager.library, {
setCanvasSize: function(width, height, noUpdates) {
var canvas = Module['canvas'];
- canvas.width = width;
- canvas.height = height;
+ Browser.updateCanvasDimensions(canvas, width, height);
if (!noUpdates) Browser.updateResizeListeners();
},
windowedWidth: 0,
windowedHeight: 0,
setFullScreenCanvasSize: function() {
- var canvas = Module['canvas'];
- this.windowedWidth = canvas.width;
- this.windowedHeight = canvas.height;
- canvas.width = screen.width;
- canvas.height = screen.height;
// check if SDL is available
if (typeof SDL != "undefined") {
var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
@@ -588,9 +610,6 @@ mergeInto(LibraryManager.library, {
},
setWindowedCanvasSize: function() {
- var canvas = Module['canvas'];
- canvas.width = this.windowedWidth;
- canvas.height = this.windowedHeight;
// check if SDL is available
if (typeof SDL != "undefined") {
var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
@@ -598,8 +617,55 @@ mergeInto(LibraryManager.library, {
{{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
}
Browser.updateResizeListeners();
- }
+ },
+ updateCanvasDimensions : function(canvas, wNative, hNative) {
+ if (wNative && hNative) {
+ canvas.widthNative = wNative;
+ canvas.heightNative = hNative;
+ } else {
+ wNative = canvas.widthNative;
+ hNative = canvas.heightNative;
+ }
+ var w = wNative;
+ var h = hNative;
+ if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
+ if (w/h < Module['forcedAspectRatio']) {
+ w = Math.round(h * Module['forcedAspectRatio']);
+ } else {
+ h = Math.round(w / Module['forcedAspectRatio']);
+ }
+ }
+ if (((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
+ document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
+ document['fullScreenElement'] || document['fullscreenElement'] ||
+ document['msFullScreenElement'] || document['msFullscreenElement'] ||
+ document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
+ var factor = Math.min(screen.width / w, screen.height / h);
+ w = Math.round(w * factor);
+ h = Math.round(h * factor);
+ }
+ if (Browser.resizeCanvas) {
+ if (canvas.width != w) canvas.width = w;
+ if (canvas.height != h) canvas.height = h;
+ if (typeof canvas.style != 'undefined') {
+ canvas.style.removeProperty( "width");
+ canvas.style.removeProperty("height");
+ }
+ } else {
+ if (canvas.width != wNative) canvas.width = wNative;
+ if (canvas.height != hNative) canvas.height = hNative;
+ if (typeof canvas.style != 'undefined') {
+ if (w != wNative || h != hNative) {
+ canvas.style.setProperty( "width", w + "px", "important");
+ canvas.style.setProperty("height", h + "px", "important");
+ } else {
+ canvas.style.removeProperty( "width");
+ canvas.style.removeProperty("height");
+ }
+ }
+ }
+ }
},
emscripten_async_wget: function(url, file, onload, onerror) {
@@ -657,8 +723,59 @@ mergeInto(LibraryManager.library, {
// PROGRESS
http.onprogress = function http_onprogress(e) {
- var percentComplete = (e.position / e.totalSize)*100;
- if (onprogress) Runtime.dynCall('vii', onprogress, [arg, percentComplete]);
+ if (e.lengthComputable || (e.lengthComputable === undefined && e.totalSize != 0)) {
+ var percentComplete = (e.position / e.totalSize)*100;
+ if (onprogress) Runtime.dynCall('vii', onprogress, [arg, percentComplete]);
+ }
+ };
+
+ // Useful because the browser can limit the number of redirection
+ try {
+ if (http.channel instanceof Ci.nsIHttpChannel)
+ http.channel.redirectionLimit = 0;
+ } catch (ex) { /* whatever */ }
+
+ if (_request == "POST") {
+ //Send the proper header information along with the request
+ http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ http.setRequestHeader("Content-length", _param.length);
+ http.setRequestHeader("Connection", "close");
+ http.send(_param);
+ } else {
+ http.send(null);
+ }
+ },
+
+ emscripten_async_wget2_data: function(url, request, param, arg, free, onload, onerror, onprogress) {
+ var _url = Pointer_stringify(url);
+ var _request = Pointer_stringify(request);
+ var _param = Pointer_stringify(param);
+
+ var http = new XMLHttpRequest();
+ http.open(_request, _url, true);
+ http.responseType = 'arraybuffer';
+
+ // LOAD
+ http.onload = function http_onload(e) {
+ if (http.status == 200 || _url.substr(0,4).toLowerCase() != "http") {
+ var byteArray = new Uint8Array(http.response);
+ var buffer = _malloc(byteArray.length);
+ HEAPU8.set(byteArray, buffer);
+ if (onload) Runtime.dynCall('viii', onload, [arg, buffer, byteArray.length]);
+ if (free) _free(buffer);
+ } else {
+ if (onerror) Runtime.dynCall('viii', onerror, [arg, http.status, http.statusText]);
+ }
+ };
+
+ // ERROR
+ http.onerror = function http_onerror(e) {
+ if (onerror) Runtime.dynCall('viii', onerror, [arg, http.status, http.statusText]);
+ };
+
+ // PROGRESS
+ http.onprogress = function http_onprogress(e) {
+ if (onprogress) Runtime.dynCall('viii', onprogress, [arg, e.loaded, e.lengthComputable || e.lengthComputable === undefined ? e.total : 0]);
};
// Useful because the browser can limit the number of redirection
@@ -943,8 +1060,11 @@ mergeInto(LibraryManager.library, {
var callbackId = msg.data['callbackId'];
var callbackInfo = info.callbacks[callbackId];
if (!callbackInfo) return; // no callback or callback removed meanwhile
- info.awaited--;
- info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this
+ // Don't trash our callback state if we expect additional calls.
+ if (msg.data['finalResponse']) {
+ info.awaited--;
+ info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this
+ }
var data = msg.data['data'];
if (data) {
if (!data.byteLength) data = new Uint8Array(data);
@@ -991,12 +1111,23 @@ mergeInto(LibraryManager.library, {
});
},
+ emscripten_worker_respond_provisionally: function(data, size) {
+ if (!inWorkerCall) throw 'not in worker call!';
+ if (workerResponded) throw 'already responded with final response!';
+ postMessage({
+ 'callbackId': workerCallbackId,
+ 'finalResponse': false,
+ 'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705
+ });
+ },
+
emscripten_worker_respond: function(data, size) {
if (!inWorkerCall) throw 'not in worker call!';
- if (workerResponded) throw 'already responded!';
+ if (workerResponded) throw 'already responded with final response!';
workerResponded = true;
postMessage({
'callbackId': workerCallbackId,
+ 'finalResponse': true,
'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705
});
},
diff --git a/src/library_fs.js b/src/library_fs.js
index 1428f041..3d0036ee 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -1436,82 +1436,81 @@ mergeInto(LibraryManager.library, {
// XHR, which is not possible in browsers except in a web worker! Use preloading,
// either --preload-file in emcc or FS.createPreloadedFile
createLazyFile: function(parent, name, url, canRead, canWrite) {
- if (typeof XMLHttpRequest !== 'undefined') {
- if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
- // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
- function LazyUint8Array() {
- this.lengthKnown = false;
- this.chunks = []; // Loaded chunks. Index is the chunk number
- }
- LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
- if (idx > this.length-1 || idx < 0) {
- return undefined;
- }
- var chunkOffset = idx % this.chunkSize;
- var chunkNum = Math.floor(idx / this.chunkSize);
- return this.getter(chunkNum)[chunkOffset];
+ // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
+ function LazyUint8Array() {
+ this.lengthKnown = false;
+ this.chunks = []; // Loaded chunks. Index is the chunk number
+ }
+ LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
+ if (idx > this.length-1 || idx < 0) {
+ return undefined;
}
- LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
- this.getter = getter;
- }
- LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
- // Find length
- var xhr = new XMLHttpRequest();
- xhr.open('HEAD', url, false);
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- var datalength = Number(xhr.getResponseHeader("Content-length"));
- var header;
- var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+ var chunkOffset = idx % this.chunkSize;
+ var chunkNum = Math.floor(idx / this.chunkSize);
+ return this.getter(chunkNum)[chunkOffset];
+ }
+ LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
+ this.getter = getter;
+ }
+ LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
+ // Find length
+ var xhr = new XMLHttpRequest();
+ xhr.open('HEAD', url, false);
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ var datalength = Number(xhr.getResponseHeader("Content-length"));
+ var header;
+ var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
#if SMALL_XHR_CHUNKS
- var chunkSize = 1024; // Chunk size in bytes
+ var chunkSize = 1024; // Chunk size in bytes
#else
- var chunkSize = 1024*1024; // Chunk size in bytes
+ var chunkSize = 1024*1024; // Chunk size in bytes
#endif
- if (!hasByteServing) chunkSize = datalength;
-
- // Function to get a range from the remote URL.
- var doXHR = (function(from, to) {
- if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
- if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
-
- // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, false);
- if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
-
- // Some hints to the browser that we want binary data.
- if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- }
-
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- if (xhr.response !== undefined) {
- return new Uint8Array(xhr.response || []);
- } else {
- return intArrayFromString(xhr.responseText || '', true);
- }
- });
- var lazyArray = this;
- lazyArray.setDataGetter(function(chunkNum) {
- var start = chunkNum * chunkSize;
- var end = (chunkNum+1) * chunkSize - 1; // including this byte
- end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
- lazyArray.chunks[chunkNum] = doXHR(start, end);
- }
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
- return lazyArray.chunks[chunkNum];
- });
+ if (!hasByteServing) chunkSize = datalength;
- this._length = datalength;
- this._chunkSize = chunkSize;
- this.lengthKnown = true;
- }
+ // Function to get a range from the remote URL.
+ var doXHR = (function(from, to) {
+ if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+ if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+ // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+ // Some hints to the browser that we want binary data.
+ if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+ if (xhr.overrideMimeType) {