Index: third_party/polymer/components/web-animations-js/src/apply-preserving-inline-style.js |
diff --git a/third_party/polymer/components/web-animations-js/src/apply-preserving-inline-style.js b/third_party/polymer/components/web-animations-js/src/apply-preserving-inline-style.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4002a2f568831c59cde2ea815ac6bb52220c9923 |
--- /dev/null |
+++ b/third_party/polymer/components/web-animations-js/src/apply-preserving-inline-style.js |
@@ -0,0 +1,239 @@ |
+// Copyright 2014 Google Inc. All rights reserved. |
+// |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// you may not use this file except in compliance with the License. |
+// You may obtain a copy of the License at |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// Unless required by applicable law or agreed to in writing, software |
+// distributed under the License is distributed on an "AS IS" BASIS, |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// See the License for the specific language governing permissions and |
+// limitations under the License. |
+ |
+(function(scope, testing) { |
+ |
+ var SVG_TRANSFORM_PROP = '_webAnimationsUpdateSvgTransformAttr'; |
+ |
+ /** |
+ * IE/Edge do not support `transform` styles for SVG elements. Instead, |
+ * `transform` attribute can be animated with some restrictions. |
+ * See https://connect.microsoft.com/IE/feedback/details/811744/ie11-bug-with-implementation-of-css-transforms-in-svg, |
+ * https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/1173754/, |
+ * https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/101242/, etc. |
+ * The same problem is exhibited by pre-Chrome Android browsers (ICS). |
+ * Unfortunately, there's no easy way to feature-detect it. |
+ */ |
+ function updateSvgTransformAttr(window, element) { |
+ if (!element.namespaceURI || element.namespaceURI.indexOf('/svg') == -1) { |
+ return false; |
+ } |
+ if (!(SVG_TRANSFORM_PROP in window)) { |
+ window[SVG_TRANSFORM_PROP] = |
+ /Trident|MSIE|IEMobile|Edge|Android 4/i.test(window.navigator.userAgent); |
+ } |
+ return window[SVG_TRANSFORM_PROP]; |
+ } |
+ |
+ var styleAttributes = { |
+ cssText: 1, |
+ length: 1, |
+ parentRule: 1, |
+ }; |
+ |
+ var styleMethods = { |
+ getPropertyCSSValue: 1, |
+ getPropertyPriority: 1, |
+ getPropertyValue: 1, |
+ item: 1, |
+ removeProperty: 1, |
+ setProperty: 1, |
+ }; |
+ |
+ var styleMutatingMethods = { |
+ removeProperty: 1, |
+ setProperty: 1, |
+ }; |
+ |
+ function configureProperty(object, property, descriptor) { |
+ descriptor.enumerable = true; |
+ descriptor.configurable = true; |
+ Object.defineProperty(object, property, descriptor); |
+ } |
+ |
+ function AnimatedCSSStyleDeclaration(element) { |
+ WEB_ANIMATIONS_TESTING && console.assert(!(element.style instanceof AnimatedCSSStyleDeclaration), |
+ 'Element must not already have an animated style attached.'); |
+ |
+ this._element = element; |
+ // Stores the inline style of the element on its behalf while the |
+ // polyfill uses the element's inline style to simulate web animations. |
+ // This is needed to fake regular inline style CSSOM access on the element. |
+ this._surrogateStyle = document.createElementNS('http://www.w3.org/1999/xhtml', 'div').style; |
+ this._style = element.style; |
+ this._length = 0; |
+ this._isAnimatedProperty = {}; |
+ this._updateSvgTransformAttr = updateSvgTransformAttr(window, element); |
+ this._savedTransformAttr = null; |
+ |
+ // Copy the inline style contents over to the surrogate. |
+ for (var i = 0; i < this._style.length; i++) { |
+ var property = this._style[i]; |
+ this._surrogateStyle[property] = this._style[property]; |
+ } |
+ this._updateIndices(); |
+ } |
+ |
+ AnimatedCSSStyleDeclaration.prototype = { |
+ get cssText() { |
+ return this._surrogateStyle.cssText; |
+ }, |
+ set cssText(text) { |
+ var isAffectedProperty = {}; |
+ for (var i = 0; i < this._surrogateStyle.length; i++) { |
+ isAffectedProperty[this._surrogateStyle[i]] = true; |
+ } |
+ this._surrogateStyle.cssText = text; |
+ this._updateIndices(); |
+ for (var i = 0; i < this._surrogateStyle.length; i++) { |
+ isAffectedProperty[this._surrogateStyle[i]] = true; |
+ } |
+ for (var property in isAffectedProperty) { |
+ if (!this._isAnimatedProperty[property]) { |
+ this._style.setProperty(property, this._surrogateStyle.getPropertyValue(property)); |
+ } |
+ } |
+ }, |
+ get length() { |
+ return this._surrogateStyle.length; |
+ }, |
+ get parentRule() { |
+ return this._style.parentRule; |
+ }, |
+ // Mirror the indexed getters and setters of the surrogate style. |
+ _updateIndices: function() { |
+ while (this._length < this._surrogateStyle.length) { |
+ Object.defineProperty(this, this._length, { |
+ configurable: true, |
+ enumerable: false, |
+ get: (function(index) { |
+ return function() { return this._surrogateStyle[index]; }; |
+ })(this._length) |
+ }); |
+ this._length++; |
+ } |
+ while (this._length > this._surrogateStyle.length) { |
+ this._length--; |
+ Object.defineProperty(this, this._length, { |
+ configurable: true, |
+ enumerable: false, |
+ value: undefined |
+ }); |
+ } |
+ }, |
+ _set: function(property, value) { |
+ this._style[property] = value; |
+ this._isAnimatedProperty[property] = true; |
+ if (this._updateSvgTransformAttr && |
+ scope.unprefixedPropertyName(property) == 'transform') { |
+ // On IE/Edge, also set SVG element's `transform` attribute to 2d |
+ // matrix of the transform. The `transform` style does not work, but |
+ // `transform` attribute can be used instead. |
+ // Notice, if the platform indeed supports SVG/CSS transforms the CSS |
+ // declaration is supposed to override the attribute. |
+ if (this._savedTransformAttr == null) { |
+ this._savedTransformAttr = this._element.getAttribute('transform'); |
+ } |
+ this._element.setAttribute('transform', scope.transformToSvgMatrix(value)); |
+ } |
+ }, |
+ _clear: function(property) { |
+ this._style[property] = this._surrogateStyle[property]; |
+ if (this._updateSvgTransformAttr && |
+ scope.unprefixedPropertyName(property) == 'transform') { |
+ if (this._savedTransformAttr) { |
+ this._element.setAttribute('transform', this._savedTransformAttr); |
+ } else { |
+ this._element.removeAttribute('transform'); |
+ } |
+ this._savedTransformAttr = null; |
+ } |
+ delete this._isAnimatedProperty[property]; |
+ }, |
+ }; |
+ |
+ // Wrap the style methods. |
+ for (var method in styleMethods) { |
+ AnimatedCSSStyleDeclaration.prototype[method] = (function(method, modifiesStyle) { |
+ return function() { |
+ var result = this._surrogateStyle[method].apply(this._surrogateStyle, arguments); |
+ if (modifiesStyle) { |
+ if (!this._isAnimatedProperty[arguments[0]]) |
+ this._style[method].apply(this._style, arguments); |
+ this._updateIndices(); |
+ } |
+ return result; |
+ } |
+ })(method, method in styleMutatingMethods); |
+ } |
+ |
+ // Wrap the style.cssProperty getters and setters. |
+ for (var property in document.documentElement.style) { |
+ if (property in styleAttributes || property in styleMethods) { |
+ continue; |
+ } |
+ (function(property) { |
+ configureProperty(AnimatedCSSStyleDeclaration.prototype, property, { |
+ get: function() { |
+ return this._surrogateStyle[property]; |
+ }, |
+ set: function(value) { |
+ this._surrogateStyle[property] = value; |
+ this._updateIndices(); |
+ if (!this._isAnimatedProperty[property]) |
+ this._style[property] = value; |
+ } |
+ }); |
+ })(property); |
+ } |
+ |
+ function ensureStyleIsPatched(element) { |
+ if (element._webAnimationsPatchedStyle) |
+ return; |
+ |
+ var animatedStyle = new AnimatedCSSStyleDeclaration(element); |
+ try { |
+ configureProperty(element, 'style', { get: function() { return animatedStyle; } }); |
+ } catch (_) { |
+ // iOS and older versions of Safari (pre v7) do not support overriding an element's |
+ // style object. Animations will clobber any inline styles as a result. |
+ element.style._set = function(property, value) { |
+ element.style[property] = value; |
+ }; |
+ element.style._clear = function(property) { |
+ element.style[property] = ''; |
+ }; |
+ } |
+ |
+ // We must keep a handle on the patched style to prevent it from getting GC'd. |
+ element._webAnimationsPatchedStyle = element.style; |
+ } |
+ |
+ scope.apply = function(element, property, value) { |
+ ensureStyleIsPatched(element); |
+ element.style._set(scope.propertyName(property), value); |
+ }; |
+ |
+ scope.clear = function(element, property) { |
+ if (element._webAnimationsPatchedStyle) { |
+ element.style._clear(scope.propertyName(property)); |
+ } |
+ }; |
+ |
+ if (WEB_ANIMATIONS_TESTING) { |
+ testing.ensureStyleIsPatched = ensureStyleIsPatched; |
+ testing.updateSvgTransformAttr = updateSvgTransformAttr; |
+ } |
+ |
+})(webAnimations1, webAnimationsTesting); |