text: /// BareSpecifier=web-animations-js/src/apply-preserving-inline-style
  // 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);