| Index: third_party/google_input_tools/third_party/closure_library/closure/goog/async/nexttick.js
|
| diff --git a/third_party/google_input_tools/third_party/closure_library/closure/goog/async/nexttick.js b/third_party/google_input_tools/third_party/closure_library/closure/goog/async/nexttick.js
|
| index ad2cb9e5891857429d256b70401bb62b0d9528ee..bdbad6b804c88a92558abe22f8687b5719ddbc50 100644
|
| --- a/third_party/google_input_tools/third_party/closure_library/closure/goog/async/nexttick.js
|
| +++ b/third_party/google_input_tools/third_party/closure_library/closure/goog/async/nexttick.js
|
| @@ -23,7 +23,10 @@ goog.provide('goog.async.nextTick');
|
| goog.provide('goog.async.throwException');
|
|
|
| goog.require('goog.debug.entryPointRegistry');
|
| +goog.require('goog.dom.TagName');
|
| goog.require('goog.functions');
|
| +goog.require('goog.labs.userAgent.browser');
|
| +goog.require('goog.labs.userAgent.engine');
|
|
|
|
|
| /**
|
| @@ -41,8 +44,8 @@ goog.async.throwException = function(exception) {
|
|
|
| /**
|
| * Fires the provided callbacks as soon as possible after the current JS
|
| - * execution context. setTimeout(…, 0) always takes at least 5ms for legacy
|
| - * reasons.
|
| + * execution context. setTimeout(…, 0) takes at least 4ms when called from
|
| + * within another setTimeout(…, 0) for legacy reasons.
|
| *
|
| * This will not schedule the callback as a microtask (i.e. a task that can
|
| * preempt user input or networking callbacks). It is meant to emulate what
|
| @@ -52,19 +55,41 @@ goog.async.throwException = function(exception) {
|
| * @param {function(this:SCOPE)} callback Callback function to fire as soon as
|
| * possible.
|
| * @param {SCOPE=} opt_context Object in whose scope to call the listener.
|
| + * @param {boolean=} opt_useSetImmediate Avoid the IE workaround that
|
| + * ensures correctness at the cost of speed. See comments for details.
|
| * @template SCOPE
|
| */
|
| -goog.async.nextTick = function(callback, opt_context) {
|
| +goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) {
|
| var cb = callback;
|
| if (opt_context) {
|
| cb = goog.bind(callback, opt_context);
|
| }
|
| cb = goog.async.nextTick.wrapCallback_(cb);
|
| - // Introduced and currently only supported by IE10.
|
| - if (goog.isFunction(goog.global.setImmediate)) {
|
| + // window.setImmediate was introduced and currently only supported by IE10+,
|
| + // but due to a bug in the implementation it is not guaranteed that
|
| + // setImmediate is faster than setTimeout nor that setImmediate N is before
|
| + // setImmediate N+1. That is why we do not use the native version if
|
| + // available. We do, however, call setImmediate if it is a normal function
|
| + // because that indicates that it has been replaced by goog.testing.MockClock
|
| + // which we do want to support.
|
| + // See
|
| + // http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10
|
| + //
|
| + // Note we do allow callers to also request setImmediate if they are willing
|
| + // to accept the possible tradeoffs of incorrectness in exchange for speed.
|
| + // The IE fallback of readystate change is much slower.
|
| + if (goog.isFunction(goog.global.setImmediate) &&
|
| + // Opt in.
|
| + (opt_useSetImmediate ||
|
| + // or it isn't a browser or the environment is weird
|
| + !goog.global.Window || !goog.global.Window.prototype ||
|
| + // or something redefined setImmediate in which case we (YOLO) decide
|
| + // to use it (This is so that we use the mockClock setImmediate. sigh).
|
| + goog.global.Window.prototype.setImmediate != goog.global.setImmediate)) {
|
| goog.global.setImmediate(cb);
|
| return;
|
| }
|
| +
|
| // Look for and cache the custom fallback version of setImmediate.
|
| if (!goog.async.nextTick.setImmediate_) {
|
| goog.async.nextTick.setImmediate_ =
|
| @@ -97,11 +122,14 @@ goog.async.nextTick.getSetImmediateEmulator_ = function() {
|
| // document.addEventListener. The latter excludes IE8 because it has a
|
| // synchronous postMessage implementation.
|
| if (typeof Channel === 'undefined' && typeof window !== 'undefined' &&
|
| - window.postMessage && window.addEventListener) {
|
| + window.postMessage && window.addEventListener &&
|
| + // Presto (The old pre-blink Opera engine) has problems with iframes
|
| + // and contentWindow.
|
| + !goog.labs.userAgent.engine.isPresto()) {
|
| /** @constructor */
|
| Channel = function() {
|
| // Make an empty, invisible iframe.
|
| - var iframe = document.createElement('iframe');
|
| + var iframe = document.createElement(goog.dom.TagName.IFRAME);
|
| iframe.style.display = 'none';
|
| iframe.src = '';
|
| document.documentElement.appendChild(iframe);
|
| @@ -121,8 +149,10 @@ goog.async.nextTick.getSetImmediateEmulator_ = function() {
|
| '*' : win.location.protocol + '//' + win.location.host;
|
| var onmessage = goog.bind(function(e) {
|
| // Validate origin and message to make sure that this message was
|
| - // intended for us.
|
| - if (e.origin != origin && e.data != message) {
|
| + // intended for us. If the origin is set to '*' (see above) only the
|
| + // message needs to match since, for example, '*' != 'file://'. Allowing
|
| + // the wildcard is ok, as we are not concerned with security here.
|
| + if ((origin != '*' && e.origin != origin) || e.data != message) {
|
| return;
|
| }
|
| this['port1'].onmessage();
|
| @@ -136,16 +166,24 @@ goog.async.nextTick.getSetImmediateEmulator_ = function() {
|
| };
|
| };
|
| }
|
| - if (typeof Channel !== 'undefined') {
|
| + if (typeof Channel !== 'undefined' &&
|
| + (!goog.labs.userAgent.browser.isIE())) {
|
| + // Exclude all of IE due to
|
| + // http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/
|
| + // which allows starving postMessage with a busy setTimeout loop.
|
| + // This currently affects IE10 and IE11 which would otherwise be able
|
| + // to use the postMessage based fallbacks.
|
| var channel = new Channel();
|
| // Use a fifo linked list to call callbacks in the right order.
|
| var head = {};
|
| var tail = head;
|
| channel['port1'].onmessage = function() {
|
| - head = head.next;
|
| - var cb = head.cb;
|
| - head.cb = null;
|
| - cb();
|
| + if (goog.isDef(head.next)) {
|
| + head = head.next;
|
| + var cb = head.cb;
|
| + head.cb = null;
|
| + cb();
|
| + }
|
| };
|
| return function(cb) {
|
| tail.next = {
|
| @@ -155,12 +193,12 @@ goog.async.nextTick.getSetImmediateEmulator_ = function() {
|
| channel['port2'].postMessage(0);
|
| };
|
| }
|
| - // Implementation for IE6-8: Script elements fire an asynchronous
|
| + // Implementation for IE6+: Script elements fire an asynchronous
|
| // onreadystatechange event when inserted into the DOM.
|
| if (typeof document !== 'undefined' && 'onreadystatechange' in
|
| - document.createElement('script')) {
|
| + document.createElement(goog.dom.TagName.SCRIPT)) {
|
| return function(cb) {
|
| - var script = document.createElement('script');
|
| + var script = document.createElement(goog.dom.TagName.SCRIPT);
|
| script.onreadystatechange = function() {
|
| // Clean up and call the callback.
|
| script.onreadystatechange = null;
|
|
|