// Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // NOTE: This is an import of the NobleJS setImmediate() polyfill located here: // // https://github.com/NobleJS/setImmediate // // It has been customized in the following ways: // // 1) Non-gecko browser compatibility code has been removed. The // postMessage() implementation is always used, except for // web workers. There we use setTimeout(0) since MessageChannel // is not implemented in gecko yet. (Bug 911972) // 2) The support for executing strings with eval() has been // disabled and will now throw an exception. // 3) Convert test code to use suite() and test(). // // The style of this code is different from the rest of gaia, but // we chose to minimize non-functional changes in order to make // importing fixes from upstream easier in the future. // // XXX: Remove this file if/when bug 686201 land. (function (global) { "use strict"; var tasks = (function () { function Task(handler, args) { if (typeof handler !== "function") { throw new Error("setImmediate() handler must be a function; eval not supported"); } this.handler = handler; this.args = args; } Task.prototype.run = function () { // Choice of `thisArg` is not in the setImmediate spec; `undefined` is in the setTimeout spec though: // http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html this.handler.apply(undefined, this.args); }; var nextHandle = 1; // Spec says greater than zero var tasksByHandle = {}; var currentlyRunningATask = false; return { addFromSetImmediateArguments: function (args) { var handler = args[0]; var argsToHandle = Array.prototype.slice.call(args, 1); var task = new Task(handler, argsToHandle); var thisHandle = nextHandle++; tasksByHandle[thisHandle] = task; return thisHandle; }, runIfPresent: function (handle) { // From the spec: "Wait until any invocations of this algorithm started before this one have completed." // So if we're currently running a task, we'll need to delay this invocation. if (!currentlyRunningATask) { var task = tasksByHandle[handle]; if (task) { currentlyRunningATask = true; try { task.run(); } finally { delete tasksByHandle[handle]; currentlyRunningATask = false; } } } else { // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a // "too much recursion" error. global.setTimeout(function () { tasks.runIfPresent(handle); }, 0); } }, remove: function (handle) { delete tasksByHandle[handle]; } }; }()); function canUsePostMessage() { // The test against `importScripts` prevents this implementation from being installed inside a web worker, // where `global.postMessage` means something completely different and can't be used for this purpose. // NOTE: removed async test since it will always pass on gecko return global.postMessage && !global.importScripts; } function installPostMessageImplementation(attachTo) { // Installs an event handler on `global` for the `message` event: see // * https://developer.mozilla.org/en/DOM/global.postMessage // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages var MESSAGE_PREFIX = "com.bn.NobleJS.setImmediate" + Math.random(); function isStringAndStartsWith(string, putativeStart) { return typeof string === "string" && string.substring(0, putativeStart.length) === putativeStart; } function onGlobalMessage(event) { // This will catch all incoming messages (even from other globals!), so we need to try reasonably hard to // avoid letting anyone else trick us into firing off. We test the origin is still this global, and that a // (randomly generated) unpredictable identifying prefix is present. if (event.source === global && isStringAndStartsWith(event.data, MESSAGE_PREFIX)) { var handle = event.data.substring(MESSAGE_PREFIX.length); tasks.runIfPresent(handle); } } global.addEventListener("message", onGlobalMessage, false); attachTo.setImmediate = function () { var handle = tasks.addFromSetImmediateArguments(arguments); // Make `global` post a message to itself with the handle and identifying prefix, thus asynchronously // invoking our onGlobalMessage listener above. global.postMessage(MESSAGE_PREFIX + handle, "*"); return handle; }; } function installSetTimeoutImplementation(attachTo) { attachTo.setImmediate = function () { var handle = tasks.addFromSetImmediateArguments(arguments); global.setTimeout(function () { tasks.runIfPresent(handle); }, 0); return handle; }; } if (!global.setImmediate) { // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live. var attachTo = typeof Object.getPrototypeOf === "function" && "setTimeout" in Object.getPrototypeOf(global) ? Object.getPrototypeOf(global) : global; if (canUsePostMessage()) { // For non-IE10 modern browsers installPostMessageImplementation(attachTo); } else { // NOTE: fallback for web workers in gecko // XXX: replace with MessageChannel impl after bug 911972 lands installSetTimeoutImplementation(attachTo); } attachTo.clearImmediate = tasks.remove; } }(this));