text: // Copyright (c) 2013 Adobe Systems Incorporated. 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.
  Snap.plugin(function (Snap, Element, Paper, glob) {
      var elproto = Element.prototype,
          pproto = Paper.prototype,
          rgurl = /^\s*url\((.+)\)/,
          Str = String,
          $ = Snap._.$;
      Snap.filter = {};
  // SIERRA Paper.filter(): I don't understand the note. Does that mean an HTML should dedicate a separate SVG region for a filter definition? What's the advantage over a DEFS?
      /*\
       * Paper.filter
       [ method ]
       **
       * Creates a `<filter>` element
       **
       - filstr (string) SVG fragment of filter provided as a string
       = (object) @Element
       * Note: It is recommended to use filters embedded into the page inside an empty SVG element.
       > Usage
       | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'),
       |     c = paper.circle(10, 10, 10).attr({
       |         filter: f
       |     });
      \*/
      pproto.filter = function (filstr) {
          var paper = this;
          if (paper.type != "svg") {
              paper = paper.paper;
          }
          var f = Snap.parse(Str(filstr)),
              id = Snap._.id(),
              width = paper.node.offsetWidth,
              height = paper.node.offsetHeight,
              filter = $("filter");
          $(filter, {
              id: id,
              filterUnits: "userSpaceOnUse",
              x: 0,
              y: 0,
              width: width,
              height: height
          });
          filter.appendChild(f.node);
          paper.defs.appendChild(filter);
          return new Element(filter);
      };
      
      eve.on("snap.util.getattr.filter", function () {
          eve.stop();
          var p = $(this.node, "filter");
          if (p) {
              var match = Str(p).match(rgurl);
              return match && Snap.select(match[1]);
          }
      });
      eve.on("snap.util.attr.filter", function (value) {
          if (value instanceof Element && value.type == "filter") {
              eve.stop();
              var id = value.node.id;
              if (!id) {
                  $(value.node, {id: value.id});
                  id = value.id;
              }
              $(this.node, {
                  filter: "url(#" + id + ")"
              });
          }
          if (!value || value == "none") {
              eve.stop();
              this.node.removeAttribute("filter");
          }
      });
      // SIERRA Would help to clarify when various Snap.filter.* matches the behavior of CSS filter property keyword functions. E.g., I don't think CSS's blur() accepts a second parameter for y axis.
      // SIERRA Would also be useful to illustrate a chain of >1 filter as a code snippet.
      /*\
       * Snap.filter.blur
       [ method ]
       **
       * Returns an SVG markup string for the blur filter
       **
       - x (number) amount of horizontal blur, in pixels
       - y (number) #optional amount of vertical blur, in pixels
       = (string) filter representation
       > Usage
       | var f = paper.filter(Snap.filter.blur(5, 10)),
       |     c = paper.circle(10, 10, 10).attr({
       |         filter: f
       |     });
      \*/
      Snap.filter.blur = function (x, y) {
          if (x == null) {
              x = 2;
          }
          var def = y == null ? x : [x, y];
          return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', {
              def: def
          });
      };
      Snap.filter.blur.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.shadow
       [ method ]
       **
       * Returns an SVG markup string for the shadow filter
       **
       - dx (number) horizontal shift of the shadow, in pixels
       - dy (number) vertical shift of the shadow, in pixels
       - blur (number) #optional amount of blur
       - color (string) #optional color of the shadow
       = (string) filter representation
       > Usage
       | var f = paper.filter(Snap.filter.shadow(0, 2, 3)),
       |     c = paper.circle(10, 10, 10).attr({
       |         filter: f
       |     });
      \*/
      Snap.filter.shadow = function (dx, dy, blur, color) {
          color = color || "#000";
          if (blur == null) {
              blur = 4;
          }
          if (typeof blur == "string") {
              color = blur;
              blur = 4;
          }
          if (dx == null) {
              dx = 0;
              dy = 2;
          }
          if (dy == null) {
              dy = dx;
          }
          color = Snap.color(color);
          return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', {
              color: color,
              dx: dx,
              dy: dy,
              blur: blur
          });
      };
      Snap.filter.shadow.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.grayscale
       [ method ]
       **
       * Returns an SVG markup string for the grayscale filter
       **
       - amount (number) amount of filter (`0..1`)
       = (string) filter representation
      \*/
      Snap.filter.grayscale = function (amount) {
          if (amount == null) {
              amount = 1;
          }
          return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', {
              a: 0.2126 + 0.7874 * (1 - amount),
              b: 0.7152 - 0.7152 * (1 - amount),
              c: 0.0722 - 0.0722 * (1 - amount),
              d: 0.2126 - 0.2126 * (1 - amount),
              e: 0.7152 + 0.2848 * (1 - amount),
              f: 0.0722 - 0.0722 * (1 - amount),
              g: 0.2126 - 0.2126 * (1 - amount),
              h: 0.0722 + 0.9278 * (1 - amount)
          });
      };
      Snap.filter.grayscale.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.sepia
       [ method ]
       **
       * Returns an SVG markup string for the sepia filter
       **
       - amount (number) amount of filter (`0..1`)
       = (string) filter representation
      \*/
      Snap.filter.sepia = function (amount) {
          if (amount == null) {
              amount = 1;
          }
          return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', {
              a: 0.393 + 0.607 * (1 - amount),
              b: 0.769 - 0.769 * (1 - amount),
              c: 0.189 - 0.189 * (1 - amount),
              d: 0.349 - 0.349 * (1 - amount),
              e: 0.686 + 0.314 * (1 - amount),
              f: 0.168 - 0.168 * (1 - amount),
              g: 0.272 - 0.272 * (1 - amount),
              h: 0.534 - 0.534 * (1 - amount),
              i: 0.131 + 0.869 * (1 - amount)
          });
      };
      Snap.filter.sepia.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.saturate
       [ method ]
       **
       * Returns an SVG markup string for the saturate filter
       **
       - amount (number) amount of filter (`0..1`)
       = (string) filter representation
      \*/
      Snap.filter.saturate = function (amount) {
          if (amount == null) {
              amount = 1;
          }
          return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', {
              amount: 1 - amount
          });
      };
      Snap.filter.saturate.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.hueRotate
       [ method ]
       **
       * Returns an SVG markup string for the hue-rotate filter
       **
       - angle (number) angle of rotation
       = (string) filter representation
      \*/
      Snap.filter.hueRotate = function (angle) {
          angle = angle || 0;
          return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', {
              angle: angle
          });
      };
      Snap.filter.hueRotate.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.invert
       [ method ]
       **
       * Returns an SVG markup string for the invert filter
       **
       - amount (number) amount of filter (`0..1`)
       = (string) filter representation
      \*/
      Snap.filter.invert = function (amount) {
          if (amount == null) {
              amount = 1;
          }
          return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', {
              amount: amount,
              amount2: 1 - amount
          });
      };
      Snap.filter.invert.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.brightness
       [ method ]
       **
       * Returns an SVG markup string for the brightness filter
       **
       - amount (number) amount of filter (`0..1`)
       = (string) filter representation
      \*/
      Snap.filter.brightness = function (amount) {
          if (amount == null) {
              amount = 1;
          }
          return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', {
              amount: amount
          });
      };
      Snap.filter.brightness.toString = function () {
          return this();
      };
      /*\
       * Snap.filter.contrast
       [ method ]
       **
       * Returns an SVG markup string for the contrast filter
       **
       - amount (number) amount of filter (`0..1`)
       = (string) filter representation
      \*/
      Snap.filter.contrast = function (amount) {
          if (amount == null) {
              amount = 1;
          }
          return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', {
              amount: amount,
              amount2: .5 - amount / 2
          });
      };
      Snap.filter.contrast.toString = function () {
          return this();
      };
  });