diff -Nru emscripten-1.9.0~20140119~7dc8c2f/AUTHORS emscripten-1.10.0~20140205~ef1e460/AUTHORS --- emscripten-1.9.0~20140119~7dc8c2f/AUTHORS 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/AUTHORS 2014-02-05 17:48:09.000000000 +0000 @@ -118,3 +118,5 @@ * Alexandre Perrot * Emerson José Silveira da Costa * Jari Vetoniemi +* Sindre Sorhus +* James S Urquhart diff -Nru emscripten-1.9.0~20140119~7dc8c2f/ChangeLog emscripten-1.10.0~20140205~ef1e460/ChangeLog --- emscripten-1.9.0~20140119~7dc8c2f/ChangeLog 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/ChangeLog 2014-02-05 17:48:09.000000000 +0000 @@ -12,12 +12,12 @@ - To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see https://github.com/kripken/emscripten/compare/1.8.2...incoming -v1.8.2: 1/4/2013 +v1.8.2: 1/4/2014 ------------------ - Fixed glGetFramebufferAttachmentParameteriv and an issue with glGetXXX when the returned value was null. - Full list of changes: https://github.com/kripken/emscripten/compare/1.8.1...1.8.2 -v1.8.1: 1/3/2013 +v1.8.1: 1/3/2014 ------------------ - Added support for WebGL hardware instancing extension. - Improved fastcomp native LLVM backend support. diff -Nru emscripten-1.9.0~20140119~7dc8c2f/debian/changelog emscripten-1.10.0~20140205~ef1e460/debian/changelog --- emscripten-1.9.0~20140119~7dc8c2f/debian/changelog 2014-01-19 13:59:47.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/debian/changelog 2014-02-05 17:53:44.000000000 +0000 @@ -1,3 +1,11 @@ +emscripten (1.10.0~20140205~ef1e460-1) unstable; urgency=medium + + * New snapshot release + * Also install cmake / emscripten files. Thanks to Daniele Di Proietto + for the patch + + -- Sylvestre Ledru Wed, 05 Feb 2014 18:46:19 +0100 + emscripten (1.9.0~20140119~7dc8c2f-1) unstable; urgency=low * New snapshot release (Closes: #733714) diff -Nru emscripten-1.9.0~20140119~7dc8c2f/debian/emscripten.install emscripten-1.10.0~20140205~ef1e460/debian/emscripten.install --- emscripten-1.9.0~20140119~7dc8c2f/debian/emscripten.install 2013-11-30 17:08:24.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/debian/emscripten.install 2014-02-05 17:46:10.000000000 +0000 @@ -1,3 +1,4 @@ +cmake/ /usr/share/emscripten src/ /usr/share/emscripten system/ /usr/share/emscripten tools/ /usr/share/emscripten diff -Nru emscripten-1.9.0~20140119~7dc8c2f/emcc emscripten-1.10.0~20140205~ef1e460/emcc --- emscripten-1.9.0~20140119~7dc8c2f/emcc 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/emcc 2014-02-05 17:48:09.000000000 +0000 @@ -61,6 +61,7 @@ DYNAMICLIB_ENDINGS = ('.dylib', '.so', '.dll') STATICLIB_ENDINGS = ('.a',) ASSEMBLY_ENDINGS = ('.ll',) +HEADER_ENDINGS = ('.h', '.hxx', '.hpp', '.hh', '.H', '.HXX', '.HPP', '.HH') LIB_PREFIXES = ('', 'lib') @@ -146,7 +147,7 @@ This is the recommended setting when you want a reasonably optimized build that is generated as - quickly as possible (it is much faster than -O2). + quickly as possible (it builds much faster than -O2). (Note: for details on the affects of different opt levels, see apply_opt_level() in @@ -158,20 +159,12 @@ time in return for the smallest and fastest output. - -O3 As -O2, plus dangerous optimizations that may - break the generated code! This adds + -O3 As -O2, plus additional optimizations that can + take a significant amount of compilation time and/or + are relatively new. - -s FORCE_ALIGNED_MEMORY=1 - -s DOUBLE_MODE=0 - -s PRECISE_I64_MATH=0 - --closure 1 - --llvm-lto 3 - - This is not recommended at all. A better idea - is to try each of these separately on top of - -O2 to see what works. See the wiki and - src/settings.js (for the -s options) for more - information. + For tips on optimizing your code, see + https://github.com/kripken/emscripten/wiki/Optimizing-Code -s OPTION=VALUE JavaScript code generation option passed into the emscripten compiler. For the @@ -267,8 +260,7 @@ code size and may in some cases increase runtime speed (although the opposite can also occur). Note that it takes time to run, and - may require some changes to the code. This - is run by default in -O3. + may require some changes to the code. In asm.js mode, closure will only be used on the 'shell' code around the compiled code (the @@ -494,10 +486,13 @@ libraries, and after any link-time optimizations (if any). - --memory-init-file If on, we generate a separate memory initialization - file. This is more efficient than storing the - memory initialization data embedded inside - JavaScript as text. (default is off) + --memory-init-file 0: Do not emit a separate memory initialization + file, keep the static initialization inside + the generated JavaScript as text (default) + 1: Emit a separate memory initialization file + in binary format. This is more efficient than + storing it as text inside JavaScript, but does + mean you have another file to publish. -Wno-warn-absolute-paths If not specified, the compiler will warn about any uses of absolute paths in -I and -L command line @@ -705,15 +700,12 @@ sys.exit(0) use_cxx = True -header = False # pre-compiled headers. We fake that by just copying the file for i in range(1, len(sys.argv)): arg = sys.argv[i] if not arg.startswith('-'): if arg.endswith(('.c','.m')): use_cxx = False - if arg.endswith('.h') and sys.argv[i-1] != '-include': - header = True if '-M' in sys.argv or '-MM' in sys.argv: # Just output dependencies, do not compile. Warning: clang and gcc behave differently with -MF! (clang seems to not recognize it) @@ -747,15 +739,6 @@ else: final_suffix = '' -if header: # header or such - if len(sys.argv) >= 3: # if there is a source and a target, then copy, otherwise do nothing - sys.argv = filter(lambda arg: not arg.startswith('-I'), sys.argv) - logging.debug('Just copy:' + sys.argv[-1] + target) - shutil.copy(sys.argv[-1], target) - else: - logging.debug('No-op.') - exit(0) - if TEMP_DIR: temp_dir = TEMP_DIR if os.path.exists(temp_dir): @@ -781,6 +764,14 @@ suffix = filename_type_suffix(filename) return '' if not suffix else ('.' + suffix) +# Log out times for emcc stages +log_time_last = time.time() +def log_time(name): + global log_time_last + now = time.time() + logging.debug('emcc step "%s" took %.2f seconds' % (name, now - log_time_last)) + log_time_last = now + try: call = CXX if use_cxx else CC @@ -1029,9 +1020,7 @@ if js_opts is None: js_opts = opt_level >= 2 if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] - if llvm_lto is None and opt_level >= 3: llvm_lto = 3 if opt_level == 0: debug_level = 4 - if closure is None and opt_level == 3: closure = True if llvm_lto is None and bind: logging.debug('running lto for embind') # XXX this is a workaround for a pointer issue @@ -1066,6 +1055,7 @@ input_files = [] has_source_inputs = False + has_header_inputs = False lib_dirs = [shared.path_from_root('system', 'local', 'lib'), shared.path_from_root('system', 'lib')] libs = [] @@ -1077,7 +1067,7 @@ prev = newargs[i-1] if prev in ['-MT', '-MF', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L']: continue # ignore this gcc-style argument - if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS)): + if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS)): arg = os.path.realpath(arg) if not arg.startswith('-'): @@ -1086,11 +1076,14 @@ exit(1) arg_ending = filename_type_ending(arg) - if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o , so all these should be inputs + if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o , so all these should be inputs newargs[i] = '' if arg_ending.endswith(SOURCE_ENDINGS): input_files.append(arg) has_source_inputs = True + elif arg_ending.endswith(HEADER_ENDINGS): + input_files.append(arg) + has_header_inputs = True elif arg_ending.endswith(ASSEMBLY_ENDINGS) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid input_files.append(arg) elif arg_ending.endswith(STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS): @@ -1129,7 +1122,7 @@ # -c means do not link in gcc, and for us, the parallel is to not go all the way to JS, but stop at bitcode has_dash_c = '-c' in newargs if has_dash_c: - assert has_source_inputs, 'Must have source code inputs to use -c' + assert has_source_inputs or has_header_inputs, 'Must have source code or header inputs to use -c' target = target_basename + '.o' final_suffix = 'o' @@ -1163,7 +1156,7 @@ input_files = filter(lambda input_file: check(input_file), input_files) if len(input_files) == 0: - logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + STATICLIB_ENDINGS + ASSEMBLY_ENDINGS)) + logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + STATICLIB_ENDINGS + ASSEMBLY_ENDINGS + HEADER_ENDINGS)) exit(0) newargs = CC_ADDITIONAL_ARGS + newargs @@ -1196,7 +1189,6 @@ shared.Settings.ASM_JS = 1 assert shared.Settings.ALLOW_MEMORY_GROWTH == 0, 'memory growth not supported in fastcomp yet' assert shared.Settings.UNALIGNED_MEMORY == 0, 'forced unaligned memory not supported in fastcomp' - assert shared.Settings.SAFE_HEAP == 0, 'safe heap not supported in fastcomp yet' assert shared.Settings.CHECK_HEAP_ALIGN == 0, 'check heap align not supported in fastcomp yet' assert shared.Settings.SAFE_DYNCALLS == 0, 'safe dyncalls not supported in fastcomp' assert shared.Settings.RESERVED_FUNCTION_POINTERS == 0, 'reserved function pointers not supported in fastcomp' @@ -1230,6 +1222,14 @@ shared.Settings.CORRECT_OVERFLOWS = 1 assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' + if shared.Settings.SAFE_HEAP and not js_opts: + js_opts = True + logging.warning('enabling js opts to allow SAFE_HEAP to work properly') + + if shared.Settings.ALLOW_MEMORY_GROWTH: + logging.error('Cannot enable ALLOW_MEMORY_GROWTH with asm.js, build with -s ASM_JS=0 if you need a growable heap'); + sys.exit(1); + if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2: debug_level = 4 # must keep debug info to do line-by-line operations @@ -1295,6 +1295,17 @@ temp_files = [] + log_time('parse arguments and setup') + + # Precompiled headers support + if has_header_inputs: + for header in input_files: + assert header.endswith(HEADER_ENDINGS), 'if you have one header input, we assume you want to precompile headers, and cannot have source files or other inputs as well: ' + str(input_files) + ' : ' + header + args = newargs + shared.EMSDK_CXX_OPTS + input_files + logging.debug("running (for precompiled headers: " + call + ' ' + ' '.join(args)) + execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) + sys.exit(1) + # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for input_file in input_files: file_ending = filename_type_ending(input_file) @@ -1334,6 +1345,8 @@ logging.error(input_file + ': Unknown file suffix when compiling to LLVM bitcode!') sys.exit(1) + log_time('bitcodeize inputs') + if not LEAVE_INPUTS_RAW: assert len(temp_files) == len(input_files) @@ -1380,6 +1393,8 @@ shared.Building.link(temp_files, specified_target) exit(0) + log_time('bitcodeize inputs') + ## Continue on to create JavaScript logging.debug('will generate JavaScript') @@ -1582,6 +1597,7 @@ 'wctomb.c', ]], ['regex', [ + 'fnmatch.c', 'regcomp.c', 'regerror.c', 'regexec.c', @@ -1752,15 +1768,14 @@ libfile = shared.Cache.get(name, create) extra_files_to_link.append(libfile) + log_time('calculate system libraries') + # First, combine the bitcode files if there are several. We must also link if we have a singleton .a if len(input_files) + len(extra_files_to_link) > 1 or \ (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_ENDINGS or suffix(temp_files[0]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0])): linker_inputs = temp_files + extra_files_to_link logging.debug('linking: ' + str(linker_inputs)) - t0 = time.time() shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_ENDINGS), temp_files)) == 0) - t1 = time.time() - logging.debug(' linking took %.2f seconds' % (t1 - t0)) final = in_temp(target_basename + '.bc') else: if not LEAVE_INPUTS_RAW: @@ -1770,19 +1785,16 @@ final = in_temp(input_files[0]) shutil.copyfile(input_files[0], final) + log_time('link') + if DEBUG: logging.debug('saving intermediate processing steps to %s' % shared.EMSCRIPTEN_TEMP_DIR) intermediate_counter = 0 - intermediate_time = None def save_intermediate(name=None, suffix='js'): - global intermediate_counter, intermediate_time + global intermediate_counter shutil.copyfile(final, os.path.join(shared.EMSCRIPTEN_TEMP_DIR, 'emcc-%d%s.%s' % (intermediate_counter, '' if name is None else '-' + name, suffix))) intermediate_counter += 1 - now = time.time() - if intermediate_time: - logging.debug(' step took %.2f seconds' % (now - intermediate_time)) - intermediate_time = now if not LEAVE_INPUTS_RAW: save_intermediate('basebc', 'bc') @@ -1843,6 +1855,8 @@ final += '.adsimp.bc' if DEBUG: save_intermediate('adsimp', 'bc') + log_time('post-link') + # Emscripten logging.debug('LLVM => JS') extra_args = [] if not js_libraries else ['--libraries', ','.join(map(os.path.abspath, js_libraries))] @@ -1850,6 +1864,8 @@ final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args) if DEBUG: save_intermediate('original') + log_time('emscript (llvm=>js)') + # Embed and preload files if len(preload_files) + len(embed_files) > 0: logging.debug('setting up files') @@ -1910,9 +1926,7 @@ shared.try_delete(memfile) def repl(m): # handle chunking of the memory initializer - s = re.sub('[\[\]\n\(\)\. ]', '', m.groups(0)[0]) - s = s.replace('concat', ',') - if s[-1] == ',': s = s[:-1] + s = m.groups(0)[0] open(memfile, 'wb').write(''.join(map(lambda x: chr(int(x or '0')), s.split(',')))) if DEBUG: # Copy into temp dir as well, so can be run there too @@ -1923,6 +1937,7 @@ src = re.sub(shared.JS.memory_initializer_pattern, repl, open(final).read(), count=1) open(final + '.mem.js', 'w').write(src) final += '.mem.js' + src = None js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings if DEBUG: if os.path.exists(memfile): @@ -1930,6 +1945,17 @@ logging.debug('wrote memory initialization to %s' % memfile) else: logging.debug('did not see memory initialization') + elif shared.Settings.USE_TYPED_ARRAYS == 2 and not shared.Settings.MAIN_MODULE and not shared.Settings.SIDE_MODULE: + # not writing a binary init, but we can at least optimize them by splitting them up + src = open(final).read() + src = shared.JS.optimize_initializer(src) + if src is not None: + logging.debug('optimizing memory initialization') + open(final + '.mem.js', 'w').write(src) + final += '.mem.js' + src = None + + log_time('source transforms') # It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing js_optimizer_queue = [] @@ -1973,12 +1999,12 @@ else: return 'eliminate' - js_optimizer_queue += [get_eliminate()] + if opt_level >= 2: + js_optimizer_queue += [get_eliminate()] - if shared.Settings.AGGRESSIVE_VARIABLE_ELIMINATION: - js_optimizer_queue += ['aggressiveVariableElimination'] + if shared.Settings.AGGRESSIVE_VARIABLE_ELIMINATION: + js_optimizer_queue += ['aggressiveVariableElimination'] - if opt_level >= 2: js_optimizer_queue += ['simplifyExpressions'] if closure and not shared.Settings.ASM_JS: @@ -1991,15 +2017,20 @@ if DEBUG: save_intermediate('closure') if js_opts: + if shared.Settings.ASM_JS and shared.Settings.SAFE_HEAP: js_optimizer_queue += ['safeHeap'] + if shared.Settings.OUTLINING_LIMIT > 0 and shared.Settings.ASM_JS: js_optimizer_queue += ['outline'] js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT - if (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3: - js_optimizer_queue += ['registerize'] + if opt_level >= 2 and (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3: + if shared.Settings.ASM_JS and opt_level >= 3 and shared.Settings.OUTLINING_LIMIT == 0: + js_optimizer_queue += ['registerizeHarder'] + else: + js_optimizer_queue += ['registerize'] - if opt_level > 0: - if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue = map(lambda p: p if p != 'registerize' else 'registerizeAndMinify', js_optimizer_queue) + if opt_level >= 2: + if debug_level < 2 and shared.Settings.ASM_JS: js_optimizer_queue += ['minifyNames'] if debug_level == 0: js_optimizer_queue += ['minifyWhitespace'] if closure and shared.Settings.ASM_JS: @@ -2009,10 +2040,12 @@ flush_js_optimizer_queue() + log_time('js opts') + # Remove some trivial whitespace # TODO: do not run when compress has already been done on all parts of the code - src = open(final).read() - src = re.sub(r'\n+[ \n]*\n+', '\n', src) - open(final, 'w').write(src) + #src = open(final).read() + #src = re.sub(r'\n+[ \n]*\n+', '\n', src) + #open(final, 'w').write(src) def generate_source_map(map_file_base_name, offset=0): jsrun.run_js(shared.path_from_root('tools', 'source-maps', 'sourcemapper.js'), @@ -2115,6 +2148,8 @@ # copy final JS to output shutil.move(final, target) + log_time('final emitting') + if DEBUG: logging.debug('total time: %.2f seconds' % (time.time() - start_time)) finally: diff -Nru emscripten-1.9.0~20140119~7dc8c2f/emscripten.py emscripten-1.10.0~20140205~ef1e460/emscripten.py --- emscripten-1.9.0~20140119~7dc8c2f/emscripten.py 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/emscripten.py 2014-02-05 17:48:09.000000000 +0000 @@ -455,7 +455,7 @@ basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') - if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] + if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] if settings['ASSERTIONS']: basic_funcs += ['nullFunc'] @@ -725,7 +725,7 @@ outfile: The file where the output is written. """ - assert(settings['ASM_JS']) # TODO: apply ASM_JS even in -O0 for fastcomp + assert(settings['ASM_JS']) # Overview: # * Run LLVM backend to emit JS. JS includes function bodies, memory initializer, @@ -956,7 +956,7 @@ basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') - if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] + if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] if settings['ASSERTIONS']: basic_funcs += ['nullFunc'] @@ -1204,7 +1204,7 @@ if DEBUG: logging.debug(' emscript: final python processing took %s seconds' % (time.time() - t)) -if os.environ.get('EMCC_FAST_COMPILER'): +if os.environ.get('EMCC_FAST_COMPILER') == '1': emscript = emscript_fast def main(args, compiler_engine, cache, jcache, relooper, temp_files, DEBUG, DEBUG_CACHE): diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/compiler.js emscripten-1.10.0~20140205~ef1e460/src/compiler.js --- emscripten-1.9.0~20140119~7dc8c2f/src/compiler.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/compiler.js 2014-02-05 17:48:09.000000000 +0000 @@ -183,9 +183,6 @@ // Settings sanity checks assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4'); -if (ASM_JS) { - assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap'); -} assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals'); // Output some info and warnings based on settings diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/headless.js emscripten-1.10.0~20140205~ef1e460/src/headless.js --- emscripten-1.9.0~20140119~7dc8c2f/src/headless.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/headless.js 2014-02-05 17:48:09.000000000 +0000 @@ -82,6 +82,16 @@ } listeners.push(func); }, + removeEventListener: function(id, func) { + var listeners = this.eventListeners[id]; + if (!listeners) return; + for (var i = 0; i < listeners.length; i++) { + if (listeners[i] === func) { + listeners.splice(i, 1); + return; + } + } + }, callEventListeners: function(id) { var listeners = this.eventListeners[id]; if (listeners) { @@ -101,6 +111,7 @@ headless: true, eventListeners: {}, addEventListener: window.addEventListener, + removeEventListener: window.removeEventListener, callEventListeners: window.callEventListeners, getElementById: function(id) { switch(id) { @@ -144,6 +155,7 @@ }, eventListeners: {}, addEventListener: document.addEventListener, + removeEventListener: document.removeEventListener, callEventListeners: document.callEventListeners, }; }; diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/headlessCanvas.js emscripten-1.10.0~20140205~ef1e460/src/headlessCanvas.js --- emscripten-1.9.0~20140119~7dc8c2f/src/headlessCanvas.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/headlessCanvas.js 2014-02-05 17:48:09.000000000 +0000 @@ -600,6 +600,7 @@ style: {}, eventListeners: {}, addEventListener: function(){}, + removeEventListener: function(){}, requestFullScreen: function() { document.fullscreenElement = document.getElementById('canvas'); window.setTimeout(function() { diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/jsifier.js emscripten-1.10.0~20140205~ef1e460/src/jsifier.js --- emscripten-1.9.0~20140119~7dc8c2f/src/jsifier.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/jsifier.js 2014-02-05 17:48:09.000000000 +0000 @@ -1844,7 +1844,7 @@ // rest of the output that we started to print out earlier (see comment on the // "Final shape that will be created"). if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { - if (!INCLUDE_FULL_LIBRARY) { + if (!INCLUDE_FULL_LIBRARY && !SIDE_MODULE) { // first row are utilities called from generated code, second are needed from fastLong ['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr', 'llvm_ctlz_i32', 'llvm_cttz_i32'].forEach(function(func) { @@ -1866,6 +1866,7 @@ } }); } + // these may be duplicated in side modules and the main module without issue print(read('fastLong.js')); print('// EMSCRIPTEN_END_FUNCS\n'); print(read('long.js')); diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/library.js emscripten-1.10.0~20140205~ef1e460/src/library.js --- emscripten-1.9.0~20140119~7dc8c2f/src/library.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/library.js 2014-02-05 17:48:09.000000000 +0000 @@ -100,7 +100,7 @@ return FS.handleFSError(e); } if (stream.position < 0 || stream.position >= entries.length) { - {{{ makeSetValue('result', '0', '0', 'i8*') }}} + {{{ makeSetValue('result', '0', '0', 'i8*') }}}; return 0; } var id; @@ -118,15 +118,15 @@ FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link. 8; // DT_REG, regular file. } - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}} - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}} - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}} + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}}; + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}}; + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}}; for (var i = 0; i < name.length; i++) { - {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}}; } - {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}} - {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}} - {{{ makeSetValue('result', '0', 'entry', 'i8*') }}} + {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}}; + {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}}; + {{{ makeSetValue('result', '0', 'entry', 'i8*') }}}; stream.position++; return 0; }, @@ -149,8 +149,6 @@ } return {{{ makeGetValue(0, '_readdir.result', 'i8*') }}}; }, - __01readdir64_: 'readdir', - // TODO: Check if we need to link any other aliases. // ========================================================================== // utime.h @@ -164,7 +162,7 @@ if (times) { // NOTE: We don't keep track of access timestamps. var offset = {{{ C_STRUCTS.utimbuf.modtime }}}; - time = {{{ makeGetValue('times', 'offset', 'i32') }}} + time = {{{ makeGetValue('times', 'offset', 'i32') }}}; time *= 1000; } else { time = Date.now(); @@ -207,13 +205,13 @@ var length = i; if (allSlashes) { // All slashes result in a single slash. - {{{ makeSetValue('path', '1', '0', 'i8') }}} + {{{ makeSetValue('path', '1', '0', 'i8') }}}; return [path, -1]; } else { // Strip trailing slashes. while (slashPositions.length && slashPositions[slashPositions.length - 1] == length - 1) { - {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}} + {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}}; length--; } return [path, slashPositions.pop()]; @@ -227,16 +225,15 @@ var result = ___libgenSplitName(path); return result[0] + result[1] + 1; }, - __xpg_basename: 'basename', dirname__deps: ['__libgenSplitName'], dirname: function(path) { // char *dirname(char *path); // http://pubs.opengroup.org/onlinepubs/007908799/xsh/dirname.html var result = ___libgenSplitName(path); if (result[1] == 0) { - {{{ makeSetValue('result[0]', 1, '0', 'i8') }}} + {{{ makeSetValue('result[0]', 1, '0', 'i8') }}}; } else if (result[1] !== -1) { - {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}} + {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}}; } return result[0]; }, @@ -257,22 +254,22 @@ {{{ makeSetValue('buf', C_STRUCTS.stat.st_dev, 'stat.dev', 'i32') }}}; {{{ makeSetValue('buf', C_STRUCTS.stat.__st_dev_padding, '0', 'i32') }}}; {{{ makeSetValue('buf', C_STRUCTS.stat.__st_ino_truncated, 'stat.ino', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}} + {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}}; {{{ makeSetValue('buf', C_STRUCTS.stat.__st_rdev_padding, '0', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}} + {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}}; return 0; } catch (e) { FS.handleFSError(e); @@ -395,14 +392,6 @@ _umask.cmask = newMask; return oldMask; }, - stat64: 'stat', - fstat64: 'fstat', - lstat64: 'lstat', - __01fstat64_: 'fstat', - __01stat64_: 'stat', - __01lstat64_: 'lstat', - - // TODO: Check if other aliases are needed. // ========================================================================== // sys/statvfs.h @@ -414,17 +403,17 @@ // int statvfs(const char *restrict path, struct statvfs *restrict buf); // NOTE: None of the constants here are true. We're just returning safe and // sane values. - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}} - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}} // ST_NOSUID - {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}} + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}}; // ST_NOSUID + {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}}; return 0; }, fstatvfs__deps: ['statvfs'], @@ -433,8 +422,6 @@ // http://pubs.opengroup.org/onlinepubs/009604499/functions/statvfs.html return _statvfs(0, buf); }, - __01statvfs64_: 'statvfs', - __01fstatvfs64_: 'fstatvfs', // ========================================================================== // fcntl.h @@ -515,7 +502,7 @@ var arg = {{{ makeGetValue('varargs', 0, 'i32') }}}; var offset = {{{ C_STRUCTS.flock.l_type }}}; // We're always unlocked. - {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}} + {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}}; return 0; case {{{ cDefine('F_SETLK') }}}: case {{{ cDefine('F_SETLKW') }}}: @@ -571,6 +558,25 @@ }, // ========================================================================== + // nl_types.h + // ========================================================================== + + catopen: function(name, oflag) { + // nl_catd catopen (const char *name, int oflag) + return -1; + }, + + catgets: function(catd, set_id, msg_id, s) { + // char *catgets (nl_catd catd, int set_id, int msg_id, const char *s) + return s; + }, + + catclose: function(catd) { + // int catclose (nl_catd catd) + return 0; + }, + + // ========================================================================== // poll.h // ========================================================================== @@ -594,7 +600,7 @@ } mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}}; if (mask) nonzero++; - {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}} + {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}}; } return nonzero; }, @@ -1174,9 +1180,9 @@ } else { var length = Math.min(len, value.length); for (var i = 0; i < length; i++) { - {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}}; } - if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}} + if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}}; return i; } }, @@ -1223,9 +1229,9 @@ // int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); // http://linux.die.net/man/2/getresuid // We have just one process/group/user, all with ID 0. - {{{ makeSetValue('ruid', '0', '0', 'i32') }}} - {{{ makeSetValue('euid', '0', '0', 'i32') }}} - {{{ makeSetValue('suid', '0', '0', 'i32') }}} + {{{ makeSetValue('ruid', '0', '0', 'i32') }}}; + {{{ makeSetValue('euid', '0', '0', 'i32') }}}; + {{{ makeSetValue('suid', '0', '0', 'i32') }}}; return 0; }, getresgid: 'getresuid', @@ -1237,7 +1243,7 @@ ___setErrNo(ERRNO_CODES.EINVAL); return -1; } else { - {{{ makeSetValue('grouplist', '0', '0', 'i32') }}} + {{{ makeSetValue('grouplist', '0', '0', 'i32') }}}; return 1; } }, @@ -1270,10 +1276,10 @@ } var length = Math.min(namelen, host.length); for (var i = 0; i < length; i++) { - {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}}; } if (namelen > length) { - {{{ makeSetValue('name', 'i', '0', 'i8') }}} + {{{ makeSetValue('name', 'i', '0', 'i8') }}}; return 0; } else { ___setErrNo(ERRNO_CODES.ENAMETOOLONG); @@ -1390,8 +1396,8 @@ for (var i = 0; i < nbytes; i += 2) { var first = {{{ makeGetValue('src', 'i', 'i8') }}}; var second = {{{ makeGetValue('src', 'i + 1', 'i8') }}}; - {{{ makeSetValue('dest', 'i', 'second', 'i8') }}} - {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}} + {{{ makeSetValue('dest', 'i', 'second', 'i8') }}}; + {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}}; } }, tcgetpgrp: function(fildes) { @@ -1565,14 +1571,6 @@ if (bytes != 0) self.alloc(bytes); return ret; // Previous break location. }, - open64: 'open', - lseek64: 'lseek', - ftruncate64: 'ftruncate', - __01open64_: 'open', - __01lseek64_: 'lseek', - __01truncate64_: 'truncate', - __01ftruncate64_: 'ftruncate', - // TODO: Check if any other aliases are needed. // ========================================================================== // stdio.h @@ -1804,7 +1802,7 @@ break; case 'X': case 'x': - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}} + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}; break; case 'F': case 'f': @@ -1815,15 +1813,15 @@ case 'E': // fallthrough intended if (long_) { - {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}} + {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}}; } else { - {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}} + {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}}; } break; case 's': var array = intArrayFromString(text); for (var j = 0; j < array.length; j++) { - {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}} + {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}; } break; } @@ -2259,7 +2257,7 @@ case 'n': { // Write the length written so far to the next parameter. var ptr = getNextArg('i32*'); - {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}} + {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}}; break; } case '%': { @@ -2386,9 +2384,9 @@ ___setErrNo(ERRNO_CODES.ESPIPE); return -1; } - {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}} + {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}}; var state = (stream.eof ? 1 : 0) + (stream.error ? 2 : 0); - {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}} + {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}}; return 0; }, fgets__deps: ['fgetc'], @@ -2405,9 +2403,9 @@ if (streamObj.error || (streamObj.eof && i == 0)) return 0; else if (streamObj.eof) break; } - {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}} + {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}}; } - {{{ makeSetValue('s', 'i', '0', 'i8') }}} + {{{ makeSetValue('s', 'i', '0', 'i8') }}}; return s; }, gets__deps: ['fgets'], @@ -2471,7 +2469,7 @@ // int fputc(int c, FILE *stream); // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html var chr = unSign(c & 0xFF); - {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}} + {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}}; var ret = _write(stream, _fputc.ret, 1); if (ret == -1) { var streamObj = FS.getStream(stream); @@ -2525,7 +2523,7 @@ return 0; } while (streamObj.ungotten.length && bytesToRead > 0) { - {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}} + {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}}; bytesToRead--; bytesRead++; } @@ -2568,7 +2566,6 @@ return 0; }, fseeko: 'fseek', - fseeko64: 'fseek', fsetpos__deps: ['$FS', 'lseek', '__setErrNo', '$ERRNO_CODES'], fsetpos: function(stream, pos) { // int fsetpos(FILE *stream, const fpos_t *pos); @@ -2605,7 +2602,6 @@ } }, ftello: 'ftell', - ftello64: 'ftell', fwrite__deps: ['$FS', 'write'], fwrite: function(ptr, size, nitems, stream) { // size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); @@ -2897,22 +2893,6 @@ }, #endif - fopen64: 'fopen', - __01fopen64_: 'fopen', - __01freopen64_: 'freopen', - __01fseeko64_: 'fseek', - __01ftello64_: 'ftell', - __01tmpfile64_: 'tmpfile', - __isoc99_fscanf: 'fscanf', - // TODO: Check if any other aliases are needed. - _IO_getc: 'getc', - _IO_putc: 'putc', - _ZNSo3putEc: 'putchar', - _ZNSo5flushEv__deps: ['fflush', 'stdout'], - _ZNSo5flushEv: function() { - _fflush({{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}}); - }, - // ========================================================================== // sys/mman.h // ========================================================================== @@ -2950,7 +2930,6 @@ _mmap.mappings[ptr] = { malloc: ptr, num: num, allocated: allocated }; return ptr; }, - __01mmap64_: 'mmap', munmap: function(start, num) { if (!_mmap.mappings) _mmap.mappings = {}; @@ -3147,7 +3126,7 @@ // Set end pointer. if (endptr) { - {{{ makeSetValue('endptr', 0, 'str', '*') }}} + {{{ makeSetValue('endptr', 0, 'str', '*') }}}; } // Unsign if needed. @@ -3233,7 +3212,7 @@ // Set end pointer. if (endptr) { - {{{ makeSetValue('endptr', 0, 'str', '*') }}} + {{{ makeSetValue('endptr', 0, 'str', '*') }}}; } try { @@ -3327,7 +3306,7 @@ poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC); envPtr = allocate(MAX_ENV_VALUES * {{{ Runtime.QUANTUM_SIZE }}}, 'i8*', ALLOC_STATIC); - {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}} + {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}}; {{{ makeSetValue(makeGlobalUse('_environ'), 0, 'envPtr', 'i8*') }}}; } else { envPtr = {{{ makeGetValue(makeGlobalUse('_environ'), '0', 'i8**') }}}; @@ -3451,7 +3430,7 @@ var limit = Math.min(nelem, 3); var doubleSize = {{{ Runtime.getNativeTypeSize('double') }}}; for (var i = 0; i < limit; i++) { - {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}} + {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}}; } return limit; }, @@ -3480,9 +3459,9 @@ } else { var size = Math.min(4095, absolute.path.length); // PATH_MAX - 1. for (var i = 0; i < size; i++) { - {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}} + {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}}; } - {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}} + {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}}; return resolved_name; } }, @@ -3690,7 +3669,7 @@ var padding = 0, curr = 0, i = 0; while ((i|0) < (num|0)) { curr = padding ? 0 : {{{ makeGetValueAsm('psrc', 'i', 'i8') }}}; - {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}} + {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}}; padding = padding ? 1 : ({{{ makeGetValueAsm('psrc', 'i', 'i8') }}} == 0); i = (i+1)|0; } @@ -3743,7 +3722,7 @@ if ({{{ makeGetValue('pdest', 'len+i', 'i8') }}} == 0) break; i ++; if (i == num) { - {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}} + {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}}; break; } } @@ -3830,6 +3809,7 @@ }, strnlen: function(ptr, num) { + num = num >>> 0; for (var i = 0; i < num; i++) { if ({{{ makeGetValue('ptr', 0, 'i8') }}} == 0) return i; ptr++; @@ -4110,7 +4090,7 @@ var i16size = {{{ Runtime.getNativeTypeSize('i16') }}}; var arr = _malloc(values.length * i16size); for (var i = 0; i < values.length; i++) { - {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}} + {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}}; } me.ret = allocate([arr + 128 * i16size], 'i16*', ALLOC_NORMAL); } @@ -4138,7 +4118,7 @@ var i32size = {{{ Runtime.getNativeTypeSize('i32') }}}; var arr = _malloc(values.length * i32size); for (var i = 0; i < values.length; i++) { - {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}} + {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}; } me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL); } @@ -4165,7 +4145,7 @@ var i32size = {{{ Runtime.getNativeTypeSize('i32') }}}; var arr = _malloc(values.length * i32size); for (var i = 0; i < values.length; i++) { - {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}} + {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}; } me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL); } @@ -4311,6 +4291,8 @@ abort('trap!'); }, + llvm_prefetch: function(){}, + __assert_fail: function(condition, filename, line, func) { ABORT = true; throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + stackTrace(); @@ -4336,21 +4318,36 @@ _ZTVN10__cxxabiv120__si_class_type_infoE: [2], // yes inherited classes #endif + // We store an extra header in front of the exception data provided + // by the user. + // This header is: + // * type + // * destructor function pointer + // This is then followed by the actual exception data. + __cxa_exception_header_size: 8, + __cxa_last_thrown_exception: 0, + __cxa_caught_exceptions: [], + // Exceptions + __cxa_allocate_exception__deps: ['__cxa_exception_header_size'], __cxa_allocate_exception: function(size) { - return _malloc(size); + var ptr = _malloc(size + ___cxa_exception_header_size); + return ptr + ___cxa_exception_header_size; }, + __cxa_free_exception__deps: ['__cxa_exception_header_size'], __cxa_free_exception: function(ptr) { try { - return _free(ptr); + return _free(ptr - ___cxa_exception_header_size); } catch(e) { // XXX FIXME #if ASSERTIONS Module.printErr('exception during cxa_free_exception: ' + e); #endif } }, + // Here, we throw an exception after recording a couple of values that we need to remember + // We also remember that it was the last exception thrown as we need to know that later. __cxa_throw__sig: 'viii', - __cxa_throw__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], + __cxa_throw__deps: ['_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch', '__cxa_exception_header_size', '__cxa_last_thrown_exception'], __cxa_throw: function(ptr, type, destructor) { if (!___cxa_throw.initialized) { try { @@ -4367,28 +4364,34 @@ #if EXCEPTION_DEBUG Module.printErr('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + stackTrace()); #endif - {{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}} - {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}} - {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}} + var header = ptr - ___cxa_exception_header_size; + {{{ makeSetValue('header', 0, 'type', 'void*') }}}; + {{{ makeSetValue('header', 4, 'destructor', 'void*') }}}; + ___cxa_last_thrown_exception = ptr; if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) { __ZSt18uncaught_exceptionv.uncaught_exception = 1; } else { __ZSt18uncaught_exceptionv.uncaught_exception++; } - {{{ makeThrow('ptr') }}}; + {{{ makeThrow('ptr') }}} }, - __cxa_rethrow__deps: ['llvm_eh_exception', '__cxa_end_catch'], + // This exception will be caught twice, but while begin_catch runs twice, + // we early-exit from end_catch when the exception has been rethrown, so + // pop that here from the caught exceptions. + __cxa_rethrow__deps: ['__cxa_end_catch', '__cxa_caught_exceptions'], __cxa_rethrow: function() { ___cxa_end_catch.rethrown = true; - {{{ makeThrow(makeGetValue('_llvm_eh_exception.buf', '0', 'void*')) }}}; + var ptr = ___cxa_caught_exceptions.pop(); + {{{ makeThrow('ptr') }}} }, - llvm_eh_exception__postset: '_llvm_eh_exception.buf = allocate(12, "void*", ALLOC_STATIC);', + llvm_eh_exception__deps: ['__cxa_last_thrown_exception'], llvm_eh_exception: function() { - return {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; + return ___cxa_last_thrown_exception; }, llvm_eh_selector__jsargs: true, + llvm_eh_selector__deps: ['__cxa_last_thrown_exception'], llvm_eh_selector: function(unused_exception_value, personality/*, varargs*/) { - var type = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}} + var type = ___cxa_last_thrown_exception; for (var i = 2; i < arguments.length; i++) { if (arguments[i] == type) return type; } @@ -4397,12 +4400,22 @@ llvm_eh_typeid_for: function(type) { return type; }, - __cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv'], + // Note that we push the last thrown exception here rather than the ptr. + // This is because if the exception is a pointer (as in test 3 of test_exceptions_typed), + // we don't actually get the value that we allocated, but something else. Easiest + // to remember that the last exception thrown is going to be the first to be caught, + // so just use that value instead as it is what we're really looking for. + __cxa_begin_catch__deps: ['_ZSt18uncaught_exceptionv', '__cxa_caught_exceptions'], __cxa_begin_catch: function(ptr) { __ZSt18uncaught_exceptionv.uncaught_exception--; + ___cxa_caught_exceptions.push(___cxa_last_thrown_exception); return ptr; }, - __cxa_end_catch__deps: ['llvm_eh_exception', '__cxa_free_exception'], + // We're done with a catch. Now, we can run the destructor if there is one + // and free the exception. Note that if the dynCall on the destructor fails + // due to calling apply on undefined, that means that the destructor is + // an invalid index into the FUNCTION_TABLE, so something has gone wrong. + __cxa_end_catch__deps: ['__cxa_free_exception', '__cxa_last_thrown_exception', '___cxa_exception_header_size', '__cxa_caught_exceptions'], __cxa_end_catch: function() { if (___cxa_end_catch.rethrown) { ___cxa_end_catch.rethrown = false; @@ -4414,22 +4427,20 @@ #else __THREW__ = 0; #endif - // Clear type. - {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}} // Call destructor if one is registered then clear it. - var ptr = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; - var destructor = {{{ makeGetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'void*') }}}; - if (destructor) { - Runtime.dynCall('vi', destructor, [ptr]); - {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}} - } - // Free ptr if it isn't null. + var ptr = ___cxa_caught_exceptions.pop(); if (ptr) { + header = ptr - ___cxa_exception_header_size; + var destructor = {{{ makeGetValue('header', 4, 'void*') }}}; + if (destructor) { + Runtime.dynCall('vi', destructor, [ptr]); + {{{ makeSetValue('header', 4, '0', 'i32') }}}; + } ___cxa_free_exception(ptr); - {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}} + ___cxa_last_thrown_exception = 0; } }, - __cxa_get_exception_ptr__deps: ['llvm_eh_exception'], + __cxa_get_exception_ptr__deps: ['___cxa_last_thrown_exception'], __cxa_get_exception_ptr: function(ptr) { return ptr; }, @@ -4447,17 +4458,9 @@ throw exception; }, - _Unwind_Resume_or_Rethrow: function(ptr) { - {{{ makeThrow('ptr') }}}; - }, - _Unwind_RaiseException: function(ptr) { - {{{ makeThrow('ptr') }}}; - }, - _Unwind_DeleteException: function(ptr) {}, - terminate: '__cxa_call_unexpected', - __gxx_personality_v0__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], + __gxx_personality_v0__deps: ['_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'], __gxx_personality_v0: function() { }, @@ -4490,10 +4493,11 @@ // functionality boils down to picking a suitable 'catch' block. // We'll do that here, instead, to keep things simpler. - __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type', '__resumeException'], + __cxa_find_matching_catch__deps: ['__cxa_does_inherit', '__cxa_is_number_type', '__resumeException', '__cxa_last_thrown_exception', '__cxa_exception_header_size'], __cxa_find_matching_catch: function(thrown, throwntype) { - if (thrown == -1) thrown = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}}; - if (throwntype == -1) throwntype = {{{ makeGetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'void*') }}}; + if (thrown == -1) thrown = ___cxa_last_thrown_exception; + header = thrown - ___cxa_exception_header_size; + if (throwntype == -1) throwntype = {{{ makeGetValue('header', 0, 'void*') }}}; var typeArray = Array.prototype.slice.call(arguments, 2); // If throwntype is a pointer, this means a pointer has been @@ -4524,8 +4528,8 @@ #if EXCEPTION_DEBUG Module.print("Resuming exception"); #endif - if ({{{ makeGetValue('_llvm_eh_exception.buf', 0, 'void*') }}} == 0) {{{ makeSetValue('_llvm_eh_exception.buf', 0, 'ptr', 'void*') }}}; - {{{ makeThrow('ptr') }}}; + if (!___cxa_last_thrown_exception) { ___cxa_last_thrown_exception = ptr; } + {{{ makeThrow('ptr') }}} }, // Recursively walks up the base types of 'possibilityType' @@ -4567,7 +4571,20 @@ } }, - _ZNSt9exceptionD2Ev: function(){}, // XXX a dependency of dlmalloc, but not actually needed if libcxx is not anyhow included + // 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. + _ZNSt9exceptionD1Ev: function() {}, + _ZNSt9exceptionD2Ev: function() {}, + + _ZNKSt9exception4whatEv__deps: ['_malloc'], + _ZNKSt9exception4whatEv: function() { + if (!__ZNKSt9exception4whatEv.buffer) { + var name = "std::exception"; + __ZNKSt9exception4whatEv.buffer = _malloc(name.length + 1); + writeStringToMemory(name, __ZNKSt9exception4whatEv.buffer); + } + return __ZNKSt9exception4whatEv.buffer; + }, _ZNSt9type_infoD2Ev: function(){}, @@ -4837,11 +4854,11 @@ cbrtl: 'cbrt', modf: function(x, intpart) { - {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}} + {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}}; return x - {{{ makeGetValue('intpart', 0, 'double') }}}; }, modff: function(x, intpart) { - {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}} + {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}}; return x - {{{ makeGetValue('intpart', 0, 'float') }}}; }, frexp: function(x, exp_addr) { @@ -4857,7 +4874,7 @@ if (exp_ === raw_exp) exp_ += 1; sig = sign*x/Math.pow(2, exp_); } - {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}} + {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}}; return sig; }, frexpf: 'frexp', @@ -5365,7 +5382,7 @@ time: function(ptr) { var ret = Math.floor(Date.now()/1000); if (ptr) { - {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}} + {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}}; } return ret; }, @@ -5392,9 +5409,9 @@ {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}}, {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}}, 0).getTime() / 1000; - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}}; var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24)); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; return timestamp; }, timelocal: 'mktime', @@ -5407,15 +5424,15 @@ gmtime_r__deps: ['__tm_timezone'], gmtime_r: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}; var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC start.setUTCDate(1); start.setUTCMonth(0); @@ -5424,8 +5441,8 @@ start.setUTCSeconds(0); start.setUTCMilliseconds(0); var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}; return tmPtr; }, @@ -5448,23 +5465,23 @@ localtime_r: function(time, tmPtr) { _tzset(); var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}; var start = new Date(date.getFullYear(), 0, 1); var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}} - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}}; var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset()); - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}}; - {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}} + {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}; return tmPtr; }, @@ -5482,9 +5499,9 @@ var timePart = formatted.match(/\d{2}:\d{2}:\d{2}/)[0]; formatted = datePart + timePart + ' ' + date.getFullYear() + '\n'; formatted.split('').forEach(function(chr, index) { - {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}} + {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}}; }); - {{{ makeSetValue('buf', '25', '0', 'i8') }}} + {{{ makeSetValue('buf', '25', '0', 'i8') }}}; return buf; }, @@ -5514,18 +5531,18 @@ if (_tzset.called) return; _tzset.called = true; - {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}} + {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}}; var winter = new Date(2000, 0, 1); var summer = new Date(2000, 6, 1); - {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}} + {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}}; var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1]; var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1]; var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL); var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL); - {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}} - {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}} + {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}}; + {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}}; }, stime__deps: ['$ERRNO_CODES', '__setErrNo'], @@ -6095,15 +6112,15 @@ */ var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0); - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}} - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}} + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}; // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F // TODO: not sure that intArrayFromString handles all unicode characters correctly @@ -6134,8 +6151,8 @@ var seconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_sec, 'i32') }}}; var nanoseconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_nsec, 'i32') }}}; if (rmtp !== 0) { - {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}} - {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}} + {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}}; + {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}}; } return _usleep((seconds * 1e6) + (nanoseconds / 1000)); }, @@ -6166,7 +6183,7 @@ } else { nsec = _emscripten_get_now_res(); } - {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}} + {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}}; {{{ makeSetValue('res', C_STRUCTS.timespec.tv_nsec, 'nsec', 'i32') }}} // resolution is milliseconds return 0; }, @@ -6250,9 +6267,6 @@ label = label|0; table = table|0; var i = 0; -#if ASSERTIONS - if ((label|0) == 0) abort(121); -#endif setjmpId = (setjmpId+1)|0; {{{ makeSetValueAsm('env', '0', 'setjmpId', 'i32') }}}; while ((i|0) < {{{ 2*MAX_SETJMPS }}}) { @@ -6310,6 +6324,10 @@ throw { longjmp: true, id: {{{ makeGetValue('env', '0', 'i32') }}}, value: value || 1 }; #endif }, + emscripten_longjmp__deps: ['longjmp'], + emscripten_longjmp: function(env, value) { + _longjmp(env, value); + }, // ========================================================================== // signal.h @@ -6847,7 +6865,7 @@ __setErrNo__postset: '___errno_state = Runtime.staticAlloc(4); {{{ makeSetValue("___errno_state", 0, 0, "i32") }}};', __setErrNo: function(value) { // For convenient setting and returning of errno. - {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}} + {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}}; return value; }, __errno_location__deps: ['__setErrNo'], @@ -6871,15 +6889,14 @@ // int setrlimit(int resource, const struct rlimit *rlp) return 0; }, - __01getrlimit64_: 'getrlimit', // TODO: Implement for real. We just do time used, and no useful data getrusage: function(resource, rlp) { // int getrusage(int resource, struct rusage *rlp); - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}} - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}} - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}} - {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}} + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}}; + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}}; + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}}; + {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}}; return 0; }, @@ -6943,8 +6960,8 @@ void **restrict stackaddr, size_t *restrict stacksize); */ /*FIXME: assumes that there is only one thread, and that attr is the current thread*/ - {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}} - {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}} + {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}}; + {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}}; return 0; }, @@ -6962,7 +6979,7 @@ if (key == 0) { return ERRNO_CODES.EINVAL; } - {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}} + {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}}; // values start at 0 PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0; PTHREAD_SPECIFIC_NEXT_KEY++; @@ -7020,7 +7037,7 @@ posix_memalign__deps: ['memalign'], posix_memalign: function(memptr, alignment, size) { var ptr = _memalign(alignment, size); - {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}} + {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}}; return 0; }, @@ -7062,7 +7079,7 @@ if (addr === null) { return 0; } - {{{ makeSetValue('inp', '0', 'addr', 'i32') }}} + {{{ makeSetValue('inp', '0', 'addr', 'i32') }}}; return 1; }, @@ -7221,7 +7238,7 @@ if (ret === null) { return 0; } - {{{ makeSetValue('dst', '0', 'ret', 'i32') }}} + {{{ makeSetValue('dst', '0', 'ret', 'i32') }}}; return 1; }, _inet_pton6_raw__deps: ['htons'], @@ -7344,6 +7361,12 @@ // netdb.h // ========================================================================== + __h_errno_state: 'allocate(1, "i32", ALLOC_STATIC)', + __h_errno_location__deps: ['__h_errno_state'], + __h_errno_location: function() { + return ___h_errno_state; + }, + // We can't actually resolve hostnames in the browser, so instead // we're generating fake IP addresses with lookup_name that we can // resolve later on with lookup_addr. @@ -7399,6 +7422,7 @@ gethostbyaddr: function (addr, addrlen, type) { if (type !== {{{ cDefine('AF_INET') }}}) { ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); + // TODO: set h_errno return null; } addr = {{{ makeGetValue('addr', '0', 'i32') }}}; // addr is in_addr @@ -7419,18 +7443,18 @@ var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here var nameBuf = _malloc(name.length+1); writeStringToMemory(name, nameBuf); - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}} + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}}; var aliasesBuf = _malloc(4); - {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}} - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}} + {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}}; + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}}; var afinet = {{{ cDefine('AF_INET') }}}; - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}} - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}} + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}}; + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}}; var addrListBuf = _malloc(12); - {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}} - {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}} - {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}} - {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}} + {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}}; + {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}}; + {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}}; + {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}}; return ret; }, @@ -7606,7 +7630,7 @@ node = DNS.lookup_name(node); addr = __inet_pton4_raw(node); if (family === {{{ cDefine('AF_UNSPEC') }}}) { - family = {{{ cDefine('AF_INET') }}} + family = {{{ cDefine('AF_INET') }}}; } else if (family === {{{ cDefine('AF_INET6') }}}) { addr = [0, 0, _htonl(0xffff), addr]; } @@ -9176,6 +9200,30 @@ // misc shims for musl __lockfile: function() { return 1 }, __unlockfile: function(){}, + + // misc definitions to avoid unnecessary unresolved symbols from fastcomp + emscripten_prep_setjmp: true, + emscripten_check_longjmp: true, + emscripten_get_longjmp_result: true, + emscripten_setjmp: true, + emscripten_preinvoke: true, + emscripten_postinvoke: true, + emscripten_resume: true, + emscripten_landingpad: true, + getHigh32: true, + setHigh32: true, + FtoILow: true, + FtoIHigh: true, + DtoILow: true, + DtoIHigh: true, + BDtoILow: true, + BDtoIHigh: true, + SItoF: true, + UItoF: true, + SItoD: true, + UItoD: true, + BItoD: true, + llvm_dbg_value: true, }; function autoAddDeps(object, name) { @@ -9188,7 +9236,7 @@ } // Add aborting stubs for various libc stuff needed by libc++ -['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose'].forEach(function(aborter) { +['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach'].forEach(function(aborter) { LibraryManager.library[aborter] = function aborting_stub() { throw 'TODO: ' + aborter }; }); diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/library_gl.js emscripten-1.10.0~20140205~ef1e460/src/library_gl.js --- emscripten-1.9.0~20140119~7dc8c2f/src/library_gl.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/library_gl.js 2014-02-05 17:48:09.000000000 +0000 @@ -957,7 +957,11 @@ usage = 0x88E8; // GL_DYNAMIC_DRAW break; } - GLctx.bufferData(target, HEAPU8.subarray(data, data+size), usage); + if (!data) { + GLctx.bufferData(target, size, usage); + } else { + GLctx.bufferData(target, HEAPU8.subarray(data, data+size), usage); + } }, glBufferSubData__sig: 'viiii', @@ -2380,7 +2384,7 @@ // GL Immediate mode // See comment in GLEmulation.init() -#if FULL_ES2 == 0 +#if !FULL_ES2 $GLImmediate__postset: 'GLImmediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GLImmediate.init() });', #endif $GLImmediate__deps: ['$Browser', '$GL', '$GLEmulation'], @@ -2644,7 +2648,7 @@ return "float"; } - return Abort_NoSupport("Unsupported combiner op: 0x" + op.toString(16)); + return abort_noSupport("Unsupported combiner op: 0x" + op.toString(16)); } function getCurTexUnit() { @@ -2997,7 +3001,7 @@ } } - return Abort_NoSupport("Unsupported TexEnv mode: 0x" + this.mode.toString(16)); + return abort_noSupport("Unsupported TexEnv mode: 0x" + this.mode.toString(16)); } CTexEnv.prototype.genCombinerLines = function CTexEnv_getCombinerLines(isColor, outputVar, @@ -3417,6 +3421,107 @@ Module.printErr('WARNING: Unhandled `pname` in call to `glTexEnvfv`.'); } }, + + hook_getTexEnviv: function(target, pname, param) { + if (target != GL_TEXTURE_ENV) + return; + + var env = getCurTexUnit().env; + switch (pname) { + case GL_TEXTURE_ENV_MODE: + {{{ makeSetValue('param', '0', 'env.mode', 'i32') }}}; + return; + + case GL_TEXTURE_ENV_COLOR: + {{{ makeSetValue('param', '0', 'Math.max(Math.min(env.envColor[0]*255, 255, -255))', 'i32') }}}; + {{{ makeSetValue('param', '1', 'Math.max(Math.min(env.envColor[1]*255, 255, -255))', 'i32') }}}; + {{{ makeSetValue('param', '2', 'Math.max(Math.min(env.envColor[2]*255, 255, -255))', 'i32') }}}; + {{{ makeSetValue('param', '3', 'Math.max(Math.min(env.envColor[3]*255, 255, -255))', 'i32') }}}; + return; + + case GL_COMBINE_RGB: + {{{ makeSetValue('param', '0', 'env.colorCombiner', 'i32') }}}; + return; + + case GL_COMBINE_ALPHA: + {{{ makeSetValue('param', '0', 'env.alphaCombiner', 'i32') }}}; + return; + + case GL_SRC0_RGB: + {{{ makeSetValue('param', '0', 'env.colorSrc[0]', 'i32') }}}; + return; + + case GL_SRC1_RGB: + {{{ makeSetValue('param', '0', 'env.colorSrc[1]', 'i32') }}}; + return; + + case GL_SRC2_RGB: + {{{ makeSetValue('param', '0', 'env.colorSrc[2]', 'i32') }}}; + return; + + case GL_SRC0_ALPHA: + {{{ makeSetValue('param', '0', 'env.alphaSrc[0]', 'i32') }}}; + return; + + case GL_SRC1_ALPHA: + {{{ makeSetValue('param', '0', 'env.alphaSrc[1]', 'i32') }}}; + return; + + case GL_SRC2_ALPHA: + {{{ makeSetValue('param', '0', 'env.alphaSrc[2]', 'i32') }}}; + return; + + case GL_OPERAND0_RGB: + {{{ makeSetValue('param', '0', 'env.colorOp[0]', 'i32') }}}; + return; + + case GL_OPERAND1_RGB: + {{{ makeSetValue('param', '0', 'env.colorOp[1]', 'i32') }}}; + return; + + case GL_OPERAND2_RGB: + {{{ makeSetValue('param', '0', 'env.colorOp[2]', 'i32') }}}; + return; + + case GL_OPERAND0_ALPHA: + {{{ makeSetValue('param', '0', 'env.alphaOp[0]', 'i32') }}}; + return; + + case GL_OPERAND1_ALPHA: + {{{ makeSetValue('param', '0', 'env.alphaOp[1]', 'i32') }}}; + return; + + case GL_OPERAND2_ALPHA: + {{{ makeSetValue('param', '0', 'env.alphaOp[2]', 'i32') }}}; + return; + + case GL_RGB_SCALE: + {{{ makeSetValue('param', '0', 'env.colorScale', 'i32') }}}; + return; + + case GL_ALPHA_SCALE: + {{{ makeSetValue('param', '0', 'env.alphaScale', 'i32') }}}; + return; + + default: + Module.printErr('WARNING: Unhandled `pname` in call to `glGetTexEnvi`.'); + } + }, + + hook_getTexEnvfv: function(target, pname, param) { + if (target != GL_TEXTURE_ENV) + return; + + var env = getCurTexUnit().env; + switch (pname) { + case GL_TEXTURE_ENV_COLOR: + {{{ makeSetValue('param', '0', 'env.envColor[0]', 'float') }}}; + {{{ makeSetValue('param', '4', 'env.envColor[1]', 'float') }}}; + {{{ makeSetValue('param', '8', 'env.envColor[2]', 'float') }}}; + {{{ makeSetValue('param', '12', 'env.envColor[3]', 'float') }}}; + return; + } + } }; }, @@ -3501,6 +3606,11 @@ GLImmediate.enabledClientAttributes[name] = true; GLImmediate.setClientAttribute(name, size, type, 0, GLImmediate.rendererComponentPointer); GLImmediate.rendererComponentPointer += size * GL.byteSizeByType[type - GL.byteSizeByTypeRoot]; +#if GL_FFP_ONLY + // We can enable the correct attribute stream index immediately here, since the same attribute in each shader + // will be bound to this same index. + GL.enableVertexAttribArray(name); +#endif } else { GLImmediate.rendererComponents[name]++; } @@ -3733,7 +3843,8 @@ GLctx.bindAttribLocation(this.program, GLImmediate.VERTEX, 'a_position'); GLctx.bindAttribLocation(this.program, GLImmediate.COLOR, 'a_color'); GLctx.bindAttribLocation(this.program, GLImmediate.NORMAL, 'a_normal'); - for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) { + var maxVertexAttribs = GLctx.getParameter(GLctx.MAX_VERTEX_ATTRIBS); + for (var i = 0; i < GLImmediate.MAX_TEXTURES && GLImmediate.TEXTURE0 + i < maxVertexAttribs; i++) { GLctx.bindAttribLocation(this.program, GLImmediate.TEXTURE0 + i, 'a_texCoord'+i); GLctx.bindAttribLocation(this.program, GLImmediate.TEXTURE0 + i, aTexCoordPrefix+i); } @@ -3760,7 +3871,7 @@ this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, aTexCoordPrefix + i); } } - + this.colorLocation = GLctx.getAttribLocation(this.program, 'a_color'); if (!useCurrProgram) { // Temporarily switch to the program so we can set our sampler uniforms early. var prevBoundProg = GLctx.getParameter(GLctx.CURRENT_PROGRAM); @@ -3772,6 +3883,9 @@ GLctx.uniform1i(texSamplerLoc, texUnitID); } } + // The default color attribute value is not the same as the default for all other attribute streams (0,0,0,1) but (1,1,1,1), + // so explicitly set it right at start. + GLctx.vertexAttrib4fv(this.colorLocation, [1,1,1,1]); GLctx.useProgram(prevBoundProg); } @@ -3779,7 +3893,6 @@ for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) { this.textureMatrixLocations[i] = GLctx.getUniformLocation(this.program, 'u_textureMatrix' + i); } - this.colorLocation = GLctx.getAttribLocation(this.program, 'a_color'); this.normalLocation = GLctx.getAttribLocation(this.program, 'a_normal'); this.modelViewLocation = GLctx.getUniformLocation(this.program, 'u_modelView'); @@ -3872,11 +3985,9 @@ #if GL_FFP_ONLY if (!GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.VERTEX, posAttr.size, posAttr.type, false, GLImmediate.stride, posAttr.offset); - GL.enableVertexAttribArray(GLImmediate.VERTEX); if (this.hasNormal) { var normalAttr = clientAttributes[GLImmediate.NORMAL]; GLctx.vertexAttribPointer(GLImmediate.NORMAL, normalAttr.size, normalAttr.type, true, GLImmediate.stride, normalAttr.offset); - GL.enableVertexAttribArray(GLImmediate.NORMAL); } } #else @@ -3899,11 +4010,9 @@ var texAttr = clientAttributes[attribLoc]; if (texAttr.size) { GLctx.vertexAttribPointer(attribLoc, texAttr.size, texAttr.type, false, GLImmediate.stride, texAttr.offset); - GL.enableVertexAttribArray(attribLoc); } else { // These two might be dangerous, but let's try them. GLctx.vertexAttrib4f(attribLoc, 0, 0, 0, 1); - GL.disableVertexAttribArray(attribLoc); } } #else @@ -3938,21 +4047,18 @@ #if GL_FFP_ONLY if (!GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.COLOR, colorAttr.size, colorAttr.type, true, GLImmediate.stride, colorAttr.offset); - GL.enableVertexAttribArray(GLImmediate.COLOR); } #else GLctx.vertexAttribPointer(this.colorLocation, colorAttr.size, colorAttr.type, true, GLImmediate.stride, colorAttr.offset); GLctx.enableVertexAttribArray(this.colorLocation); #endif - } else if (this.hasColor) { -#if GL_FFP_ONLY - GL.disableVertexAttribArray(GLImmediate.COLOR); - GLctx.vertexAttrib4fv(GLImmediate.COLOR, GLImmediate.clientColor); -#else + } +#if !GL_FFP_ONLY + else if (this.hasColor) { GLctx.disableVertexAttribArray(this.colorLocation); GLctx.vertexAttrib4fv(this.colorLocation, GLImmediate.clientColor); -#endif } +#endif if (this.hasFog) { if (this.fogColorLocation) GLctx.uniform4fv(this.fogColorLocation, GLEmulation.fogColor); if (this.fogEndLocation) GLctx.uniform1f(this.fogEndLocation, GLEmulation.fogEnd); @@ -3979,6 +4085,7 @@ } if (!GL.currProgram) { GLctx.useProgram(null); + GLImmediate.fixedFunctionProgram = 0; } if (!GL.currArrayBuffer) { GLctx.bindBuffer(GLctx.ARRAY_BUFFER, null); @@ -4092,6 +4199,14 @@ //glTexEnvfv(target, pname, param); }; + _glGetTexEnviv = function _glGetTexEnviv(target, pname, param) { + GLImmediate.TexEnvJIT.hook_getTexEnviv(target, pname, param); + }; + + _glGetTexEnvfv = function _glGetTexEnvfv(target, pname, param) { + GLImmediate.TexEnvJIT.hook_getTexEnvfv(target, pname, param); + }; + var glGetIntegerv = _glGetIntegerv; _glGetIntegerv = function _glGetIntegerv(pname, params) { switch (pname) { @@ -4348,7 +4463,7 @@ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.buffers[GL.currElementArrayBuffer] || null); } -#if GL_UNSAFE_OPTS == 0 +#if !GL_UNSAFE_OPTS #if !GL_FFP_ONLY renderer.cleanup(); #endif @@ -4461,6 +4576,9 @@ GLImmediate.clientColor[1] = g; GLImmediate.clientColor[2] = b; GLImmediate.clientColor[3] = a; +#if GL_FFP_ONLY + GLctx.vertexAttrib4fv(GLImmediate.COLOR, GLImmediate.clientColor); +#endif } }, glColor4d: 'glColor4f', @@ -4608,6 +4726,10 @@ GLImmediate.enabledClientAttributes[attrib] = true; GLImmediate.totalEnabledClientAttributes++; GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed. +#if GL_FFP_ONLY + // In GL_FFP_ONLY mode, attributes are bound to the same index in each FFP emulation shader, so we can immediately apply the change here. + GL.enableVertexAttribArray(attrib); +#endif if (GLEmulation.currentVao) GLEmulation.currentVao.enabledClientStates[cap] = 1; GLImmediate.modifiedClientAttributes = true; } @@ -4624,6 +4746,10 @@ GLImmediate.enabledClientAttributes[attrib] = false; GLImmediate.totalEnabledClientAttributes--; GLImmediate.currentRenderer = null; // Will need to change current renderer, since the set of active vertex pointers changed. +#if GL_FFP_ONLY + // In GL_FFP_ONLY mode, attributes are bound to the same index in each FFP emulation shader, so we can immediately apply the change here. + GL.disableVertexAttribArray(attrib); +#endif if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledClientStates[cap]; GLImmediate.modifiedClientAttributes = true; } @@ -4635,7 +4761,6 @@ #if GL_FFP_ONLY if (GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.VERTEX, size, type, false, stride, pointer); - GL.enableVertexAttribArray(GLImmediate.VERTEX); } #endif }, @@ -4645,7 +4770,6 @@ if (GL.currArrayBuffer) { var loc = GLImmediate.TEXTURE0 + GLImmediate.clientActiveTexture; GLctx.vertexAttribPointer(loc, size, type, false, stride, pointer); - GL.enableVertexAttribArray(loc); } #endif }, @@ -4654,7 +4778,6 @@ #if GL_FFP_ONLY if (GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.NORMAL, size, type, true, stride, pointer); - GL.enableVertexAttribArray(GLImmediate.NORMAL); } #endif }, @@ -4663,7 +4786,6 @@ #if GL_FFP_ONLY if (GL.currArrayBuffer) { GLctx.vertexAttribPointer(GLImmediate.COLOR, size, type, true, stride, pointer); - GL.enableVertexAttribArray(GLImmediate.COLOR); } #endif }, @@ -4877,6 +4999,9 @@ glTexEnvf: function() { Runtime.warnOnce('glTexEnvf: TODO') }, glTexEnvfv: function() { Runtime.warnOnce('glTexEnvfv: TODO') }, + glGetTexEnviv: function(target, pname, param) { throw 'GL emulation not initialized!'; }, + glGetTexEnvfv: function(target, pname, param) { throw 'GL emulation not initialized!'; }, + glTexImage1D: function() { throw 'glTexImage1D: TODO' }, glTexCoord3f: function() { throw 'glTexCoord3f: TODO' }, glGetTexLevelParameteriv: function() { throw 'glGetTexLevelParameteriv: TODO' }, diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/library_html5.js emscripten-1.10.0~20140205~ef1e460/src/library_html5.js --- emscripten-1.9.0~20140119~7dc8c2f/src/library_html5.js 1970-01-01 00:00:00.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/library_html5.js 2014-02-05 17:48:09.000000000 +0000 @@ -0,0 +1,1257 @@ +var LibraryJSEvents = { + $JSEvents: { + // pointers to structs malloc()ed to Emscripten HEAP for JS->C interop. + keyEvent: 0, + mouseEvent: 0, + wheelEvent: 0, + uiEvent: 0, + focusEvent: 0, + deviceOrientationEvent: 0, + deviceMotionEvent: 0, + fullscreenChangeEvent: 0, + pointerlockChangeEvent: 0, + visibilityChangeEvent: 0, + touchEvent: 0, + + // When the C runtime exits via exit(), we unregister all event handlers added by this library to be nice and clean. + // Track in this field whether we have yet registered that __ATEXIT__ handler. + removeEventListenersRegistered: false, + + registerRemoveEventListeners: function() { + if (!JSEvents.removeEventListenersRegistered) { + __ATEXIT__.push({ func: function() { + for(var i = JSEvents.eventHandlers.length-1; i >= 0; --i) { + JSEvents._removeHandler(i); + } + } }); + JSEvents.removeEventListenersRegistered = true; + } + }, + + findEventTarget: function(target) { + if (target) { + if (typeof target == "number") { + target = Pointer_stringify(target); + } + if (target == '#window') return window; + else if (target == '#document') return document; + else if (target == '#screen') return window.screen; + else if (target == '#canvas') return Module['canvas']; + + if (typeof target == 'string') return document.getElementById(target); + else return target; + } else { + // The sensible target varies between events, but use window as the default + // since DOM events mostly can default to that. Specific callback registrations + // override their own defaults. + return window; + } + }, + + deferredCalls: [], + + // Queues the given function call to occur the next time we enter an event handler. + // Existing implementations of pointerlock apis have required that + // the target element is active in fullscreen mode first. Thefefore give + // fullscreen mode request a precedence of 1 and pointer lock a precedence of 2 + // and sort by that to always request fullscreen before pointer lock. + deferCall: function(targetFunction, precedence, argsList) { + function arraysHaveEqualContent(arrA, arrB) { + if (arrA.length != arrB.length) return false; + + for(var i in arrA) { + if (arrA[i] != arrB[i]) return false; + } + return true; + } + // Test if the given call was already queued, and if so, don't add it again. + for(var i in JSEvents.deferredCalls) { + var call = JSEvents.deferredCalls[i]; + if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { + return; + } + } + JSEvents.deferredCalls.push({ + targetFunction: targetFunction, + precedence: precedence, + argsList: argsList + }); + + JSEvents.deferredCalls.sort(function(x,y) { return x.precedence < y.precedence; }); + }, + + // Erases all deferred calls to the given target function from the queue list. + removeDeferredCalls: function(targetFunction) { + for(var i = 0; i < JSEvents.deferredCalls.length; ++i) { + if (JSEvents.deferredCalls[i].targetFunction == targetFunction) { + JSEvents.deferredCalls.splice(i, 1); + --i; + } + } + }, + + canPerformEventHandlerRequests: function() { + return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls; + }, + + runDeferredCalls: function() { + if (!JSEvents.canPerformEventHandlerRequests()) { + return; + } + for(var i = 0; i < JSEvents.deferredCalls.length; ++i) { + var call = JSEvents.deferredCalls[i]; + JSEvents.deferredCalls.splice(i, 1); + --i; + call.targetFunction.apply(this, call.argsList); + } + }, + + // If positive, we are currently executing in a JS event handler. + inEventHandler: 0, + // If we are in an event handler, specifies the event handler object from the eventHandlers array that is currently running. + currentEventHandler: null, + + // Stores objects representing each currently registered JS event handler. + eventHandlers: [], + + _removeHandler: function(i) { + JSEvents.eventHandlers[i].target.removeEventListener(JSEvents.eventHandlers[i].eventTypeString, JSEvents.eventHandlers[i].handlerFunc, true); + JSEvents.eventHandlers.splice(i, 1); + }, + + registerOrRemoveHandler: function(eventHandler) { + var jsEventHandler = function jsEventHandler(event) { + // Increment nesting count for the event handler. + ++JSEvents.inEventHandler; + JSEvents.currentEventHandler = eventHandler; + // Process any old deferred calls the user has placed. + JSEvents.runDeferredCalls(); + // Process the actual event, calls back to user C code handler. + eventHandler.handlerFunc(event); + // Process any new deferred calls that were placed right now from this event handler. + JSEvents.runDeferredCalls(); + // Out of event handler - restore nesting count. + --JSEvents.inEventHandler; + } + + if (eventHandler.callbackfunc) { + eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture); + JSEvents.eventHandlers.push(eventHandler); + JSEvents.registerRemoveEventListeners(); + } else { + for(var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == eventHandler.target + && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { + JSEvents._removeHandler(i--); + } + } + } + }, + + registerKeyEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.keyEvent) { + JSEvents.keyEvent = _malloc( {{{ C_STRUCTS.EmscriptenKeyboardEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + writeStringToMemory(e.key ? e.key : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.key }}} ); + writeStringToMemory(e.code ? e.code : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.code }}} ); + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.location, 'e.location', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.metaKey, 'e.metaKey', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.repeat, 'e.repeat', 'i32') }}} + writeStringToMemory(e.locale ? e.locale : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.locale }}} ); + writeStringToMemory(e.char ? e.char : "", JSEvents.keyEvent + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charValue }}} ); + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.charCode, 'e.charCode', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.keyCode, 'e.keyCode', 'i32') }}} + {{{ makeSetValue('JSEvents.keyEvent', C_STRUCTS.EmscriptenKeyboardEvent.which, 'e.which', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.keyEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var isInternetExplorer = (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0); + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: isInternetExplorer ? false : true, // MSIE doesn't allow fullscreen and pointerlock requests from key handlers, others do. + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + fillMouseEventData: function(eventStruct, e) { + var rect = Module['canvas'].getBoundingClientRect(); + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.timestamp, 'JSEvents.tick()', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenX, 'e.screenX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenY, 'e.screenY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.clientX, 'e.clientX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.clientY, 'e.clientY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.metaKey, 'e.metaKey', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.button, 'e.button', 'i16') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.buttons, 'e.buttons', 'i16') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementX, 'e.movementX', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementY, 'e.movementY', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}} + }, + + registerMouseEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.mouseEvent) { + JSEvents.mouseEvent = _malloc( {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + JSEvents.fillMouseEventData(JSEvents.mouseEvent, e); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.mouseEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: eventTypeString != 'mousemove', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them! + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + registerWheelEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.wheelEvent) { + JSEvents.wheelEvent = _malloc( {{{ C_STRUCTS.EmscriptenWheelEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + JSEvents.fillMouseEventData(JSEvents.wheelEvent, e); + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaX, 'e.deltaX', 'double') }}} + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaY, 'e.deltaY', 'double') }}} + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaZ, 'e.deltaZ', 'double') }}} + {{{ makeSetValue('JSEvents.wheelEvent', C_STRUCTS.EmscriptenWheelEvent.deltaMode, 'e.deltaMode', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.wheelEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + pageScrollPos: function() { + if (window.pageXOffset > 0 || window.pageYOffset > 0) { + return [window.pageXOffset, window.pageYOffset]; + } + if (typeof document.documentElement.scrollLeft !== 'undefined' || typeof document.documentElement.scrollTop !== 'undefined') { + return [document.documentElement.scrollLeft, document.documentElement.scrollTop]; + } + return [document.body.scrollLeft|0, document.body.scrollTop|0]; + }, + + registerUiEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.uiEvent) { + JSEvents.uiEvent = _malloc( {{{ C_STRUCTS.EmscriptenUiEvent.__size__ }}} ); + } + + if (eventTypeString == "scroll" && !target) { + target = document; // By default read scroll events on document rather than window. + } else { + target = JSEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + if (e.target != target) { + // Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that + // was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log + // message box could cause to scroll, generating a new (bubbled) scroll message, causing a new log print, + // causing a new scroll, etc.. + return; + } + var scrollPos = JSEvents.pageScrollPos(); + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.detail, 'e.detail', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientWidth, 'document.body.clientWidth', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.documentBodyClientHeight, 'document.body.clientHeight', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerWidth, 'window.innerWidth', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowInnerHeight, 'window.innerHeight', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterWidth, 'window.outerWidth', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.windowOuterHeight, 'window.outerHeight', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollTop, 'scrollPos[0]', 'i32') }}} + {{{ makeSetValue('JSEvents.uiEvent', C_STRUCTS.EmscriptenUiEvent.scrollLeft, 'scrollPos[1]', 'i32') }}} + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.uiEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, // Neither scroll or resize events allow running requests inside them. + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + getNodeNameForTarget: function(target) { + if (!target) return ''; + if (target == window) return '#window'; + if (target == window.screen) return '#screen'; + return (target && target.nodeName) ? target.nodeName : ''; + }, + + registerFocusEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.focusEvent) { + JSEvents.focusEvent = _malloc( {{{ C_STRUCTS.EmscriptenFocusEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + + var nodeName = JSEvents.getNodeNameForTarget(e.target); + var id = e.target.id ? e.target.id : ''; + writeStringToMemory(nodeName, JSEvents.focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.nodeName }}} ); + writeStringToMemory(id, JSEvents.focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.id }}} ); + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.focusEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + tick: function() { + if (window['performance'] && window['performance']['now']) return window['performance']['now'](); + else return Date.now(); + }, + + registerDeviceOrientationEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.deviceOrientationEvent) { + JSEvents.deviceOrientationEvent = _malloc( {{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.timestamp, 'JSEvents.tick()', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.alpha, 'e.alpha', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.beta, 'e.beta', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.gamma, 'e.gamma', 'double') }}} + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceOrientationEvent.absolute, 'e.absolute', 'i32') }}} + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.deviceOrientationEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + registerDeviceMotionEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.deviceMotionEvent) { + JSEvents.deviceMotionEvent = _malloc( {{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}} ); + } + var handlerFunc = function(event) { + var e = event || window.event; + + {{{ makeSetValue('JSEvents.deviceOrientationEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.timestamp, 'JSEvents.tick()', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationX, 'e.acceleration.x', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationY, 'e.acceleration.y', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationZ, 'e.acceleration.z', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityX, 'e.accelerationIncludingGravity.x', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityY, 'e.accelerationIncludingGravity.y', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.accelerationIncludingGravityZ, 'e.accelerationIncludingGravity.z', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateAlpha, 'e.rotationRate.alpha', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateBeta, 'e.rotationRate.beta', 'double') }}} + {{{ makeSetValue('JSEvents.deviceMotionEvent', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateGamma, 'e.rotationRate.gamma', 'double') }}} + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.deviceMotionEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + screenOrientation: function() { + if (!window.screen) return undefined; + return window.screen.orientation || window.screen.mozOrientation || window.screen.webkitOrientation || window.screen.msOrientation; + }, + + fillOrientationChangeEventData: function(eventStruct, e) { + var orientations = ["portrait-primary", "portrait-secondary", "landscape-primary", "landscape-secondary"]; + var orientations2 = ["portrait", "portrait", "landscape", "landscape"]; + + var orientationString = JSEvents.screenOrientation(); + var orientation = orientations.indexOf(orientationString); + if (orientation == -1) { + orientation = orientations2.indexOf(orientationString); + } + + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationIndex, '1 << orientation', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationAngle, 'window.orientation', 'i32') }}} + }, + + registerOrientationChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.orientationChangeEvent) { + JSEvents.orientationChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenOrientationChangeEvent.__size__ }}} ); + } + + if (!target) { + target = window.screen; // Orientation events need to be captured from 'window.screen' instead of 'window' + } else { + target = JSEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JSEvents.fillOrientationChangeEventData(JSEvents.orientationChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.orientationChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + if (eventTypeString == "orientationchange" && window.screen.mozOrientation !== undefined) { + eventTypeString = "mozorientationchange"; + } + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + fullscreenEnabled: function() { + return document.fullscreenEnabled || document.mozFullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled; + }, + + fillFullscreenChangeEventData: function(eventStruct, e) { + var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement; + var isFullscreen = !!fullscreenElement; + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.isFullscreen, 'isFullscreen', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.fullscreenEnabled, 'JSEvents.fullscreenEnabled()', 'i32') }}} + var nodeName = JSEvents.getNodeNameForTarget(fullscreenElement); + var id = (fullscreenElement && fullscreenElement.id) ? fullscreenElement.id : ''; + writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.nodeName }}} ); + writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.id }}} ); + }, + + registerFullscreenChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.fullscreenChangeEvent) { + JSEvents.fullscreenChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.__size__ }}} ); + } + + if (!target) { + target = document; // Fullscreen change events need to be captured from 'document' by default instead of 'window' + } else { + target = JSEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JSEvents.fillFullscreenChangeEventData(JSEvents.fullscreenChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.fullscreenChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + requestFullscreen: function(target) { + if (target.requestFullscreen) { + target.requestFullscreen(); + } else if (target.msRequestFullscreen) { + target.msRequestFullscreen(); + } else if (target.mozRequestFullScreen) { + target.mozRequestFullScreen(); + } else if (target.mozRequestFullscreen) { + target.mozRequestFullscreen(); + } else if (target.webkitRequestFullscreen) { + target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } else { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + } + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + fillPointerlockChangeEventData: function(eventStruct, e) { + var pointerLockElement = document.pointerLockElement || document.mozPointerLockElement || document.webkitPointerLockElement || document.msPointerLockElement; + var isPointerlocked = !!pointerLockElement; + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenPointerlockChangeEvent.isActive, 'isPointerlocked', 'i32') }}} + var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement); + var id = (pointerLockElement && pointerLockElement.id) ? pointerLockElement.id : ''; + writeStringToMemory(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.nodeName }}} ); + writeStringToMemory(id, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.id }}}); + }, + + registerPointerlockChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.pointerlockChangeEvent) { + JSEvents.pointerlockChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.__size__ }}} ); + } + + if (!target) { + target = document; // Pointer lock change events need to be captured from 'document' by default instead of 'window' + } else { + target = JSEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JSEvents.fillPointerlockChangeEventData(JSEvents.pointerlockChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.pointerlockChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + requestPointerLock: function(target) { + if (target.requestPointerLock) { + target.requestPointerLock(); + } else if (target.mozRequestPointerLock) { + target.mozRequestPointerLock(); + } else if (target.webkitRequestPointerLock) { + target.webkitRequestPointerLock(); + } else if (target.msRequestPointerLock) { + target.msRequestPointerLock(); + } else { + // document.body is known to accept pointer lock, so use that to differentiate if the user passed a bad element, + // or if the whole browser just doesn't support the feature. + if (document.body.requestPointerLock || document.body.mozRequestPointerLock || document.body.webkitRequestPointerLock || document.body.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + fillVisibilityChangeEventData: function(eventStruct, e) { + var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ]; + var visibilityState = visibilityStates.indexOf(document.visibilityState); + + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.hidden, 'document.hidden', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}} + }, + + registerVisibilityChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.visibilityChangeEvent) { + JSEvents.visibilityChangeEvent = _malloc( {{{ C_STRUCTS.EmscriptenVisibilityChangeEvent.__size__ }}} ); + } + + if (!target) { + target = document; // Visibility change events need to be captured from 'document' by default instead of 'window' + } else { + target = JSEvents.findEventTarget(target); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JSEvents.fillVisibilityChangeEventData(JSEvents.visibilityChangeEvent, e); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.visibilityChangeEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: target, + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + registerTouchEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.touchEvent) { + JSEvents.touchEvent = _malloc( {{{ C_STRUCTS.EmscriptenTouchEvent.__size__ }}} ); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + var touches = {}; + for(var i = 0; i < e.touches.length; ++i) { + var touch = e.touches[i]; + touches[touch.identifier] = touch; + } + for(var i = 0; i < e.changedTouches.length; ++i) { + var touch = e.changedTouches[i]; + touches[touch.identifier] = touch; + touch.changed = true; + } + for(var i = 0; i < e.targetTouches.length; ++i) { + var touch = e.targetTouches[i]; + touches[touch.identifier].onTarget = true; + } + + var ptr = JSEvents.touchEvent; + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.ctrlKey, 'e.ctrlKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.shiftKey, 'e.shiftKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.altKey, 'e.altKey', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchEvent.metaKey, 'e.metaKey', 'i32') }}} + ptr += {{{ C_STRUCTS.EmscriptenTouchEvent.touches }}}; // Advance to the start of the touch array. + var rect = Module['canvas'].getBoundingClientRect(); + var numTouches = 0; + for(var i in touches) { + var t = touches[i]; + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.identifier, 't.identifier', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.screenX, 't.screenX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.screenY, 't.screenY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.clientX, 't.clientX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.clientY, 't.clientY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.pageX, 't.pageX', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.pageY, 't.pageY', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.isChanged, 't.changed', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.onTarget, 't.onTarget', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.canvasX, 't.clientX - rect.left', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.EmscriptenTouchPoint.canvasY, 't.clientY - rect.top', 'i32') }}} + ptr += {{{ C_STRUCTS.EmscriptenTouchPoint.__size__ }}}; + + if (++numTouches >= 32) { + break; + } + } + {{{ makeSetValue('JSEvents.touchEvent', C_STRUCTS.EmscriptenTouchEvent.numTouches, 'numTouches', 'i32') }}} + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.touchEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + fillGamepadEventData: function(eventStruct, e) { + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.timestamp, 'e.timestamp', 'double') }}} + for(var i = 0; i < e.axes.length; ++i) { + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.axis, 'e.axes[i]', 'double') }}} + } + for(var i = 0; i < e.buttons.length; ++i) { + {{{ makeSetValue('eventStruct+i*8', C_STRUCTS.EmscriptenGamepadEvent.analogButton, 'e.buttons[i].value', 'double') }}} + } + for(var i = 0; i < e.buttons.length; ++i) { + {{{ makeSetValue('eventStruct+i*4', C_STRUCTS.EmscriptenGamepadEvent.digitalButton, 'e.buttons[i].pressed', 'i32') }}} + } + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.connected, 'e.connected', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.index, 'e.index', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numAxes, 'e.axes.length', 'i32') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numButtons, 'e.buttons.length', 'i32') }}} + writeStringToMemory(e.id, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.id }}} ); + writeStringToMemory(e.mapping, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.mapping }}} ); + }, + + registerGamepadEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.gamepadEvent) { + JSEvents.gamepadEvent = _malloc( {{{ C_STRUCTS.EmscriptenGamepadEvent.__size__ }}} ); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JSEvents.fillGamepadEventData(JSEvents.gamepadEvent, e.gamepad); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.gamepadEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + registerBeforeUnloadEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + var handlerFunc = function(event) { + var e = event || window.event; + + var confirmationMessage = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, 0, userData]); + + confirmationMessage = Pointer_stringify(confirmationMessage); + if (confirmationMessage) { + e.preventDefault(); + e.returnValue = confirmationMessage; + return confirmationMessage; + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + battery: function() { return navigator.battery || navigator.mozBattery || navigator.webkitBattery; }, + + fillBatteryEventData: function(eventStruct, e) { + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.chargingTime, 'e.chargingTime', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.dischargingTime, 'e.dischargingTime', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.level, 'e.level', 'double') }}} + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenBatteryEvent.charging, 'e.charging', 'i32') }}} + }, + + registerBatteryEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!JSEvents.batteryEvent) { + JSEvents.batteryEvent = _malloc( {{{ C_STRUCTS.EmscriptenBatteryEvent.__size__ }}} ); + } + + var handlerFunc = function(event) { + var e = event || window.event; + + JSEvents.fillBatteryEventData(JSEvents.batteryEvent, JSEvents.battery()); + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, JSEvents.batteryEvent, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + + registerWebGlEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) { + if (!target) { + target = Module['canvas']; + } + var handlerFunc = function(event) { + var e = event || window.event; + + var shouldCancel = Runtime.dynCall('iiii', callbackfunc, [eventTypeId, 0, userData]); + if (shouldCancel) { + e.preventDefault(); + } + }; + + var eventHandler = { + target: JSEvents.findEventTarget(target), + allowsDeferredCalls: false, + eventTypeString: eventTypeString, + callbackfunc: callbackfunc, + handlerFunc: handlerFunc, + useCapture: useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }, + }, + + emscripten_set_keypress_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYPRESS') }}}, "keypress"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_keydown_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYDOWN') }}}, "keydown"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_keyup_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYUP') }}}, "keyup"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_click_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_CLICK') }}}, "click"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_mousedown_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEDOWN') }}}, "mousedown"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_mouseup_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEUP') }}}, "mouseup"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_dblclick_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DBLCLICK') }}}, "dblclick"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_mousemove_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEMOVE') }}}, "mousemove"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_mouse_status: function(mouseState) { + if (!JSEvents.mouseEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + // HTML5 does not really have a polling API for mouse events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler to any of the mouse function. + HEAP32.set(HEAP32.subarray(JSEvents.mouseEvent, {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}}), mouseState); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_wheel_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WHEEL') }}}, "wheel"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_resize_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_RESIZE') }}}, "resize"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_scroll_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_SCROLL') }}}, "scroll"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_blur_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BLUR') }}}, "blur"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_focus_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUS') }}}, "focus"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_focusin_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSIN') }}}, "focusin"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_focusout_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSOUT') }}}, "focusout"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_deviceorientation_callback: function(userData, useCapture, callbackfunc) { + JSEvents.registerDeviceOrientationEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEORIENTATION') }}}, "deviceorientation"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_deviceorientation_status: function(orientationState) { + if (!JSEvents.deviceOrientationEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + // HTML5 does not really have a polling API for device orientation events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler. + HEAP32.set(HEAP32.subarray(JSEvents.deviceOrientationEvent, {{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}}), orientationState); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_devicemotion_callback: function(userData, useCapture, callbackfunc) { + JSEvents.registerDeviceMotionEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEMOTION') }}}, "devicemotion"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_devicemotion_status: function(motionState) { + if (!JSEvents.deviceMotionEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + // HTML5 does not really have a polling API for device motion events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler. + HEAP32.set(HEAP32.subarray(JSEvents.deviceMotionEvent, {{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}}), motionState); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_orientationchange_callback: function(userData, useCapture, callbackfunc) { + if (!window.screen || !window.screen.addEventListener) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerOrientationChangeEventCallback(window.screen, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_ORIENTATIONCHANGE') }}}, "orientationchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_orientation_status: function(orientationChangeEvent) { + if (!JSEvents.screenOrientation() && typeof window.orientation === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.fillOrientationChangeEventData(orientationChangeEvent); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_lock_orientation: function(allowedOrientations) { + var orientations = []; + if (allowedOrientations & 1) orientations.push("portrait-primary"); + if (allowedOrientations & 2) orientations.push("portrait-secondary"); + if (allowedOrientations & 4) orientations.push("landscape-primary"); + if (allowedOrientations & 8) orientations.push("landscape-secondary"); + if (window.screen.lockOrientation) { + window.screen.lockOrientation(orientations); + } else if (window.screen.mozLockOrientation) { + window.screen.mozLockOrientation(orientations); + } else if (window.screen.webkitLockOrientation) { + window.screen.webkitLockOrientation(orientations); + } else if (window.screen.msLockOrientation) { + window.screen.msLockOrientation(orientations); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_unlock_orientation: function() { + if (window.screen.unlockOrientation) { + window.screen.unlockOrientation(); + } else if (window.screen.mozUnlockOrientation) { + window.screen.mozUnlockOrientation(); + } else if (window.screen.webkitUnlockOrientation) { + window.screen.webkitUnlockOrientation(); + } else if (window.screen.msUnlockOrientation) { + window.screen.msUnlockOrientation(); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_fullscreenchange_callback: function(target, userData, useCapture, callbackfunc) { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!target) target = document; + else { + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + } + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "fullscreenchange"); + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "mozfullscreenchange"); + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "webkitfullscreenchange"); + JSEvents.registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "msfullscreenchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_fullscreen_status: function(fullscreenStatus) { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.fillFullscreenChangeEventData(fullscreenStatus); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + // https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode + emscripten_request_fullscreen: function(target, deferUntilInEventHandler) { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + if (!target) target = '#canvas'; + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + + if (!target.requestFullscreen && !target.msRequestFullscreen && !target.mozRequestFullScreen && !target.mozRequestFullscreen && !target.webkitRequestFullscreen) { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + } + + var canPerformRequests = JSEvents.canPerformEventHandlerRequests(); + + // Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so. + if (!canPerformRequests) { + if (deferUntilInEventHandler) { + JSEvents.deferCall(JSEvents.requestFullscreen, 1 /* priority over pointer lock */, [target]); + return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; + } + } + + return JSEvents.requestFullscreen(target); + }, + + emscripten_exit_fullscreen: function() { + if (typeof JSEvents.fullscreenEnabled() === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + // Make sure no queued up calls will fire after this. + JSEvents.removeDeferredCalls(JSEvents.requestFullscreen); + + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_pointerlockchange_callback: function(target, userData, useCapture, callbackfunc) { + if (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + if (!target) target = document; + else { + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + } + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "pointerlockchange"); + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "mozpointerlockchange"); + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "webkitpointerlockchange"); + JSEvents.registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "mspointerlockchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_pointerlock_status: function(pointerlockStatus) { + if (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + JSEvents.fillPointerlockChangeEventData(pointerlockStatus); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_request_pointerlock: function(target, deferUntilInEventHandler) { + if (!target) target = '#canvas'; + target = JSEvents.findEventTarget(target); + if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!target.requestPointerLock && !target.mozRequestPointerLock && !target.webkitRequestPointerLock && !target.msRequestPointerLock) { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + + var canPerformRequests = JSEvents.canPerformEventHandlerRequests(); + + // Queue this function call if we're not currently in an event handler and the user saw it appropriate to do so. + if (!canPerformRequests) { + if (deferUntilInEventHandler) { + JSEvents.deferCall(JSEvents.requestPointerLock, 2 /* priority below fullscreen */, [target]); + return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; + } + } + + return JSEvents.requestPointerLock(target); + }, + + emscripten_exit_pointerlock: function() { + // Make sure no queued up calls will fire after this. + JSEvents.removeDeferredCalls(JSEvents.requestPointerLock); + + if (document.exitPointerLock) { + document.exitPointerLock(); + } else if (document.msExitPointerLock) { + document.msExitPointerLock(); + } else if (document.mozExitPointerLock) { + document.mozExitPointerLock(); + } else if (document.webkitExitPointerLock) { + document.webkitExitPointerLock(); + } else { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_vibrate: function(msecs) { + if (!navigator.vibrate) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + navigator.vibrate(msecs); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_vibrate_pattern: function(msecsArray, numEntries) { + if (!navigator.vibrate) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + + var vibrateList = []; + for(var i = 0; i < numEntries; ++i) { + var msecs = {{{ makeGetValue('msecsArray', 'i*4', 'i32') }}} + vibrateList.push(msecs); + } + navigator.vibrate(vibrateList); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_visibilitychange_callback: function(userData, useCapture, callbackfunc) { + JSEvents.registerVisibilityChangeEventCallback(document, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_VISIBILITYCHANGE') }}}, "visibilitychange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_visibility_status: function(visibilityStatus) { + if (typeof document.visibilityState === 'undefined' && typeof document.hidden === 'undefined') { + return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + } + JSEvents.fillVisibilityChangeEventData(visibilityStatus); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchstart_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHSTART') }}}, "touchstart"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchend_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHEND') }}}, "touchend"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchmove_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHMOVE') }}}, "touchmove"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_touchcancel_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHCANCEL') }}}, "touchcancel"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_gamepadconnected_callback: function(userData, useCapture, callbackfunc) { + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADCONNECTED') }}}, "gamepadconnected"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_gamepaddisconnected_callback: function(userData, useCapture, callbackfunc) { + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerGamepadEventCallback(window, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED') }}}, "gamepaddisconnected"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_num_gamepads: function() { + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return navigator.getGamepads().length; + }, + + emscripten_get_gamepad_status: function(index, gamepadState) { + if (!navigator.getGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + var gamepads = navigator.getGamepads(); + if (index < 0 || index >= gamepads.length) { + return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + } + JSEvents.fillGamepadEventData(gamepadState, gamepads[index]); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_beforeunload_callback: function(userData, callbackfunc) { + if (typeof window.onbeforeunload === 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerBeforeUnloadEventCallback(window, userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BEFOREUNLOAD') }}}, "beforeunload"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_batterychargingchange_callback: function(userData, callbackfunc) { + if (!JSEvents.battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerBatteryEventCallback(JSEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE') }}}, "chargingchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_batterylevelchange_callback: function(userData, callbackfunc) { + if (!JSEvents.battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.registerBatteryEventCallback(JSEvents.battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE') }}}, "levelchange"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_get_battery_status: function(batteryState) { + if (!JSEvents.battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + JSEvents.fillBatteryEventData(batteryState, JSEvents.battery()); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_webglcontextlost_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, + + emscripten_set_webglcontextrestored_callback: function(target, userData, useCapture, callbackfunc) { + JSEvents.registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored"); + return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + }, +}; + +autoAddDeps(LibraryJSEvents, '$JSEvents'); +mergeInto(LibraryManager.library, LibraryJSEvents); diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/library_openal.js emscripten-1.10.0~20140205~ef1e460/src/library_openal.js --- emscripten-1.9.0~20140119~7dc8c2f/src/library_openal.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/library_openal.js 2014-02-05 17:48:09.000000000 +0000 @@ -201,12 +201,15 @@ } if (ctx) { + var gain = ctx.createGain(); + gain.connect(ctx.destination); var context = { ctx: ctx, err: 0, src: [], buf: [], - interval: setInterval(function() { AL.updateSources(context); }, AL.QUEUE_INTERVAL) + interval: setInterval(function() { AL.updateSources(context); }, AL.QUEUE_INTERVAL), + gain: gain }; AL.contexts.push(context); return AL.contexts.length; @@ -254,7 +257,7 @@ } for (var i = 0; i < count; ++i) { var gain = AL.currentContext.ctx.createGain(); - gain.connect(AL.currentContext.ctx.destination); + gain.connect(AL.currentContext.gain); AL.currentContext.src.push({ state: 0x1011 /* AL_INITIAL */, queue: [], @@ -294,6 +297,34 @@ this._velocity = val; if (this.panner) this.panner.setVelocity(val[0], val[1], val[2]); }, + get direction() { + return this._direction || [0, 0, 0]; + }, + set direction(val) { + this._direction = val; + if (this.panner) this.panner.setOrientation(val[0], val[1], val[2]); + }, + get coneOuterGain() { + return this._coneOuterGain || 0.0; + }, + set coneOuterGain(val) { + this._coneOuterGain = val; + if (this.panner) this.panner.coneOuterGain = val; + }, + get coneInnerAngle() { + return this._coneInnerAngle || 360.0; + }, + set coneInnerAngle(val) { + this._coneInnerAngle = val; + if (this.panner) this.panner.coneInnerAngle = val; + }, + get coneOuterAngle() { + return this._coneOuterAngle || 360.0; + }, + set coneOuterAngle(val) { + this._coneOuterAngle = val; + if (this.panner) this.panner.coneOuterAngle = val; + }, gain: gain, panner: null, buffersPlayed: 0, @@ -320,6 +351,12 @@ return; } switch (param) { + case 0x1001 /* AL_CONE_INNER_ANGLE */: + src.coneInnerAngle = value; + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + src.coneOuterAngle = value; + break; case 0x1007 /* AL_LOOPING */: src.loop = (value === 1 /* AL_TRUE */); break; @@ -406,12 +443,15 @@ case 0x1021 /* AL_ROLLOFF_FACTOR */: src.rolloffFactor = value; break; - // case 0x1022 /* AL_CONE_OUTER_GAIN */: - // break; - // case 0x1001 /* AL_CONE_INNER_ANGLE */: - // break; - // case 0x1002 /* AL_CONE_OUTER_ANGLE */: - // break; + case 0x1022 /* AL_CONE_OUTER_GAIN */: + src.coneOuterGain = value; + break; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + src.coneInnerAngle = value; + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + src.coneOuterAngle = value; + break; case 0x1020 /* AL_REFERENCE_DISTANCE */: src.refDistance = value; break; @@ -443,6 +483,9 @@ case 0x1004 /* AL_POSITION */: src.position = [v1, v2, v3]; break; + case 0x1005 /* AL_DIRECTION */: + src.direction = [v1, v2, v3]; + break; case 0x1006 /* AL_VELOCITY */: src.velocity = [v1, v2, v3]; break; @@ -594,6 +637,21 @@ } }, + alIsBuffer: function(bufferId) { + if (!AL.currentContext) { + return false; + } + if (bufferId > AL.currentContext.buf.length) { + return false; + } + + if (!AL.currentContext.buf[bufferId - 1]) { + return false; + } else { + return true; + } + }, + alBufferData: function(buffer, format, data, size, freq) { if (!AL.currentContext) { #if OPENAL_DEBUG @@ -743,6 +801,12 @@ case 0x202 /* AL_SOURCE_RELATIVE */: {{{ makeSetValue('value', '0', 'src.panner ? 1 : 0', 'i32') }}}; break; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneInnerAngle', 'i32') }}}; + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneOuterAngle', 'i32') }}}; + break; case 0x1009 /* AL_BUFFER */: if (!src.queue.length) { {{{ makeSetValue('value', '0', '0', 'i32') }}}; @@ -809,12 +873,15 @@ case 0x1021 /* AL_ROLLOFF_FACTOR */: {{{ makeSetValue('value', '0', 'src.rolloffFactor', 'float') }}} break; - // case 0x1022 /* AL_CONE_OUTER_GAIN */: - // break; - // case 0x1001 /* AL_CONE_INNER_ANGLE */: - // break; - // case 0x1002 /* AL_CONE_OUTER_ANGLE */: - // break; + case 0x1022 /* AL_CONE_OUTER_GAIN */: + {{{ makeSetValue('value', '0', 'src.coneOuterGain', 'float') }}} + break; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneInnerAngle', 'float') }}} + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + {{{ makeSetValue('value', '0', 'src.coneOuterAngle', 'float') }}} + break; case 0x1020 /* AL_REFERENCE_DISTANCE */: {{{ makeSetValue('value', '0', 'src.refDistance', 'float') }}} break; @@ -830,6 +897,49 @@ } }, + alGetSourcefv: function(source, param, values) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetSourcefv called without a valid context"); +#endif + return; + } + var src = AL.currentContext.src[source - 1]; + if (!src) { +#if OPENAL_DEBUG + console.error("alGetSourcefv called with an invalid source"); +#endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; + return; + } + switch (param) { + case 0x1004 /* AL_POSITION */: + var position = src.position; + {{{ makeSetValue('values', '0', 'position[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'position[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'position[2]', 'float') }}} + break; + case 0x1005 /* AL_DIRECTION */: + var direction = src.direction; + {{{ makeSetValue('values', '0', 'direction[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'direction[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'direction[2]', 'float') }}} + break; + case 0x1006 /* AL_VELOCITY */: + var velocity = src.velocity; + {{{ makeSetValue('values', '0', 'velocity[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'velocity[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'velocity[2]', 'float') }}} + break; + default: +#if OPENAL_DEBUG + console.error("alGetSourcefv with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + alDistanceModel: function(model) { if (model !== 0 /* AL_NONE */) { #if OPENAL_DEBUG @@ -838,6 +948,136 @@ } }, + alGetListenerf: function(pname, values) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetListenerf called without a valid context"); +#endif + return; + } + switch (pname) { + case 0x100A /* AL_GAIN */: + {{{ makeSetValue('value', '0', 'AL.currentContext.gain.gain', 'float') }}} + break; + default: +#if OPENAL_DEBUG + console.error("alGetListenerf with param " + pname + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + + }, + + alGetListenerfv: function(pname, values) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetListenerfv called without a valid context"); +#endif + return; + } + switch (pname) { + case 0x1004 /* AL_POSITION */: + var position = AL.currentContext.ctx.listener._position || [0,0,0]; + {{{ makeSetValue('values', '0', 'position[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'position[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'position[2]', 'float') }}} + break; + case 0x1006 /* AL_VELOCITY */: + var velocity = AL.currentContext.ctx.listener._velocity || [0,0,0]; + {{{ makeSetValue('values', '0', 'velocity[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'velocity[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'velocity[2]', 'float') }}} + break; + case 0x100F /* AL_ORIENTATION */: + var orientation = AL.currentContext.ctx.listener._orientation || [0,0,0,0,0,0]; + {{{ makeSetValue('values', '0', 'orientation[0]', 'float') }}} + {{{ makeSetValue('values', '4', 'orientation[1]', 'float') }}} + {{{ makeSetValue('values', '8', 'orientation[2]', 'float') }}} + {{{ makeSetValue('values', '12', 'orientation[3]', 'float') }}} + {{{ makeSetValue('values', '16', 'orientation[4]', 'float') }}} + {{{ makeSetValue('values', '20', 'orientation[5]', 'float') }}} + break; + default: +#if OPENAL_DEBUG + console.error("alGetListenerfv with param " + pname + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alGetListeneri: function(pname, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetListeneri called without a valid context"); +#endif + return; + } + switch (pname) { + default: +#if OPENAL_DEBUG + console.error("alGetListeneri with param " + pname + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alListenerf: function(param, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alListenerf called without a valid context"); +#endif + return; + } + switch (param) { + case 0x100A /* AL_GAIN */: + AL.currentContext.gain.value = value; + break; + default: +#if OPENAL_DEBUG + console.error("alListenerf with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alEnable: function(param) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alEnable called without a valid context"); +#endif + return; + } + switch (param) { + default: +#if OPENAL_DEBUG + console.error("alEnable with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + + alDisable: function(param) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alDisable called without a valid context"); +#endif + return; + } + switch (pname) { + default: +#if OPENAL_DEBUG + console.error("alDisable with param " + param + " not implemented yet"); +#endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; + break; + } + }, + alListenerfv: function(param, values) { if (!AL.currentContext) { #if OPENAL_DEBUG @@ -847,32 +1087,32 @@ } switch (param) { case 0x1004 /* AL_POSITION */: - AL.currentContext.ctx.listener.setPosition( - {{{ makeGetValue('values', '0', 'float') }}}, - {{{ makeGetValue('values', '4', 'float') }}}, - {{{ makeGetValue('values', '8', 'float') }}} - ); + var x = {{{ makeGetValue('values', '0', 'float') }}}; + var y = {{{ makeGetValue('values', '4', 'float') }}}; + var z = {{{ makeGetValue('values', '8', 'float') }}}; + AL.currentContext.ctx.listener._position = [x, y, z]; + AL.currentContext.ctx.listener.setPosition(x, y, z); break; case 0x1006 /* AL_VELOCITY */: - AL.currentContext.ctx.listener.setVelocity( - {{{ makeGetValue('values', '0', 'float') }}}, - {{{ makeGetValue('values', '4', 'float') }}}, - {{{ makeGetValue('values', '8', 'float') }}} - ); + var x = {{{ makeGetValue('values', '0', 'float') }}}; + var y = {{{ makeGetValue('values', '4', 'float') }}}; + var z = {{{ makeGetValue('values', '8', 'float') }}}; + AL.currentContext.ctx.listener._velocity = [x, y, z]; + AL.currentContext.ctx.listener.setVelocity(x, y, z); break; case 0x100F /* AL_ORIENTATION */: - AL.currentContext.ctx.listener.setOrientation( - {{{ makeGetValue('values', '0', 'float') }}}, - {{{ makeGetValue('values', '4', 'float') }}}, - {{{ makeGetValue('values', '8', 'float') }}}, - {{{ makeGetValue('values', '12', 'float') }}}, - {{{ makeGetValue('values', '16', 'float') }}}, - {{{ makeGetValue('values', '20', 'float') }}} - ); + var x = {{{ makeGetValue('values', '0', 'float') }}}; + var y = {{{ makeGetValue('values', '4', 'float') }}}; + var z = {{{ makeGetValue('values', '8', 'float') }}}; + var x2 = {{{ makeGetValue('values', '12', 'float') }}}; + var y2 = {{{ makeGetValue('values', '16', 'float') }}}; + var z2 = {{{ makeGetValue('values', '20', 'float') }}}; + AL.currentContext.ctx.listener._orientation = [x, y, z, x2, y2, z2]; + AL.currentContext.ctx.listener.setOrientation(x, y, z, x2, y2, z2); break; default: #if OPENAL_DEBUG - console.log("alListenerfv with param " + param + " not implemented yet"); + console.error("alListenerfv with param " + param + " not implemented yet"); #endif AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/library_sdl.js emscripten-1.10.0~20140205~ef1e460/src/library_sdl.js --- emscripten-1.9.0~20140119~7dc8c2f/src/library_sdl.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/library_sdl.js 2014-02-05 17:48:09.000000000 +0000 @@ -223,26 +223,26 @@ var is_SDL_HWPALETTE = flags & 0x00200000; var bpp = is_SDL_HWPALETTE ? 1 : 4; - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.flags, 'flags', 'i32') }}} // SDL_Surface.flags - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.format, 'pixelFormat', 'void*') }}} // SDL_Surface.format TODO - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.w, 'width', 'i32') }}} // SDL_Surface.w - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.h, 'height', 'i32') }}} // SDL_Surface.h - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}} // SDL_Surface.pitch, assuming RGBA or indexed for now, + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.flags, 'flags', 'i32') }}}; // SDL_Surface.flags + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.format, 'pixelFormat', 'void*') }}};// SDL_Surface.format TODO + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.w, 'width', 'i32') }}}; // SDL_Surface.w + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.h, 'height', 'i32') }}}; // SDL_Surface.h + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}}; // SDL_Surface.pitch, assuming RGBA or indexed for now, // since that is what ImageData gives us in browsers - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}} // SDL_Surface.pixels - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}} // SDL_Surface.offset + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}}; // SDL_Surface.pixels + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}}; // SDL_Surface.offset - {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}} + {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}}; - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}} // SDL_PIXELFORMAT_RGBA8888 - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}} // TODO - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}} - - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}} - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}} + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}};// SDL_PIXELFORMAT_RGBA8888 + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}};// TODO + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}}; + + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}}; // Decide if we want to use WebGL or not var useWebGL = (flags & 0x04000000) != 0; // SDL_OPENGL @@ -592,19 +592,19 @@ scan = SDL.scanCodes[key] || key; } - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}} // TODO - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}} - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}} + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}}; // TODO + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}}; // some non-character keys (e.g. backspace and tab) won't have keypressCharCode set, fill in with the keyCode. - {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}}; break; } case 'keypress': { - {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}} + {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}; // Not filling in windowID for now var cStr = intArrayFromString(String.fromCharCode(event.charCode)); for (var i = 0; i < cStr.length; ++i) { @@ -819,9 +819,9 @@ SDL_Linked_Version: function() { if (SDL.version === null) { SDL.version = _malloc({{{ C_STRUCTS.SDL_version.__size__ }}}); - {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}} - {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}} - {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}} + {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}}; + {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}}; + {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}}; } return SDL.version; }, @@ -879,11 +879,11 @@ SDL_GetVideoInfo: function() { // %struct.SDL_VideoInfo = type { i32, i32, %struct.SDL_PixelFormat*, i32, i32 } - 5 fields of quantum size var ret = _malloc(5*Runtime.QUANTUM_SIZE); - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*0', '0', '0', 'i32') }}} // TODO - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*1', '0', '0', 'i32') }}} // TODO - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}} - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}} - {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}} + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*0', '0', '0', 'i32') }}}; // TODO + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*1', '0', '0', 'i32') }}}; // TODO + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}}; + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}}; + {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}}; return ret; }, diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/modules.js emscripten-1.10.0~20140205~ef1e460/src/modules.js --- emscripten-1.9.0~20140119~7dc8c2f/src/modules.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/modules.js 2014-02-05 17:48:09.000000000 +0000 @@ -424,9 +424,22 @@ load: function() { if (this.library) return; - var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js'].concat(additionalLibraries); + var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js', 'library_html5.js'].concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { - eval(processMacros(preprocess(read(libraries[i])))); + var filename = libraries[i]; + var src = read(filename); + try { + var processed = processMacros(preprocess(src)); + eval(processed); + } catch(e) { + var details = [e, e.lineNumber ? 'line number: ' + e.lineNumber : '', (e.stack || "").toString().replace('Object.', filename)]; + if (processed) { + error('failure to execute js library "' + filename + '": ' + details + '\npreprocessed source (you can run a js engine on this to get a clearer error message sometimes):\n=============\n' + processed + '\n=============\n'); + } else { + error('failure to process js library "' + filename + '": ' + details + '\noriginal source:\n=============\n' + src + '\n=============\n'); + } + throw e; + } } /* diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/parseTools.js emscripten-1.10.0~20140205~ef1e460/src/parseTools.js --- emscripten-1.9.0~20140119~7dc8c2f/src/parseTools.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/parseTools.js 2014-02-05 17:48:09.000000000 +0000 @@ -46,7 +46,11 @@ error('unsupported preprecessor op ' + op); } } else { - showStack.push(ident in this && this[ident] > 0); + if (ident[0] === '!') { + showStack.push(!(this[ident.substr(1)] > 0)); + } else { + showStack.push(ident in this && this[ident] > 0); + } } } else if (line[2] == 'n') { // include var included = read(line.substr(line.indexOf(' ')+1)); @@ -1327,18 +1331,22 @@ var printType = type; if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); - return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type); - } else { - var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; - if (ASM_JS && (phase == 'funcs' || forceAsm)) { - ret = asmCoercion(ret, type); - } - if (ASM_HEAP_LOG) { - ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret, - 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int')); + if (ASM_JS) { + if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type); + // else fall through + } else { + return asmCoercion('SAFE_HEAP_LOAD(' + offset + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type); } - return ret; } + var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; + if (ASM_JS && (phase == 'funcs' || forceAsm)) { + ret = asmCoercion(ret, type); + } + if (ASM_HEAP_LOG) { + ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret, + 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int')); + } + return ret; } function makeGetValueAsm(ptr, pos, type, unsigned) { @@ -1435,10 +1443,14 @@ var printType = type; if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); - return 'SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; - } else { - return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep); + if (ASM_JS) { + if (!ignore && phase !== 'funcs') return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ')', type); + // else fall through + } else { + return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; + } } + return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep); } function makeSetValueAsm(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) { @@ -1781,31 +1793,12 @@ types = 'i8'; } - // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime - var chunkSize = JS_CHUNK_SIZE; - function chunkify(array) { - // break very large slabs into parts - var ret = ''; - var index = 0; - while (index < array.length) { - ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')\n' : ''); - index += chunkSize; - } - return ret; - } - if (typeof slab == 'object' && slab.length > chunkSize) { - slab = chunkify(slab); - } if (typeof types == 'object') { while (types.length < slab.length) types.push(0); } - if (typeof types != 'string' && types.length > chunkSize) { - types = chunkify(types); - } else { - types = JSON.stringify(types); - } + types = JSON.stringify(types); if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; - return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')'; + return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ');'; } function makeGetSlabs(ptr, type, allowMultiple, unsigned) { diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/preamble.js emscripten-1.10.0~20140205~ef1e460/src/preamble.js --- emscripten-1.9.0~20140119~7dc8c2f/src/preamble.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/preamble.js 2014-02-05 17:48:09.000000000 +0000 @@ -6,6 +6,8 @@ {{RUNTIME}} +Module['Runtime'] = Runtime; + #if ASM_JS #if RESERVED_FUNCTION_POINTERS function jsCall() { @@ -21,6 +23,7 @@ #endif #if SAFE_HEAP +#if ASM_JS == 0 //======================================== // Debugging tools - Heap //======================================== @@ -166,6 +169,41 @@ } //========================================== +#else +// ASM_JS safe heap + +function getSafeHeapType(bytes, isFloat) { + switch (bytes) { + case 1: return 'i8'; + case 2: return 'i16'; + case 4: return isFloat ? 'float' : 'i32'; + case 8: return 'double'; + default: assert(0); + } +} + +function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { +#if SAFE_HEAP_LOG + Module.print('SAFE_HEAP store: ' + [dest, value, bytes, isFloat]); +#endif + assert(dest > 0, 'segmentation fault'); + assert(dest % bytes === 0); + setValue(dest, value, getSafeHeapType(bytes, isFloat), 1); +} + +function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) { +#if SAFE_HEAP_LOG + Module.print('SAFE_HEAP load: ' + [dest, bytes, isFloat, unsigned]); +#endif + assert(dest > 0, 'segmentation fault'); + assert(dest % bytes === 0); + var type = getSafeHeapType(bytes, isFloat); + var ret = getValue(dest, type, 1); + if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1); + return ret; +} + +#endif #endif #if CHECK_HEAP_ALIGN diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/relooper/Relooper.cpp emscripten-1.10.0~20140205~ef1e460/src/relooper/Relooper.cpp --- emscripten-1.9.0~20140119~7dc8c2f/src/relooper/Relooper.cpp 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/relooper/Relooper.cpp 2014-02-05 17:48:09.000000000 +0000 @@ -1,3 +1,7 @@ +// We are implementing the Relooper C API, so always export from this file. +#ifndef RELOOPERDLL_EXPORTS +#define RELOOPERDLL_EXPORTS +#endif #include "Relooper.h" @@ -322,12 +326,26 @@ void MultipleShape::Render(bool InLoop) { RenderLoopPrefix(); - bool First = true; + + // We know that blocks with the same Id were split from the same source, so their contents are identical and they are logically the same, so re-merge them here + typedef std::map IdShapeMap; + IdShapeMap IdMap; for (BlockShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { + int Id = iter->first->Id; + IdShapeMap::iterator Test = IdMap.find(Id); + if (Test != IdMap.end()) { + assert(Shape::IsSimple(iter->second) && Shape::IsSimple(Test->second)); // we can only merge simple blocks, something horrible has gone wrong if we see anything else + continue; + } + IdMap[iter->first->Id] = iter->second; + } + + bool First = true; + for (IdShapeMap::iterator iter = IdMap.begin(); iter != IdMap.end(); iter++) { if (AsmJS) { - PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first->Id); + PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first); } else { - PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first->Id); + PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first); } First = false; Indenter::Indent(); @@ -391,8 +409,8 @@ for (unsigned i = 0; i < Shapes.size(); i++) delete Shapes[i]; } -void Relooper::AddBlock(Block *New) { - New->Id = BlockIdCounter++; +void Relooper::AddBlock(Block *New, int Id) { + New->Id = Id == -1 ? BlockIdCounter++ : Id; Blocks.push_back(New); } @@ -446,8 +464,7 @@ for (BlockSet::iterator iter = Original->BranchesIn.begin(); iter != Original->BranchesIn.end(); iter++) { Block *Prior = *iter; Block *Split = new Block(Original->Code, Original->BranchVar); - Parent->AddBlock(Split); - PrintDebug(" to %d\n", Split->Id); + Parent->AddBlock(Split, Original->Id); Split->BranchesIn.insert(Prior); Branch *Details = Prior->BranchesOut[Original]; Prior->BranchesOut[Split] = new Branch(Details->Condition, Details->Code); @@ -1256,7 +1273,7 @@ extern "C" { -void rl_set_output_buffer(char *buffer, int size) { +RELOOPERDLL_API void rl_set_output_buffer(char *buffer, int size) { #if DEBUG printf("#include \"Relooper.h\"\n"); printf("int main() {\n"); @@ -1266,15 +1283,15 @@ Relooper::SetOutputBuffer(buffer, size); } -void rl_make_output_buffer(int size) { +RELOOPERDLL_API void rl_make_output_buffer(int size) { Relooper::SetOutputBuffer((char*)malloc(size), size); } -void rl_set_asm_js_mode(int on) { +RELOOPERDLL_API void rl_set_asm_js_mode(int on) { Relooper::SetAsmJSMode(on); } -void *rl_new_block(const char *text, const char *branch_var) { +RELOOPERDLL_API void *rl_new_block(const char *text, const char *branch_var) { Block *ret = new Block(text, branch_var); #if DEBUG printf(" void *b%d = rl_new_block(\"// code %d\");\n", ret->Id, ret->Id); @@ -1284,21 +1301,21 @@ return ret; } -void rl_delete_block(void *block) { +RELOOPERDLL_API void rl_delete_block(void *block) { #if DEBUG printf(" rl_delete_block(block_map[%d]);\n", ((Block*)block)->Id); #endif delete (Block*)block; } -void rl_block_add_branch_to(void *from, void *to, const char *condition, const char *code) { +RELOOPERDLL_API void rl_block_add_branch_to(void *from, void *to, const char *condition, const char *code) { #if DEBUG printf(" rl_block_add_branch_to(block_map[%d], block_map[%d], %s%s%s, %s%s%s);\n", ((Block*)from)->Id, ((Block*)to)->Id, condition ? "\"" : "", condition ? condition : "NULL", condition ? "\"" : "", code ? "\"" : "", code ? code : "NULL", code ? "\"" : ""); #endif ((Block*)from)->AddBranchTo((Block*)to, condition, code); } -void *rl_new_relooper() { +RELOOPERDLL_API void *rl_new_relooper() { #if DEBUG printf(" void *block_map[10000];\n"); printf(" void *rl = rl_new_relooper();\n"); @@ -1306,18 +1323,18 @@ return new Relooper; } -void rl_delete_relooper(void *relooper) { +RELOOPERDLL_API void rl_delete_relooper(void *relooper) { delete (Relooper*)relooper; } -void rl_relooper_add_block(void *relooper, void *block) { +RELOOPERDLL_API void rl_relooper_add_block(void *relooper, void *block) { #if DEBUG printf(" rl_relooper_add_block(rl, block_map[%d]);\n", ((Block*)block)->Id); #endif ((Relooper*)relooper)->AddBlock((Block*)block); } -void rl_relooper_calculate(void *relooper, void *entry) { +RELOOPERDLL_API void rl_relooper_calculate(void *relooper, void *entry) { #if DEBUG printf(" rl_relooper_calculate(rl, block_map[%d]);\n", ((Block*)entry)->Id); printf(" rl_relooper_render(rl);\n"); @@ -1329,7 +1346,7 @@ ((Relooper*)relooper)->Calculate((Block*)entry); } -void rl_relooper_render(void *relooper) { +RELOOPERDLL_API void rl_relooper_render(void *relooper) { ((Relooper*)relooper)->Render(); } diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/relooper/Relooper.h emscripten-1.10.0~20140205~ef1e460/src/relooper/Relooper.h --- emscripten-1.9.0~20140119~7dc8c2f/src/relooper/Relooper.h 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/relooper/Relooper.h 2014-02-05 17:48:09.000000000 +0000 @@ -57,7 +57,7 @@ BlockBranchMap ProcessedBranchesOut; BlockSet ProcessedBranchesIn; Shape *Parent; // The shape we are directly inside - int Id; // A unique identifier, defined when added to relooper + int Id; // A unique identifier, defined when added to relooper. Note that this uniquely identifies a *logical* block - if we split it, the two instances have the same content *and* the same Id const char *Code; // The string representation of the code in this block. Owning pointer (we copy the input) const char *BranchVar; // If we have more than one branch out, the variable whose value determines where we go bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable @@ -191,7 +191,7 @@ Relooper(); ~Relooper(); - void AddBlock(Block *New); + void AddBlock(Block *New, int Id=-1); // Calculates the shapes void Calculate(Block *Entry); diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/relooper/test.txt emscripten-1.10.0~20140205~ef1e460/src/relooper/test.txt --- emscripten-1.9.0~20140119~7dc8c2f/src/relooper/test.txt 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/relooper/test.txt 2014-02-05 17:48:09.000000000 +0000 @@ -91,7 +91,7 @@ } default: { var $x_1 = $x_0; - label = 8; + label = 7; break L1; } } @@ -106,7 +106,7 @@ } } } - if (label == 8) { + if (label == 7) { // code 7 } // code 4 diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/runtime.js emscripten-1.10.0~20140205~ef1e460/src/runtime.js --- emscripten-1.9.0~20140119~7dc8c2f/src/runtime.js 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/runtime.js 2014-02-05 17:48:09.000000000 +0000 @@ -49,7 +49,7 @@ stackExit: function(initial, force) { if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return ''; var ret = ''; - if (SAFE_HEAP) { + if (SAFE_HEAP && !ASM_JS) { ret += 'var i = sp; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }'; } return ret += 'STACKTOP=sp'; @@ -393,7 +393,17 @@ for (var i = 0; i < numArgs; i++) { args.push(String.fromCharCode(36) + i); // $0, $1 etc } - return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + Pointer_stringify(code) + ' })'); // new Function does not allow upvars in node + code = Pointer_stringify(code); + if (code[0] === '"') { + // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct + if (code.indexOf('"', 1) === code.length-1) { + code = code.substr(1, code.length-2); + } else { + // something invalid happened, e.g. EM_ASM("..code($0)..", input) + abort('invalid EM_ASM input |' + code + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)'); + } + } + return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + code + ' })'); // new Function does not allow upvars in node }, warnOnce: function(text) { diff -Nru emscripten-1.9.0~20140119~7dc8c2f/src/shell.html emscripten-1.10.0~20140205~ef1e460/src/shell.html --- emscripten-1.9.0~20140119~7dc8c2f/src/shell.html 2014-01-19 14:02:09.000000000 +0000 +++ emscripten-1.10.0~20140205~ef1e460/src/shell.html 2014-02-05 17:48:09.000000000 +0000 @@ -11,10 +11,44 @@ div.emscripten_border { border: 1px solid black; } /* the canvas *must not* have any border or padding, or mouse coords will be wrong */ canvas.emscripten { border: 0px none; } + + .spinner { + height: 50px; + width: 50px; + margin: 0px auto; + -webkit-animation: rotation .8s linear infinite; + -moz-animation: rotation .8s linear infinite; + -o-animation: rotation .8s linear infinite; + animation: rotation 0.8s linear infinite; + border-left: 10px solid rgb(0,150,240); + border-right: 10px solid rgb(0,150,240); + border-bottom: 10px solid rgb(0,150,240); + border-top: 10px solid rgb(100,0,200); + border-radius: 100%; + background-color: rgb(200,100,250); + } + @-webkit-keyframes rotation { + from {-webkit-transform: rotate(0deg);} + to {-webkit-transform: rotate(360deg);} + } + @-moz-keyframes rotation { + from {-moz-transform: rotate(0deg);} + to {-moz-transform: rotate(360deg);} + } + @-o-keyframes rotation { + from {-o-transform: rotate(0deg);} + to {-o-transform: rotate(360deg);} + } + @keyframes rotation { + from {transform: rotate(0deg);} + to {transform: rotate(360deg);} + } +
+
emscripten
Downloading...
@@ -35,7 +69,10 @@