~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to src/library_browser.js

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//"use strict";
 
2
 
 
3
// Utilities for browser environments
 
4
 
 
5
mergeInto(LibraryManager.library, {
 
6
  $Browser__postset: 'Module["requestFullScreen"] = function(lockPointer, resizeCanvas) { Browser.requestFullScreen(lockPointer, resizeCanvas) };\n' + // exports
 
7
                     'Module["requestAnimationFrame"] = function(func) { Browser.requestAnimationFrame(func) };\n' +
 
8
                     'Module["pauseMainLoop"] = function() { Browser.mainLoop.pause() };\n' +
 
9
                     'Module["resumeMainLoop"] = function() { Browser.mainLoop.resume() };\n',
 
10
  $Browser: {
 
11
    mainLoop: {
 
12
      scheduler: null,
 
13
      shouldPause: false,
 
14
      paused: false,
 
15
      queue: [],
 
16
      pause: function() {
 
17
        Browser.mainLoop.shouldPause = true;
 
18
      },
 
19
      resume: function() {
 
20
        if (Browser.mainLoop.paused) {
 
21
          Browser.mainLoop.paused = false;
 
22
          Browser.mainLoop.scheduler();
 
23
        }
 
24
        Browser.mainLoop.shouldPause = false;
 
25
      },
 
26
      updateStatus: function() {
 
27
        if (Module['setStatus']) {
 
28
          var message = Module['statusMessage'] || 'Please wait...';
 
29
          var remaining = Browser.mainLoop.remainingBlockers;
 
30
          var expected = Browser.mainLoop.expectedBlockers;
 
31
          if (remaining) {
 
32
            if (remaining < expected) {
 
33
              Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
 
34
            } else {
 
35
              Module['setStatus'](message);
 
36
            }
 
37
          } else {
 
38
            Module['setStatus']('');
 
39
          }
 
40
        }
 
41
      }
 
42
    },
 
43
    isFullScreen: false,
 
44
    pointerLock: false,
 
45
    moduleContextCreatedCallbacks: [],
 
46
    workers: [],
 
47
 
 
48
    init: function() {
 
49
      if (Browser.initted) return;
 
50
      Browser.initted = true;
 
51
      try {
 
52
        new Blob();
 
53
        Browser.hasBlobConstructor = true;
 
54
      } catch(e) {
 
55
        Browser.hasBlobConstructor = false;
 
56
        console.log("warning: no blob constructor, cannot create blobs with mimetypes");
 
57
      }
 
58
      Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
 
59
      Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : console.log("warning: cannot create object URLs");
 
60
 
 
61
      // Support for plugins that can process preloaded files. You can add more of these to
 
62
      // your app by creating and appending to Module.preloadPlugins.
 
63
      //
 
64
      // Each plugin is asked if it can handle a file based on the file's name. If it can,
 
65
      // it is given the file's raw data. When it is done, it calls a callback with the file's
 
66
      // (possibly modified) data. For example, a plugin might decompress a file, or it
 
67
      // might create some side data structure for use later (like an Image element, etc.).
 
68
 
 
69
      function getMimetype(name) {
 
70
        return {
 
71
          'jpg': 'image/jpeg',
 
72
          'jpeg': 'image/jpeg',
 
73
          'png': 'image/png',
 
74
          'bmp': 'image/bmp',
 
75
          'ogg': 'audio/ogg',
 
76
          'wav': 'audio/wav',
 
77
          'mp3': 'audio/mpeg'
 
78
        }[name.substr(name.lastIndexOf('.')+1)];
 
79
      }
 
80
 
 
81
      if (!Module["preloadPlugins"]) Module["preloadPlugins"] = [];
 
82
 
 
83
      var imagePlugin = {};
 
84
      imagePlugin['canHandle'] = function(name) {
 
85
        return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/.exec(name);
 
86
      };
 
87
      imagePlugin['handle'] = function(byteArray, name, onload, onerror) {
 
88
        var b = null;
 
89
        if (Browser.hasBlobConstructor) {
 
90
          try {
 
91
            b = new Blob([byteArray], { type: getMimetype(name) });
 
92
          } catch(e) {
 
93
            Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
 
94
          }
 
95
        }
 
96
        if (!b) {
 
97
          var bb = new Browser.BlobBuilder();
 
98
          bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
 
99
          b = bb.getBlob();
 
100
        }
 
101
        var url = Browser.URLObject.createObjectURL(b);
 
102
#if ASSERTIONS
 
103
        assert(typeof url == 'string', 'createObjectURL must return a url as a string');
 
104
#endif
 
105
        var img = new Image();
 
106
        img.onload = function() {
 
107
          assert(img.complete, 'Image ' + name + ' could not be decoded');
 
108
          var canvas = document.createElement('canvas');
 
109
          canvas.width = img.width;
 
110
          canvas.height = img.height;
 
111
          var ctx = canvas.getContext('2d');
 
112
          ctx.drawImage(img, 0, 0);
 
113
          Module["preloadedImages"][name] = canvas;
 
114
          Browser.URLObject.revokeObjectURL(url);
 
115
          if (onload) onload(byteArray);
 
116
        };
 
117
        img.onerror = function(event) {
 
118
          console.log('Image ' + url + ' could not be decoded');
 
119
          if (onerror) onerror();
 
120
        };
 
121
        img.src = url;
 
122
      };
 
123
      Module['preloadPlugins'].push(imagePlugin);
 
124
 
 
125
      var audioPlugin = {};
 
126
      audioPlugin['canHandle'] = function(name) {
 
127
        return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
 
128
      };
 
129
      audioPlugin['handle'] = function(byteArray, name, onload, onerror) {
 
130
        var done = false;
 
131
        function finish(audio) {
 
132
          if (done) return;
 
133
          done = true;
 
134
          Module["preloadedAudios"][name] = audio;
 
135
          if (onload) onload(byteArray);
 
136
        }
 
137
        function fail() {
 
138
          if (done) return;
 
139
          done = true;
 
140
          Module["preloadedAudios"][name] = new Audio(); // empty shim
 
141
          if (onerror) onerror();
 
142
        }
 
143
        if (Browser.hasBlobConstructor) {
 
144
          try {
 
145
            var b = new Blob([byteArray], { type: getMimetype(name) });
 
146
          } catch(e) {
 
147
            return fail();
 
148
          }
 
149
          var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
 
150
#if ASSERTIONS
 
151
          assert(typeof url == 'string', 'createObjectURL must return a url as a string');
 
152
#endif
 
153
          var audio = new Audio();
 
154
          audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
 
155
          audio.onerror = function(event) {
 
156
            if (done) return;
 
157
            console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
 
158
            function encode64(data) {
 
159
              var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
 
160
              var PAD = '=';
 
161
              var ret = '';
 
162
              var leftchar = 0;
 
163
              var leftbits = 0;
 
164
              for (var i = 0; i < data.length; i++) {
 
165
                leftchar = (leftchar << 8) | data[i];
 
166
                leftbits += 8;
 
167
                while (leftbits >= 6) {
 
168
                  var curr = (leftchar >> (leftbits-6)) & 0x3f;
 
169
                  leftbits -= 6;
 
170
                  ret += BASE[curr];
 
171
                }
 
172
              }
 
173
              if (leftbits == 2) {
 
174
                ret += BASE[(leftchar&3) << 4];
 
175
                ret += PAD + PAD;
 
176
              } else if (leftbits == 4) {
 
177
                ret += BASE[(leftchar&0xf) << 2];
 
178
                ret += PAD;
 
179
              }
 
180
              return ret;
 
181
            }
 
182
            audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
 
183
            finish(audio); // we don't wait for confirmation this worked - but it's worth trying
 
184
          };
 
185
          audio.src = url;
 
186
          // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
 
187
          setTimeout(function() {
 
188
            finish(audio); // try to use it even though it is not necessarily ready to play
 
189
          }, 10000);
 
190
        } else {
 
191
          return fail();
 
192
        }
 
193
      };
 
194
      Module['preloadPlugins'].push(audioPlugin);
 
195
 
 
196
      // Canvas event setup
 
197
 
 
198
      var canvas = Module['canvas'];
 
199
      canvas.requestPointerLock = canvas['requestPointerLock'] ||
 
200
                                  canvas['mozRequestPointerLock'] ||
 
201
                                  canvas['webkitRequestPointerLock'];
 
202
      canvas.exitPointerLock = document['exitPointerLock'] ||
 
203
                               document['mozExitPointerLock'] ||
 
204
                               document['webkitExitPointerLock'];
 
205
      canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
 
206
 
 
207
      function pointerLockChange() {
 
208
        Browser.pointerLock = document['pointerLockElement'] === canvas ||
 
209
                              document['mozPointerLockElement'] === canvas ||
 
210
                              document['webkitPointerLockElement'] === canvas;
 
211
      }
 
212
 
 
213
      document.addEventListener('pointerlockchange', pointerLockChange, false);
 
214
      document.addEventListener('mozpointerlockchange', pointerLockChange, false);
 
215
      document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
 
216
 
 
217
      if (Module['elementPointerLock']) {
 
218
        canvas.addEventListener("click", function(ev) {
 
219
          if (!Browser.pointerLock && canvas.requestPointerLock) {
 
220
            canvas.requestPointerLock();
 
221
            ev.preventDefault();
 
222
          }
 
223
        }, false);
 
224
      }
 
225
    },
 
226
 
 
227
    createContext: function(canvas, useWebGL, setInModule) {
 
228
#if !USE_TYPED_ARRAYS
 
229
      if (useWebGL) {
 
230
        Module.print('(USE_TYPED_ARRAYS needs to be enabled for WebGL)');
 
231
        return null;
 
232
      }
 
233
#endif
 
234
      var ctx;
 
235
      try {
 
236
        if (useWebGL) {
 
237
          ctx = canvas.getContext('experimental-webgl', {
 
238
#if GL_TESTING
 
239
            preserveDrawingBuffer: true,
 
240
#endif
 
241
            alpha: false
 
242
          });
 
243
        } else {
 
244
          ctx = canvas.getContext('2d');
 
245
        }
 
246
        if (!ctx) throw ':(';
 
247
      } catch (e) {
 
248
        Module.print('Could not create canvas - ' + e);
 
249
        return null;
 
250
      }
 
251
      if (useWebGL) {
 
252
#if GL_DEBUG
 
253
        // Useful to debug native webgl apps: var Module = { printErr: function(x) { console.log(x) } };
 
254
        var tempCtx = ctx;
 
255
        var wrapper = {};
 
256
        for (var prop in tempCtx) {
 
257
          (function(prop) {
 
258
            switch (typeof tempCtx[prop]) {
 
259
              case 'function': {
 
260
                wrapper[prop] = function() {
 
261
                  if (GL.debug) {
 
262
                    var printArgs = Array.prototype.slice.call(arguments).map(Runtime.prettyPrint);
 
263
                    Module.printErr('[gl_f:' + prop + ':' + printArgs + ']');
 
264
                  }
 
265
                  var ret = tempCtx[prop].apply(tempCtx, arguments);
 
266
                  if (GL.debug && typeof ret != 'undefined') {
 
267
                    Module.printErr('[     gl:' + prop + ':return:' + Runtime.prettyPrint(ret) + ']');
 
268
                  }
 
269
                  return ret;
 
270
                }
 
271
                break;
 
272
              }
 
273
              case 'number': case 'string': {
 
274
                wrapper.__defineGetter__(prop, function() {
 
275
                  //Module.printErr('[gl_g:' + prop + ':' + tempCtx[prop] + ']');
 
276
                  return tempCtx[prop];
 
277
                });
 
278
                wrapper.__defineSetter__(prop, function(value) {
 
279
                  if (GL.debug) {
 
280
                    Module.printErr('[gl_s:' + prop + ':' + value + ']');
 
281
                  }
 
282
                  tempCtx[prop] = value;
 
283
                });
 
284
                break;
 
285
              }
 
286
            }
 
287
          })(prop);
 
288
        }
 
289
        ctx = wrapper;
 
290
#endif
 
291
        // Set the background of the WebGL canvas to black
 
292
        canvas.style.backgroundColor = "black";
 
293
 
 
294
        // Warn on context loss
 
295
        canvas.addEventListener('webglcontextlost', function(event) {
 
296
          alert('WebGL context lost. You will need to reload the page.');
 
297
        }, false);
 
298
      }
 
299
      if (setInModule) {
 
300
        Module.ctx = ctx;
 
301
        Module.useWebGL = useWebGL;
 
302
        Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
 
303
        Browser.init();
 
304
      }
 
305
      return ctx;
 
306
    },
 
307
 
 
308
    destroyContext: function(canvas, useWebGL, setInModule) {},
 
309
 
 
310
    fullScreenHandlersInstalled: false,
 
311
    lockPointer: undefined,
 
312
    resizeCanvas: undefined,
 
313
    requestFullScreen: function(lockPointer, resizeCanvas) {
 
314
      this.lockPointer = lockPointer;
 
315
      this.resizeCanvas = resizeCanvas;
 
316
      if (typeof this.lockPointer === 'undefined') this.lockPointer = true;
 
317
      if (typeof this.resizeCanvas === 'undefined') this.resizeCanvas = false;
 
318
 
 
319
      var canvas = Module['canvas'];
 
320
      function fullScreenChange() {
 
321
        Browser.isFullScreen = false;
 
322
        if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] ||
 
323
             document['mozFullScreenElement'] || document['mozFullscreenElement'] ||
 
324
             document['fullScreenElement'] || document['fullscreenElement']) === canvas) {
 
325
          canvas.cancelFullScreen = document['cancelFullScreen'] ||
 
326
                                    document['mozCancelFullScreen'] ||
 
327
                                    document['webkitCancelFullScreen'];
 
328
          canvas.cancelFullScreen = canvas.cancelFullScreen.bind(document);
 
329
          if (Browser.lockPointer) canvas.requestPointerLock();
 
330
          Browser.isFullScreen = true;
 
331
          if (Browser.resizeCanvas) Browser.setFullScreenCanvasSize();
 
332
        } else if (Browser.resizeCanvas){
 
333
          Browser.setWindowedCanvasSize();
 
334
        }
 
335
        if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen);
 
336
      }
 
337
 
 
338
      if (!this.fullScreenHandlersInstalled) {
 
339
        this.fullScreenHandlersInstalled = true;
 
340
        document.addEventListener('fullscreenchange', fullScreenChange, false);
 
341
        document.addEventListener('mozfullscreenchange', fullScreenChange, false);
 
342
        document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
 
343
      }
 
344
 
 
345
      canvas.requestFullScreen = canvas['requestFullScreen'] ||
 
346
                                 canvas['mozRequestFullScreen'] ||
 
347
                                 (canvas['webkitRequestFullScreen'] ? function() { canvas['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
 
348
      canvas.requestFullScreen(); 
 
349
    },
 
350
 
 
351
    requestAnimationFrame: function(func) {
 
352
      if (!window.requestAnimationFrame) {
 
353
        window.requestAnimationFrame = window['requestAnimationFrame'] ||
 
354
                                       window['mozRequestAnimationFrame'] ||
 
355
                                       window['webkitRequestAnimationFrame'] ||
 
356
                                       window['msRequestAnimationFrame'] ||
 
357
                                       window['oRequestAnimationFrame'] ||
 
358
                                       window['setTimeout'];
 
359
      }
 
360
      window.requestAnimationFrame(func);
 
361
    },
 
362
 
 
363
    getMovementX: function(event) {
 
364
      return event['movementX'] ||
 
365
             event['mozMovementX'] ||
 
366
             event['webkitMovementX'] ||
 
367
             0;
 
368
    },
 
369
 
 
370
    getMovementY: function(event) {
 
371
      return event['movementY'] ||
 
372
             event['mozMovementY'] ||
 
373
             event['webkitMovementY'] ||
 
374
             0;
 
375
    },
 
376
 
 
377
    xhrLoad: function(url, onload, onerror) {
 
378
      var xhr = new XMLHttpRequest();
 
379
      xhr.open('GET', url, true);
 
380
      xhr.responseType = 'arraybuffer';
 
381
      xhr.onload = function() {
 
382
        if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
 
383
          onload(xhr.response);
 
384
        } else {
 
385
          onerror();
 
386
        }
 
387
      };
 
388
      xhr.onerror = onerror;
 
389
      xhr.send(null);
 
390
    },
 
391
 
 
392
    asyncLoad: function(url, onload, onerror, noRunDep) {
 
393
      Browser.xhrLoad(url, function(arrayBuffer) {
 
394
        assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
 
395
        onload(new Uint8Array(arrayBuffer));
 
396
        if (!noRunDep) removeRunDependency('al ' + url);
 
397
      }, function(event) {
 
398
        if (onerror) {
 
399
          onerror();
 
400
        } else {
 
401
          throw 'Loading data file "' + url + '" failed.';
 
402
        }
 
403
      });
 
404
      if (!noRunDep) addRunDependency('al ' + url);
 
405
    },
 
406
 
 
407
    resizeListeners: [],
 
408
 
 
409
    updateResizeListeners: function() {
 
410
      var canvas = Module['canvas'];
 
411
      Browser.resizeListeners.forEach(function(listener) {
 
412
        listener(canvas.width, canvas.height);
 
413
      });
 
414
    },
 
415
 
 
416
    setCanvasSize: function(width, height, noUpdates) {
 
417
      var canvas = Module['canvas'];
 
418
      canvas.width = width;
 
419
      canvas.height = height;
 
420
      if (!noUpdates) Browser.updateResizeListeners();
 
421
    },
 
422
 
 
423
    windowedWidth: 0,
 
424
    windowedHeight: 0,
 
425
    setFullScreenCanvasSize: function() {
 
426
      var canvas = Module['canvas'];
 
427
      this.windowedWidth = canvas.width;
 
428
      this.windowedHeight = canvas.height;
 
429
      canvas.width = screen.width;
 
430
      canvas.height = screen.height;
 
431
      var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
 
432
      flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
 
433
      {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
 
434
      Browser.updateResizeListeners();
 
435
    },
 
436
    
 
437
    setWindowedCanvasSize: function() {
 
438
      var canvas = Module['canvas'];
 
439
      canvas.width = this.windowedWidth;
 
440
      canvas.height = this.windowedHeight;
 
441
      var flags = {{{ makeGetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'i32', 0, 1) }}};
 
442
      flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
 
443
      {{{ makeSetValue('SDL.screen+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}}
 
444
      Browser.updateResizeListeners();
 
445
    }
 
446
    
 
447
  },
 
448
 
 
449
  emscripten_async_wget: function(url, file, onload, onerror) {
 
450
    var _url = Pointer_stringify(url);
 
451
    var _file = Pointer_stringify(file);
 
452
    var index = _file.lastIndexOf('/');
 
453
    FS.createPreloadedFile(
 
454
      _file.substr(0, index),
 
455
      _file.substr(index +1),
 
456
      _url, true, true,
 
457
      function() {
 
458
        if (onload) Runtime.dynCall('vi', onload, [file]);
 
459
      },
 
460
      function() {
 
461
        if (onerror) Runtime.dynCall('vi', onerror, [file]);
 
462
      }
 
463
    );
 
464
  },
 
465
 
 
466
  emscripten_async_wget_data: function(url, arg, onload, onerror) {
 
467
    Browser.asyncLoad(Pointer_stringify(url), function(byteArray) {
 
468
      var buffer = _malloc(byteArray.length);
 
469
      HEAPU8.set(byteArray, buffer);
 
470
      Runtime.dynCall('viii', onload, [arg, buffer, byteArray.length]);
 
471
      _free(buffer);
 
472
    }, function() {
 
473
      if (onerror) Runtime.dynCall('vi', onerror, [arg]);
 
474
    }, true /* no need for run dependency, this is async but will not do any prepare etc. step */ );
 
475
  },
 
476
 
 
477
  emscripten_async_wget2: function(url, file, request, param, arg, onload, onerror, onprogress) {
 
478
    var _url = Pointer_stringify(url);
 
479
    var _file = Pointer_stringify(file);
 
480
    var _request = Pointer_stringify(request);
 
481
    var _param = Pointer_stringify(param);
 
482
    var index = _file.lastIndexOf('/');
 
483
     
 
484
    var http = new XMLHttpRequest();
 
485
    http.open(_request, _url, true);
 
486
    http.responseType = 'arraybuffer';
 
487
    
 
488
    // LOAD
 
489
    http.onload = function(e) {
 
490
      if (http.status == 200) {
 
491
        FS.createDataFile( _file.substr(0, index), _file.substr(index + 1), new Uint8Array(http.response), true, true);
 
492
        if (onload) Runtime.dynCall('vii', onload, [arg, file]);
 
493
      } else {
 
494
        if (onerror) Runtime.dynCall('vii', onerror, [arg, http.status]);
 
495
      }
 
496
    };
 
497
      
 
498
    // ERROR
 
499
    http.onerror = function(e) {
 
500
      if (onerror) Runtime.dynCall('vii', onerror, [arg, http.status]);
 
501
    };
 
502
        
 
503
    // PROGRESS
 
504
    http.onprogress = function(e) {
 
505
      var percentComplete = (e.position / e.totalSize)*100;
 
506
      if (onprogress) Runtime.dynCall('vii', onprogress, [arg, percentComplete]);
 
507
    };
 
508
          
 
509
    // Useful because the browser can limit the number of redirection
 
510
    try {  
 
511
      if (http.channel instanceof Ci.nsIHttpChannel)
 
512
      http.channel.redirectionLimit = 0;
 
513
    } catch (ex) { /* whatever */ }
 
514
 
 
515
    if (_request == "POST") {
 
516
      //Send the proper header information along with the request
 
517
      http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 
518
      http.setRequestHeader("Content-length", _param.length);
 
519
      http.setRequestHeader("Connection", "close");
 
520
      http.send(_param);
 
521
    } else {
 
522
      http.send(null);
 
523
    }
 
524
  },
 
525
  
 
526
  emscripten_async_prepare: function(file, onload, onerror) {
 
527
    var _file = Pointer_stringify(file);
 
528
    var data = FS.analyzePath(_file);
 
529
    if (!data.exists) return -1;
 
530
    var index = _file.lastIndexOf('/');
 
531
    FS.createPreloadedFile(
 
532
      _file.substr(0, index),
 
533
      _file.substr(index +1),
 
534
      new Uint8Array(data.object.contents), true, true,
 
535
      function() {
 
536
        if (onload) Runtime.dynCall('vi', onload, [file]);
 
537
      },
 
538
      function() {
 
539
        if (onerror) Runtime.dynCall('vi', onerror, [file]);
 
540
      },
 
541
      true // don'tCreateFile - it's already there
 
542
    );
 
543
    return 0;
 
544
  },
 
545
 
 
546
  emscripten_async_prepare_data: function(data, size, suffix, arg, onload, onerror) {
 
547
    var _suffix = Pointer_stringify(suffix);
 
548
    if (!Browser.asyncPrepareDataCounter) Browser.asyncPrepareDataCounter = 0;
 
549
    var name = 'prepare_data_' + (Browser.asyncPrepareDataCounter++) + '.' + _suffix;
 
550
    var cname = _malloc(name.length+1);
 
551
    writeStringToMemory(name, cname);
 
552
    FS.createPreloadedFile(
 
553
      '',
 
554
      name,
 
555
      {{{ makeHEAPView('U8', 'data', 'data + size') }}},
 
556
      true, true,
 
557
      function() {
 
558
        if (onload) Runtime.dynCall('vii', onload, [arg, cname]);
 
559
      },
 
560
      function() {
 
561
        if (onerror) Runtime.dynCall('vi', onerror, [arg]);
 
562
      },
 
563
      true // don'tCreateFile - it's already there
 
564
    );
 
565
    return 0;
 
566
  },
 
567
 
 
568
  emscripten_async_run_script__deps: ['emscripten_run_script'],
 
569
  emscripten_async_run_script: function(script, millis) {
 
570
    Module['noExitRuntime'] = true;
 
571
 
 
572
    // TODO: cache these to avoid generating garbage
 
573
    setTimeout(function() {
 
574
      _emscripten_run_script(script);
 
575
    }, millis);
 
576
  },
 
577
 
 
578
  emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop) {
 
579
    Module['noExitRuntime'] = true;
 
580
 
 
581
    Browser.mainLoop.runner = function() {
 
582
      if (Browser.mainLoop.queue.length > 0) {
 
583
        var start = Date.now();
 
584
        var blocker = Browser.mainLoop.queue.shift();
 
585
        blocker.func(blocker.arg);
 
586
        if (Browser.mainLoop.remainingBlockers) {
 
587
          var remaining = Browser.mainLoop.remainingBlockers;
 
588
          var next = remaining%1 == 0 ? remaining-1 : Math.floor(remaining);
 
589
          if (blocker.counted) {
 
590
            Browser.mainLoop.remainingBlockers = next;
 
591
          } else {
 
592
            // not counted, but move the progress along a tiny bit
 
593
            next = next + 0.5; // do not steal all the next one's progress
 
594
            Browser.mainLoop.remainingBlockers = (8*remaining + next)/9;
 
595
          }
 
596
        }
 
597
        console.log('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + ' ms'); //, left: ' + Browser.mainLoop.remainingBlockers);
 
598
        Browser.mainLoop.updateStatus();
 
599
        setTimeout(Browser.mainLoop.runner, 0);
 
600
        return;
 
601
      }
 
602
      if (Browser.mainLoop.shouldPause) {
 
603
        // catch pauses from non-main loop sources
 
604
        Browser.mainLoop.paused = true;
 
605
        Browser.mainLoop.shouldPause = false;
 
606
        return;
 
607
      }
 
608
 
 
609
      if (Module['preMainLoop']) {
 
610
        Module['preMainLoop']();
 
611
      }
 
612
 
 
613
      Runtime.dynCall('v', func);
 
614
 
 
615
      if (Module['postMainLoop']) {
 
616
        Module['postMainLoop']();
 
617
      }
 
618
 
 
619
      if (Browser.mainLoop.shouldPause) {
 
620
        // catch pauses from the main loop itself
 
621
        Browser.mainLoop.paused = true;
 
622
        Browser.mainLoop.shouldPause = false;
 
623
        return;
 
624
      }
 
625
      Browser.mainLoop.scheduler();
 
626
    }
 
627
    if (fps && fps > 0) {
 
628
      Browser.mainLoop.scheduler = function() {
 
629
        setTimeout(Browser.mainLoop.runner, 1000/fps); // doing this each time means that on exception, we stop
 
630
      }
 
631
    } else {
 
632
      Browser.mainLoop.scheduler = function() {
 
633
        Browser.requestAnimationFrame(Browser.mainLoop.runner);
 
634
      }
 
635
    }
 
636
    Browser.mainLoop.scheduler();
 
637
 
 
638
    if (simulateInfiniteLoop) {
 
639
      throw 'SimulateInfiniteLoop';
 
640
    }
 
641
  },
 
642
 
 
643
  emscripten_cancel_main_loop: function() {
 
644
    Browser.mainLoop.scheduler = null;
 
645
    Browser.mainLoop.shouldPause = true;
 
646
  },
 
647
 
 
648
  emscripten_pause_main_loop: function() {
 
649
    Browser.mainLoop.pause();
 
650
  },
 
651
 
 
652
  emscripten_resume_main_loop: function() {
 
653
    Browser.mainLoop.resume();
 
654
  },
 
655
 
 
656
  _emscripten_push_main_loop_blocker: function(func, arg, name) {
 
657
    Browser.mainLoop.queue.push({ func: function() {
 
658
      Runtime.dynCall('vi', func, [arg]);
 
659
    }, name: Pointer_stringify(name), counted: true });
 
660
    Browser.mainLoop.updateStatus();
 
661
  },
 
662
 
 
663
  _emscripten_push_uncounted_main_loop_blocker: function(func, arg, name) {
 
664
    Browser.mainLoop.queue.push({ func: function() {
 
665
      Runtime.dynCall('vi', func, [arg]);
 
666
    }, name: Pointer_stringify(name), counted: false });
 
667
    Browser.mainLoop.updateStatus();
 
668
  },
 
669
 
 
670
  emscripten_set_main_loop_expected_blockers: function(num) {
 
671
    Browser.mainLoop.expectedBlockers = num;
 
672
    Browser.mainLoop.remainingBlockers = num;
 
673
    Browser.mainLoop.updateStatus();
 
674
  },
 
675
 
 
676
  emscripten_async_call: function(func, arg, millis) {
 
677
    Module['noExitRuntime'] = true;
 
678
 
 
679
    function wrapper() {
 
680
      Runtime.getFuncWrapper(func, 'vi')(arg);
 
681
    }
 
682
 
 
683
    if (millis >= 0) {
 
684
      setTimeout(wrapper, millis);
 
685
    } else {
 
686
      Browser.requestAnimationFrame(wrapper);
 
687
    }
 
688
  },
 
689
 
 
690
  emscripten_hide_mouse: function() {
 
691
    var styleSheet = document.styleSheets[0];
 
692
    var rules = styleSheet.cssRules;
 
693
    for (var i = 0; i < rules.length; i++) {
 
694
      if (rules[i].cssText.substr(0, 5) == 'canvas') {
 
695
        styleSheet.deleteRule(i);
 
696
        i--;
 
697
      }
 
698
    }
 
699
    styleSheet.insertRule('canvas.emscripten { border: 1px solid black; cursor: none; }', 0);
 
700
  },
 
701
 
 
702
  emscripten_set_canvas_size: function(width, height) {
 
703
    Browser.setCanvasSize(width, height);
 
704
  },
 
705
 
 
706
  emscripten_get_now: function() {
 
707
    if (ENVIRONMENT_IS_NODE) {
 
708
        var t = process['hrtime']();
 
709
        return t[0] * 1e3 + t[1] / 1e6;
 
710
    }
 
711
    else if (window['performance'] && window['performance']['now']) {
 
712
      return window['performance']['now']();
 
713
    } else {
 
714
      return Date.now();
 
715
    }
 
716
  },
 
717
 
 
718
  emscripten_create_worker: function(url) {
 
719
    url = Pointer_stringify(url);
 
720
    var id = Browser.workers.length;
 
721
    var info = {
 
722
      worker: new Worker(url),
 
723
      callbacks: [],
 
724
      awaited: 0,
 
725
      buffer: 0,
 
726
      bufferSize: 0
 
727
    };
 
728
    info.worker.onmessage = function(msg) {
 
729
      var info = Browser.workers[id];
 
730
      if (!info) return; // worker was destroyed meanwhile
 
731
      var callbackId = msg.data['callbackId'];
 
732
      var callbackInfo = info.callbacks[callbackId];
 
733
      if (!callbackInfo) return; // no callback or callback removed meanwhile
 
734
      info.awaited--;
 
735
      info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this
 
736
      var data = msg.data['data'];
 
737
      if (data) {
 
738
        if (!data.byteLength) data = new Uint8Array(data);
 
739
        if (!info.buffer || info.bufferSize < data.length) {
 
740
          if (info.buffer) _free(info.buffer);
 
741
          info.bufferSize = data.length;
 
742
          info.buffer = _malloc(data.length);
 
743
        }
 
744
        HEAPU8.set(data, info.buffer);
 
745
        callbackInfo.func(info.buffer, data.length, callbackInfo.arg);
 
746
      } else {
 
747
        callbackInfo.func(0, 0, callbackInfo.arg);
 
748
      }
 
749
    };
 
750
    Browser.workers.push(info);
 
751
    return id;
 
752
  },
 
753
 
 
754
  emscripten_destroy_worker: function(id) {
 
755
    var info = Browser.workers[id];
 
756
    info.worker.terminate();
 
757
    if (info.buffer) _free(info.buffer);
 
758
    Browser.workers[id] = null;
 
759
  },
 
760
 
 
761
  emscripten_call_worker: function(id, funcName, data, size, callback, arg) {
 
762
    funcName = Pointer_stringify(funcName);
 
763
    var info = Browser.workers[id];
 
764
    var callbackId = -1;
 
765
    if (callback) {
 
766
      callbackId = info.callbacks.length;
 
767
      info.callbacks.push({
 
768
        func: Runtime.getFuncWrapper(callback, 'viii'),
 
769
        arg: arg
 
770
      });
 
771
      info.awaited++;
 
772
    }
 
773
    info.worker.postMessage({
 
774
      'funcName': funcName,
 
775
      'callbackId': callbackId,
 
776
      'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705
 
777
    });
 
778
  },
 
779
 
 
780
  emscripten_worker_respond: function(data, size) {
 
781
    if (!inWorkerCall) throw 'not in worker call!';
 
782
    if (workerResponded) throw 'already responded!';
 
783
    workerResponded = true;
 
784
    postMessage({
 
785
      'callbackId': workerCallbackId,
 
786
      'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0 // XXX copy to a new typed array as a workaround for chrome bug 169705
 
787
    });
 
788
  },
 
789
 
 
790
  emscripten_get_worker_queue_size: function(id) {
 
791
    var info = Browser.workers[id];
 
792
    if (!info) return -1;
 
793
    return info.awaited;
 
794
  }
 
795
});
 
796
 
 
797
/* Useful stuff for browser debugging
 
798
 
 
799
function slowLog(label, text) {
 
800
  if (!slowLog.labels) slowLog.labels = {};
 
801
  if (!slowLog.labels[label]) slowLog.labels[label] = 0;
 
802
  var now = Date.now();
 
803
  if (now - slowLog.labels[label] > 1000) {
 
804
    Module.print(label + ': ' + text);
 
805
    slowLog.labels[label] = now;
 
806
  }
 
807
}
 
808
 
 
809
*/
 
810