{"version":3,"file":"pwc-576.f7251f80.chunk.js","mappings":"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","sources":["../node_modules/fabric/dist/fabric.js","../node_modules/use-query-params/adapters/react-router-5/index.js"],"sourcesContent":["/* build: `node build.js modules=ALL exclude=gestures,accessors,erasing requirejs minifier=uglifyjs` */\n/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */\n\nvar fabric = fabric || { version: '5.4.2' };\nif (typeof exports !== 'undefined') {\n  exports.fabric = fabric;\n}\n/* _AMD_START_ */\nelse if (typeof define === 'function' && define.amd) {\n  define([], function() { return fabric; });\n}\n/* _AMD_END_ */\nif (typeof document !== 'undefined' && typeof window !== 'undefined') {\n  if (document instanceof (typeof HTMLDocument !== 'undefined' ? HTMLDocument : Document)) {\n    fabric.document = document;\n  }\n  else {\n    fabric.document = document.implementation.createHTMLDocument('');\n  }\n  fabric.window = window;\n}\nelse {\n  // assume we're running under node.js when document/window are not present\n  var jsdom = require('jsdom');\n  var virtualWindow = new jsdom.JSDOM(\n    decodeURIComponent('%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E'),\n    {\n      features: {\n        FetchExternalResources: ['img']\n      },\n      resources: 'usable'\n    }).window;\n  fabric.document = virtualWindow.document;\n  fabric.jsdomImplForWrapper = require('jsdom/lib/jsdom/living/generated/utils').implForWrapper;\n  fabric.nodeCanvas = require('jsdom/lib/jsdom/utils').Canvas;\n  fabric.window = virtualWindow;\n  DOMParser = fabric.window.DOMParser;\n}\n\n/**\n * True when in environment that supports touch events\n * @type boolean\n */\nfabric.isTouchSupported = 'ontouchstart' in fabric.window || 'ontouchstart' in fabric.document ||\n  (fabric.window && fabric.window.navigator && fabric.window.navigator.maxTouchPoints > 0);\n\n/**\n * True when in environment that's probably Node.js\n * @type boolean\n */\nfabric.isLikelyNode = typeof Buffer !== 'undefined' &&\n                      typeof window === 'undefined';\n\n/* _FROM_SVG_START_ */\n/**\n * Attributes parsed from all SVG elements\n * @type array\n */\nfabric.SHARED_ATTRIBUTES = [\n  'display',\n  'transform',\n  'fill', 'fill-opacity', 'fill-rule',\n  'opacity',\n  'stroke', 'stroke-dasharray', 'stroke-linecap', 'stroke-dashoffset',\n  'stroke-linejoin', 'stroke-miterlimit',\n  'stroke-opacity', 'stroke-width',\n  'id', 'paint-order', 'vector-effect',\n  'instantiated_by_use', 'clip-path',\n];\n/* _FROM_SVG_END_ */\n\n/**\n * Pixel per Inch as a default value set to 96. Can be changed for more realistic conversion.\n */\nfabric.DPI = 96;\nfabric.reNum = '(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:[eE][-+]?\\\\d+)?)';\nfabric.commaWsp = '(?:\\\\s+,?\\\\s*|,\\\\s*)';\nfabric.rePathCommand = /([-+]?((\\d+\\.\\d+)|((\\d+)|(\\.\\d+)))(?:[eE][-+]?\\d+)?)/ig;\nfabric.reNonWord = /[ \\n\\.,;!\\?\\-]/;\nfabric.fontPaths = { };\nfabric.iMatrix = [1, 0, 0, 1, 0, 0];\nfabric.svgNS = 'http://www.w3.org/2000/svg';\n\n/**\n * Pixel limit for cache canvases. 1Mpx , 4Mpx should be fine.\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.perfLimitSizeTotal = 2097152;\n\n/**\n * Pixel limit for cache canvases width or height. IE fixes the maximum at 5000\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.maxCacheSideLimit = 4096;\n\n/**\n * Lowest pixel limit for cache canvases, set at 256PX\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.minCacheSideLimit = 256;\n\n/**\n * Cache Object for widths of chars in text rendering.\n */\nfabric.charWidthsCache = { };\n\n/**\n * if webgl is enabled and available, textureSize will determine the size\n * of the canvas backend\n * @since 2.0.0\n * @type Number\n * @default\n */\nfabric.textureSize = 2048;\n\n/**\n * When 'true', style information is not retained when copy/pasting text, making\n * pasted text use destination style.\n * Defaults to 'false'.\n * @type Boolean\n * @default\n */\nfabric.disableStyleCopyPaste = false;\n\n/**\n * Enable webgl for filtering picture is available\n * A filtering backend will be initialized, this will both take memory and\n * time since a default 2048x2048 canvas will be created for the gl context\n * @since 2.0.0\n * @type Boolean\n * @default\n */\nfabric.enableGLFiltering = true;\n\n/**\n * Device Pixel Ratio\n * @see https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/SettingUptheCanvas/SettingUptheCanvas.html\n */\nfabric.devicePixelRatio = fabric.window.devicePixelRatio ||\n                          fabric.window.webkitDevicePixelRatio ||\n                          fabric.window.mozDevicePixelRatio ||\n                          1;\n/**\n * Browser-specific constant to adjust CanvasRenderingContext2D.shadowBlur value,\n * which is unitless and not rendered equally across browsers.\n *\n * Values that work quite well (as of October 2017) are:\n * - Chrome: 1.5\n * - Edge: 1.75\n * - Firefox: 0.9\n * - Safari: 0.95\n *\n * @since 2.0.0\n * @type Number\n * @default 1\n */\nfabric.browserShadowBlurConstant = 1;\n\n/**\n * This object contains the result of arc to bezier conversion for faster retrieving if the same arc needs to be converted again.\n * It was an internal variable, is accessible since version 2.3.4\n */\nfabric.arcToSegmentsCache = { };\n\n/**\n * This object keeps the results of the boundsOfCurve calculation mapped by the joined arguments necessary to calculate it.\n * It does speed up calculation, if you parse and add always the same paths, but in case of heavy usage of freedrawing\n * you do not get any speed benefit and you get a big object in memory.\n * The object was a private variable before, while now is appended to the lib so that you have access to it and you\n * can eventually clear it.\n * It was an internal variable, is accessible since version 2.3.4\n */\nfabric.boundsOfCurveCache = { };\n\n/**\n * If disabled boundsOfCurveCache is not used. For apps that make heavy usage of pencil drawing probably disabling it is better\n * @default true\n */\nfabric.cachesBoundsOfCurve = true;\n\n/**\n * Skip performance testing of setupGLContext and force the use of putImageData that seems to be the one that works best on\n * Chrome + old hardware. if your users are experiencing empty images after filtering you may try to force this to true\n * this has to be set before instantiating the filtering backend ( before filtering the first image )\n * @type Boolean\n * @default false\n */\nfabric.forceGLPutImageData = false;\n\nfabric.initFilterBackend = function() {\n  if (fabric.enableGLFiltering && fabric.isWebglSupported && fabric.isWebglSupported(fabric.textureSize)) {\n    console.log('max texture size: ' + fabric.maxTextureSize);\n    return (new fabric.WebglFilterBackend({ tileSize: fabric.textureSize }));\n  }\n  else if (fabric.Canvas2dFilterBackend) {\n    return (new fabric.Canvas2dFilterBackend());\n  }\n};\n\n\nif (typeof document !== 'undefined' && typeof window !== 'undefined') {\n  // ensure globality even if entire library were function wrapped (as in Meteor.js packaging system)\n  window.fabric = fabric;\n}\n\n\n(function() {\n\n  /**\n   * @private\n   * @param {String} eventName\n   * @param {Function} handler\n   */\n  function _removeEventListener(eventName, handler) {\n    if (!this.__eventListeners[eventName]) {\n      return;\n    }\n    var eventListener = this.__eventListeners[eventName];\n    if (handler) {\n      eventListener[eventListener.indexOf(handler)] = false;\n    }\n    else {\n      fabric.util.array.fill(eventListener, false);\n    }\n  }\n\n  /**\n   * Observes specified event\n   * @memberOf fabric.Observable\n   * @alias on\n   * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n   * @param {Function} handler Function that receives a notification when an event of the specified type occurs\n   * @return {Self} thisArg\n   * @chainable\n   */\n  function on(eventName, handler) {\n    if (!this.__eventListeners) {\n      this.__eventListeners = { };\n    }\n    // one object with key/value pairs was passed\n    if (arguments.length === 1) {\n      for (var prop in eventName) {\n        this.on(prop, eventName[prop]);\n      }\n    }\n    else {\n      if (!this.__eventListeners[eventName]) {\n        this.__eventListeners[eventName] = [];\n      }\n      this.__eventListeners[eventName].push(handler);\n    }\n    return this;\n  }\n\n  function _once(eventName, handler) {\n    var _handler = function () {\n      handler.apply(this, arguments);\n      this.off(eventName, _handler);\n    }.bind(this);\n    this.on(eventName, _handler);\n  }\n\n  function once(eventName, handler) {\n    // one object with key/value pairs was passed\n    if (arguments.length === 1) {\n      for (var prop in eventName) {\n        _once.call(this, prop, eventName[prop]);\n      }\n    }\n    else {\n      _once.call(this, eventName, handler);\n    }\n    return this;\n  }\n\n  /**\n   * Stops event observing for a particular event handler. Calling this method\n   * without arguments removes all handlers for all events\n   * @memberOf fabric.Observable\n   * @alias off\n   * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n   * @param {Function} handler Function to be deleted from EventListeners\n   * @return {Self} thisArg\n   * @chainable\n   */\n  function off(eventName, handler) {\n    if (!this.__eventListeners) {\n      return this;\n    }\n\n    // remove all key/value pairs (event name -> event handler)\n    if (arguments.length === 0) {\n      for (eventName in this.__eventListeners) {\n        _removeEventListener.call(this, eventName);\n      }\n    }\n    // one object with key/value pairs was passed\n    else if (arguments.length === 1 && typeof arguments[0] === 'object') {\n      for (var prop in eventName) {\n        _removeEventListener.call(this, prop, eventName[prop]);\n      }\n    }\n    else {\n      _removeEventListener.call(this, eventName, handler);\n    }\n    return this;\n  }\n\n  /**\n   * Fires event with an optional options object\n   * @memberOf fabric.Observable\n   * @param {String} eventName Event name to fire\n   * @param {Object} [options] Options object\n   * @return {Self} thisArg\n   * @chainable\n   */\n  function fire(eventName, options) {\n    if (!this.__eventListeners) {\n      return this;\n    }\n\n    var listenersForEvent = this.__eventListeners[eventName];\n    if (!listenersForEvent) {\n      return this;\n    }\n\n    for (var i = 0, len = listenersForEvent.length; i < len; i++) {\n      listenersForEvent[i] && listenersForEvent[i].call(this, options || { });\n    }\n    this.__eventListeners[eventName] = listenersForEvent.filter(function(value) {\n      return value !== false;\n    });\n    return this;\n  }\n\n  /**\n   * @namespace fabric.Observable\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events}\n   * @see {@link http://fabricjs.com/events|Events demo}\n   */\n  fabric.Observable = {\n    fire: fire,\n    on: on,\n    once: once,\n    off: off,\n  };\n})();\n\n\n/**\n * @namespace fabric.Collection\n */\nfabric.Collection = {\n\n  _objects: [],\n\n  /**\n   * Adds objects to collection, Canvas or Group, then renders canvas\n   * (if `renderOnAddRemove` is not `false`).\n   * in case of Group no changes to bounding box are made.\n   * Objects should be instances of (or inherit from) fabric.Object\n   * Use of this function is highly discouraged for groups.\n   * you can add a bunch of objects with the add method but then you NEED\n   * to run a addWithUpdate call for the Group class or position/bbox will be wrong.\n   * @param {...fabric.Object} object Zero or more fabric instances\n   * @return {Self} thisArg\n   * @chainable\n   */\n  add: function () {\n    this._objects.push.apply(this._objects, arguments);\n    if (this._onObjectAdded) {\n      for (var i = 0, length = arguments.length; i < length; i++) {\n        this._onObjectAdded(arguments[i]);\n      }\n    }\n    this.renderOnAddRemove && this.requestRenderAll();\n    return this;\n  },\n\n  /**\n   * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`)\n   * An object should be an instance of (or inherit from) fabric.Object\n   * Use of this function is highly discouraged for groups.\n   * you can add a bunch of objects with the insertAt method but then you NEED\n   * to run a addWithUpdate call for the Group class or position/bbox will be wrong.\n   * @param {Object} object Object to insert\n   * @param {Number} index Index to insert object at\n   * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs\n   * @return {Self} thisArg\n   * @chainable\n   */\n  insertAt: function (object, index, nonSplicing) {\n    var objects = this._objects;\n    if (nonSplicing) {\n      objects[index] = object;\n    }\n    else {\n      objects.splice(index, 0, object);\n    }\n    this._onObjectAdded && this._onObjectAdded(object);\n    this.renderOnAddRemove && this.requestRenderAll();\n    return this;\n  },\n\n  /**\n   * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n   * @param {...fabric.Object} object Zero or more fabric instances\n   * @return {Self} thisArg\n   * @chainable\n   */\n  remove: function() {\n    var objects = this._objects,\n        index, somethingRemoved = false;\n\n    for (var i = 0, length = arguments.length; i < length; i++) {\n      index = objects.indexOf(arguments[i]);\n\n      // only call onObjectRemoved if an object was actually removed\n      if (index !== -1) {\n        somethingRemoved = true;\n        objects.splice(index, 1);\n        this._onObjectRemoved && this._onObjectRemoved(arguments[i]);\n      }\n    }\n\n    this.renderOnAddRemove && somethingRemoved && this.requestRenderAll();\n    return this;\n  },\n\n  /**\n   * Executes given function for each object in this group\n   * @param {Function} callback\n   *                   Callback invoked with current object as first argument,\n   *                   index - as second and an array of all objects - as third.\n   *                   Callback is invoked in a context of Global Object (e.g. `window`)\n   *                   when no `context` argument is given\n   *\n   * @param {Object} context Context (aka thisObject)\n   * @return {Self} thisArg\n   * @chainable\n   */\n  forEachObject: function(callback, context) {\n    var objects = this.getObjects();\n    for (var i = 0, len = objects.length; i < len; i++) {\n      callback.call(context, objects[i], i, objects);\n    }\n    return this;\n  },\n\n  /**\n   * Returns an array of children objects of this instance\n   * Type parameter introduced in 1.3.10\n   * since 2.3.5 this method return always a COPY of the array;\n   * @param {String} [type] When specified, only objects of this type are returned\n   * @return {Array}\n   */\n  getObjects: function(type) {\n    if (typeof type === 'undefined') {\n      return this._objects.concat();\n    }\n    return this._objects.filter(function(o) {\n      return o.type === type;\n    });\n  },\n\n  /**\n   * Returns object at specified index\n   * @param {Number} index\n   * @return {Self} thisArg\n   */\n  item: function (index) {\n    return this._objects[index];\n  },\n\n  /**\n   * Returns true if collection contains no objects\n   * @return {Boolean} true if collection is empty\n   */\n  isEmpty: function () {\n    return this._objects.length === 0;\n  },\n\n  /**\n   * Returns a size of a collection (i.e: length of an array containing its objects)\n   * @return {Number} Collection size\n   */\n  size: function() {\n    return this._objects.length;\n  },\n\n  /**\n   * Returns true if collection contains an object\n   * @param {Object} object Object to check against\n   * @param {Boolean} [deep=false] `true` to check all descendants, `false` to check only `_objects`\n   * @return {Boolean} `true` if collection contains an object\n   */\n  contains: function (object, deep) {\n    if (this._objects.indexOf(object) > -1) {\n      return true;\n    }\n    else if (deep) {\n      return this._objects.some(function (obj) {\n        return typeof obj.contains === 'function' && obj.contains(object, true);\n      });\n    }\n    return false;\n  },\n\n  /**\n   * Returns number representation of a collection complexity\n   * @return {Number} complexity\n   */\n  complexity: function () {\n    return this._objects.reduce(function (memo, current) {\n      memo += current.complexity ? current.complexity() : 0;\n      return memo;\n    }, 0);\n  }\n};\n\n\n/**\n * @namespace fabric.CommonMethods\n */\nfabric.CommonMethods = {\n\n  /**\n   * Sets object's properties from options\n   * @param {Object} [options] Options object\n   */\n  _setOptions: function(options) {\n    for (var prop in options) {\n      this.set(prop, options[prop]);\n    }\n  },\n\n  /**\n   * @private\n   * @param {Object} [filler] Options object\n   * @param {String} [property] property to set the Gradient to\n   */\n  _initGradient: function(filler, property) {\n    if (filler && filler.colorStops && !(filler instanceof fabric.Gradient)) {\n      this.set(property, new fabric.Gradient(filler));\n    }\n  },\n\n  /**\n   * @private\n   * @param {Object} [filler] Options object\n   * @param {String} [property] property to set the Pattern to\n   * @param {Function} [callback] callback to invoke after pattern load\n   */\n  _initPattern: function(filler, property, callback) {\n    if (filler && filler.source && !(filler instanceof fabric.Pattern)) {\n      this.set(property, new fabric.Pattern(filler, callback));\n    }\n    else {\n      callback && callback();\n    }\n  },\n\n  /**\n   * @private\n   */\n  _setObject: function(obj) {\n    for (var prop in obj) {\n      this._set(prop, obj[prop]);\n    }\n  },\n\n  /**\n   * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.\n   * @param {String|Object} key Property name or object (if object, iterate over the object properties)\n   * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  set: function(key, value) {\n    if (typeof key === 'object') {\n      this._setObject(key);\n    }\n    else {\n      this._set(key, value);\n    }\n    return this;\n  },\n\n  _set: function(key, value) {\n    this[key] = value;\n  },\n\n  /**\n   * Toggles specified property from `true` to `false` or from `false` to `true`\n   * @param {String} property Property to toggle\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  toggle: function(property) {\n    var value = this.get(property);\n    if (typeof value === 'boolean') {\n      this.set(property, !value);\n    }\n    return this;\n  },\n\n  /**\n   * Basic getter\n   * @param {String} property Property name\n   * @return {*} value of a property\n   */\n  get: function(property) {\n    return this[property];\n  }\n};\n\n\n(function(global) {\n\n  var sqrt = Math.sqrt,\n      atan2 = Math.atan2,\n      pow = Math.pow,\n      PiBy180 = Math.PI / 180,\n      PiBy2 = Math.PI / 2;\n\n  /**\n   * @namespace fabric.util\n   */\n  fabric.util = {\n\n    /**\n     * Calculate the cos of an angle, avoiding returning floats for known results\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} angle the angle in radians or in degree\n     * @return {Number}\n     */\n    cos: function(angle) {\n      if (angle === 0) { return 1; }\n      if (angle < 0) {\n        // cos(a) = cos(-a)\n        angle = -angle;\n      }\n      var angleSlice = angle / PiBy2;\n      switch (angleSlice) {\n        case 1: case 3: return 0;\n        case 2: return -1;\n      }\n      return Math.cos(angle);\n    },\n\n    /**\n     * Calculate the sin of an angle, avoiding returning floats for known results\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} angle the angle in radians or in degree\n     * @return {Number}\n     */\n    sin: function(angle) {\n      if (angle === 0) { return 0; }\n      var angleSlice = angle / PiBy2, sign = 1;\n      if (angle < 0) {\n        // sin(-a) = -sin(a)\n        sign = -1;\n      }\n      switch (angleSlice) {\n        case 1: return sign;\n        case 2: return 0;\n        case 3: return -sign;\n      }\n      return Math.sin(angle);\n    },\n\n    /**\n     * Removes value from an array.\n     * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf`\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} array\n     * @param {*} value\n     * @return {Array} original array\n     */\n    removeFromArray: function(array, value) {\n      var idx = array.indexOf(value);\n      if (idx !== -1) {\n        array.splice(idx, 1);\n      }\n      return array;\n    },\n\n    /**\n     * Returns random number between 2 specified ones.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} min lower limit\n     * @param {Number} max upper limit\n     * @return {Number} random value (between min and max)\n     */\n    getRandomInt: function(min, max) {\n      return Math.floor(Math.random() * (max - min + 1)) + min;\n    },\n\n    /**\n     * Transforms degrees to radians.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} degrees value in degrees\n     * @return {Number} value in radians\n     */\n    degreesToRadians: function(degrees) {\n      return degrees * PiBy180;\n    },\n\n    /**\n     * Transforms radians to degrees.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number} radians value in radians\n     * @return {Number} value in degrees\n     */\n    radiansToDegrees: function(radians) {\n      return radians / PiBy180;\n    },\n\n    /**\n     * Rotates `point` around `origin` with `radians`\n     * @static\n     * @memberOf fabric.util\n     * @param {fabric.Point} point The point to rotate\n     * @param {fabric.Point} origin The origin of the rotation\n     * @param {Number} radians The radians of the angle for the rotation\n     * @return {fabric.Point} The new rotated point\n     */\n    rotatePoint: function(point, origin, radians) {\n      var newPoint = new fabric.Point(point.x - origin.x, point.y - origin.y),\n          v = fabric.util.rotateVector(newPoint, radians);\n      return new fabric.Point(v.x, v.y).addEquals(origin);\n    },\n\n    /**\n     * Rotates `vector` with `radians`\n     * @static\n     * @memberOf fabric.util\n     * @param {Object} vector The vector to rotate (x and y)\n     * @param {Number} radians The radians of the angle for the rotation\n     * @return {Object} The new rotated point\n     */\n    rotateVector: function(vector, radians) {\n      var sin = fabric.util.sin(radians),\n          cos = fabric.util.cos(radians),\n          rx = vector.x * cos - vector.y * sin,\n          ry = vector.x * sin + vector.y * cos;\n      return {\n        x: rx,\n        y: ry\n      };\n    },\n\n    /**\n     * Creates a vetor from points represented as a point\n     * @static\n     * @memberOf fabric.util\n     *\n     * @typedef {Object} Point\n     * @property {number} x\n     * @property {number} y\n     *\n     * @param {Point} from\n     * @param {Point} to\n     * @returns {Point} vector\n     */\n    createVector: function (from, to) {\n      return new fabric.Point(to.x - from.x, to.y - from.y);\n    },\n\n    /**\n     * Calculates angle between 2 vectors using dot product\n     * @static\n     * @memberOf fabric.util\n     * @param {Point} a\n     * @param {Point} b\n     * @returns the angle in radian between the vectors\n     */\n    calcAngleBetweenVectors: function (a, b) {\n      return Math.acos((a.x * b.x + a.y * b.y) / (Math.hypot(a.x, a.y) * Math.hypot(b.x, b.y)));\n    },\n\n    /**\n     * @static\n     * @memberOf fabric.util\n     * @param {Point} v\n     * @returns {Point} vector representing the unit vector of pointing to the direction of `v`\n     */\n    getHatVector: function (v) {\n      return new fabric.Point(v.x, v.y).multiply(1 / Math.hypot(v.x, v.y));\n    },\n\n    /**\n     * @static\n     * @memberOf fabric.util\n     * @param {Point} A\n     * @param {Point} B\n     * @param {Point} C\n     * @returns {{ vector: Point, angle: number }} vector representing the bisector of A and A's angle\n     */\n    getBisector: function (A, B, C) {\n      var AB = fabric.util.createVector(A, B), AC = fabric.util.createVector(A, C);\n      var alpha = fabric.util.calcAngleBetweenVectors(AB, AC);\n      //  check if alpha is relative to AB->BC\n      var ro = fabric.util.calcAngleBetweenVectors(fabric.util.rotateVector(AB, alpha), AC);\n      var phi = alpha * (ro === 0 ? 1 : -1) / 2;\n      return {\n        vector: fabric.util.getHatVector(fabric.util.rotateVector(AB, phi)),\n        angle: alpha\n      };\n    },\n\n    /**\n     * Project stroke width on points returning 2 projections for each point as follows:\n     * - `miter`: 2 points corresponding to the outer boundary and the inner boundary of stroke.\n     * - `bevel`: 2 points corresponding to the bevel boundaries, tangent to the bisector.\n     * - `round`: same as `bevel`\n     * Used to calculate object's bounding box\n     * @static\n     * @memberOf fabric.util\n     * @param {Point[]} points\n     * @param {Object} options\n     * @param {number} options.strokeWidth\n     * @param {'miter'|'bevel'|'round'} options.strokeLineJoin\n     * @param {number} options.strokeMiterLimit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit\n     * @param {boolean} options.strokeUniform\n     * @param {number} options.scaleX\n     * @param {number} options.scaleY\n     * @param {boolean} [openPath] whether the shape is open or not, affects the calculations of the first and last points\n     * @returns {fabric.Point[]} array of size 2n/4n of all suspected points\n     */\n    projectStrokeOnPoints: function (points, options, openPath) {\n      var coords = [], s = options.strokeWidth / 2,\n          strokeUniformScalar = options.strokeUniform ?\n            new fabric.Point(1 / options.scaleX, 1 / options.scaleY) : new fabric.Point(1, 1),\n          getStrokeHatVector = function (v) {\n            var scalar = s / (Math.hypot(v.x, v.y));\n            return new fabric.Point(v.x * scalar * strokeUniformScalar.x, v.y * scalar * strokeUniformScalar.y);\n          };\n      if (points.length <= 1) {return coords;}\n      points.forEach(function (p, index) {\n        var A = new fabric.Point(p.x, p.y), B, C;\n        if (index === 0) {\n          C = points[index + 1];\n          B = openPath ? getStrokeHatVector(fabric.util.createVector(C, A)).addEquals(A) : points[points.length - 1];\n        }\n        else if (index === points.length - 1) {\n          B = points[index - 1];\n          C = openPath ? getStrokeHatVector(fabric.util.createVector(B, A)).addEquals(A) : points[0];\n        }\n        else {\n          B = points[index - 1];\n          C = points[index + 1];\n        }\n        var bisector = fabric.util.getBisector(A, B, C),\n            bisectorVector = bisector.vector,\n            alpha = bisector.angle,\n            scalar,\n            miterVector;\n        if (options.strokeLineJoin === 'miter') {\n          scalar = -s / Math.sin(alpha / 2);\n          miterVector = new fabric.Point(\n            bisectorVector.x * scalar * strokeUniformScalar.x,\n            bisectorVector.y * scalar * strokeUniformScalar.y\n          );\n          if (Math.hypot(miterVector.x, miterVector.y) / s <= options.strokeMiterLimit) {\n            coords.push(A.add(miterVector));\n            coords.push(A.subtract(miterVector));\n            return;\n          }\n        }\n        scalar = -s * Math.SQRT2;\n        miterVector = new fabric.Point(\n          bisectorVector.x * scalar * strokeUniformScalar.x,\n          bisectorVector.y * scalar * strokeUniformScalar.y\n        );\n        coords.push(A.add(miterVector));\n        coords.push(A.subtract(miterVector));\n      });\n      return coords;\n    },\n\n    /**\n     * Apply transform t to point p\n     * @static\n     * @memberOf fabric.util\n     * @param  {fabric.Point} p The point to transform\n     * @param  {Array} t The transform\n     * @param  {Boolean} [ignoreOffset] Indicates that the offset should not be applied\n     * @return {fabric.Point} The transformed point\n     */\n    transformPoint: function(p, t, ignoreOffset) {\n      if (ignoreOffset) {\n        return new fabric.Point(\n          t[0] * p.x + t[2] * p.y,\n          t[1] * p.x + t[3] * p.y\n        );\n      }\n      return new fabric.Point(\n        t[0] * p.x + t[2] * p.y + t[4],\n        t[1] * p.x + t[3] * p.y + t[5]\n      );\n    },\n\n    /**\n     * Returns coordinates of points's bounding rectangle (left, top, width, height)\n     * @param {Array} points 4 points array\n     * @param {Array} [transform] an array of 6 numbers representing a 2x3 transform matrix\n     * @return {Object} Object with left, top, width, height properties\n     */\n    makeBoundingBoxFromPoints: function(points, transform) {\n      if (transform) {\n        for (var i = 0; i < points.length; i++) {\n          points[i] = fabric.util.transformPoint(points[i], transform);\n        }\n      }\n      var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x],\n          minX = fabric.util.array.min(xPoints),\n          maxX = fabric.util.array.max(xPoints),\n          width = maxX - minX,\n          yPoints = [points[0].y, points[1].y, points[2].y, points[3].y],\n          minY = fabric.util.array.min(yPoints),\n          maxY = fabric.util.array.max(yPoints),\n          height = maxY - minY;\n\n      return {\n        left: minX,\n        top: minY,\n        width: width,\n        height: height\n      };\n    },\n\n    /**\n     * Invert transformation t\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} t The transform\n     * @return {Array} The inverted transform\n     */\n    invertTransform: function(t) {\n      var a = 1 / (t[0] * t[3] - t[1] * t[2]),\n          r = [a * t[3], -a * t[1], -a * t[2], a * t[0]],\n          o = fabric.util.transformPoint({ x: t[4], y: t[5] }, r, true);\n      r[4] = -o.x;\n      r[5] = -o.y;\n      return r;\n    },\n\n    /**\n     * A wrapper around Number#toFixed, which contrary to native method returns number, not string.\n     * @static\n     * @memberOf fabric.util\n     * @param {Number|String} number number to operate on\n     * @param {Number} fractionDigits number of fraction digits to \"leave\"\n     * @return {Number}\n     */\n    toFixed: function(number, fractionDigits) {\n      return parseFloat(Number(number).toFixed(fractionDigits));\n    },\n\n    /**\n     * Converts from attribute value to pixel value if applicable.\n     * Returns converted pixels or original value not converted.\n     * @param {Number|String} value number to operate on\n     * @param {Number} fontSize\n     * @return {Number|String}\n     */\n    parseUnit: function(value, fontSize) {\n      var unit = /\\D{0,2}$/.exec(value),\n          number = parseFloat(value);\n      if (!fontSize) {\n        fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;\n      }\n      switch (unit[0]) {\n        case 'mm':\n          return number * fabric.DPI / 25.4;\n\n        case 'cm':\n          return number * fabric.DPI / 2.54;\n\n        case 'in':\n          return number * fabric.DPI;\n\n        case 'pt':\n          return number * fabric.DPI / 72; // or * 4 / 3\n\n        case 'pc':\n          return number * fabric.DPI / 72 * 12; // or * 16\n\n        case 'em':\n          return number * fontSize;\n\n        default:\n          return number;\n      }\n    },\n\n    /**\n     * Function which always returns `false`.\n     * @static\n     * @memberOf fabric.util\n     * @return {Boolean}\n     */\n    falseFunction: function() {\n      return false;\n    },\n\n    /**\n     * Returns klass \"Class\" object of given namespace\n     * @memberOf fabric.util\n     * @param {String} type Type of object (eg. 'circle')\n     * @param {String} namespace Namespace to get klass \"Class\" object from\n     * @return {Object} klass \"Class\"\n     */\n    getKlass: function(type, namespace) {\n      // capitalize first letter only\n      type = fabric.util.string.camelize(type.charAt(0).toUpperCase() + type.slice(1));\n      return fabric.util.resolveNamespace(namespace)[type];\n    },\n\n    /**\n     * Returns array of attributes for given svg that fabric parses\n     * @memberOf fabric.util\n     * @param {String} type Type of svg element (eg. 'circle')\n     * @return {Array} string names of supported attributes\n     */\n    getSvgAttributes: function(type) {\n      var attributes = [\n        'instantiated_by_use',\n        'style',\n        'id',\n        'class'\n      ];\n      switch (type) {\n        case 'linearGradient':\n          attributes = attributes.concat(['x1', 'y1', 'x2', 'y2', 'gradientUnits', 'gradientTransform']);\n          break;\n        case 'radialGradient':\n          attributes = attributes.concat(['gradientUnits', 'gradientTransform', 'cx', 'cy', 'r', 'fx', 'fy', 'fr']);\n          break;\n        case 'stop':\n          attributes = attributes.concat(['offset', 'stop-color', 'stop-opacity']);\n          break;\n      }\n      return attributes;\n    },\n\n    /**\n     * Returns object of given namespace\n     * @memberOf fabric.util\n     * @param {String} namespace Namespace string e.g. 'fabric.Image.filter' or 'fabric'\n     * @return {Object} Object for given namespace (default fabric)\n     */\n    resolveNamespace: function(namespace) {\n      if (!namespace) {\n        return fabric;\n      }\n\n      var parts = namespace.split('.'),\n          len = parts.length, i,\n          obj = global || fabric.window;\n\n      for (i = 0; i < len; ++i) {\n        obj = obj[parts[i]];\n      }\n\n      return obj;\n    },\n\n    /**\n     * Loads image element from given url and passes it to a callback\n     * @memberOf fabric.util\n     * @param {String} url URL representing an image\n     * @param {Function} callback Callback; invoked with loaded image\n     * @param {*} [context] Context to invoke callback in\n     * @param {Object} [crossOrigin] crossOrigin value to set image element to\n     */\n    loadImage: function(url, callback, context, crossOrigin) {\n      if (!url) {\n        callback && callback.call(context, url);\n        return;\n      }\n\n      var img = fabric.util.createImage();\n\n      /** @ignore */\n      var onLoadCallback = function () {\n        callback && callback.call(context, img, false);\n        img = img.onload = img.onerror = null;\n      };\n\n      img.onload = onLoadCallback;\n      /** @ignore */\n      img.onerror = function() {\n        fabric.log('Error loading ' + img.src);\n        callback && callback.call(context, null, true);\n        img = img.onload = img.onerror = null;\n      };\n\n      // data-urls appear to be buggy with crossOrigin\n      // https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767\n      // see https://code.google.com/p/chromium/issues/detail?id=315152\n      //     https://bugzilla.mozilla.org/show_bug.cgi?id=935069\n      // crossOrigin null is the same as not set.\n      if (url.indexOf('data') !== 0 &&\n        crossOrigin !== undefined &&\n        crossOrigin !== null) {\n        img.crossOrigin = crossOrigin;\n      }\n\n      // IE10 / IE11-Fix: SVG contents from data: URI\n      // will only be available if the IMG is present\n      // in the DOM (and visible)\n      if (url.substring(0,14) === 'data:image/svg') {\n        img.onload = null;\n        fabric.util.loadImageInDom(img, onLoadCallback);\n      }\n\n      img.src = url;\n    },\n\n    /**\n     * Attaches SVG image with data: URL to the dom\n     * @memberOf fabric.util\n     * @param {Object} img Image object with data:image/svg src\n     * @param {Function} callback Callback; invoked with loaded image\n     * @return {Object} DOM element (div containing the SVG image)\n     */\n    loadImageInDom: function(img, onLoadCallback) {\n      var div = fabric.document.createElement('div');\n      div.style.width = div.style.height = '1px';\n      div.style.left = div.style.top = '-100%';\n      div.style.position = 'absolute';\n      div.appendChild(img);\n      fabric.document.querySelector('body').appendChild(div);\n      /**\n       * Wrap in function to:\n       *   1. Call existing callback\n       *   2. Cleanup DOM\n       */\n      img.onload = function () {\n        onLoadCallback();\n        div.parentNode.removeChild(div);\n        div = null;\n      };\n    },\n\n    /**\n     * Creates corresponding fabric instances from their object representations\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} objects Objects to enliven\n     * @param {Function} callback Callback to invoke when all objects are created\n     * @param {String} namespace Namespace to get klass \"Class\" object from\n     * @param {Function} reviver Method for further parsing of object elements,\n     * called after each fabric object created.\n     */\n    enlivenObjects: function(objects, callback, namespace, reviver) {\n      objects = objects || [];\n\n      var enlivenedObjects = [],\n          numLoadedObjects = 0,\n          numTotalObjects = objects.length;\n\n      function onLoaded() {\n        if (++numLoadedObjects === numTotalObjects) {\n          callback && callback(enlivenedObjects.filter(function(obj) {\n            // filter out undefined objects (objects that gave error)\n            return obj;\n          }));\n        }\n      }\n\n      if (!numTotalObjects) {\n        callback && callback(enlivenedObjects);\n        return;\n      }\n\n      objects.forEach(function (o, index) {\n        // if sparse array\n        if (!o || !o.type) {\n          onLoaded();\n          return;\n        }\n        var klass = fabric.util.getKlass(o.type, namespace);\n        klass.fromObject(o, function (obj, error) {\n          error || (enlivenedObjects[index] = obj);\n          reviver && reviver(o, obj, error);\n          onLoaded();\n        });\n      });\n    },\n\n    /**\n     * Creates corresponding fabric instances residing in an object, e.g. `clipPath`\n     * @see {@link fabric.Object.ENLIVEN_PROPS}\n     * @param {Object} object\n     * @param {Object} [context] assign enlived props to this object (pass null to skip this)\n     * @param {(objects:fabric.Object[]) => void} callback\n     */\n    enlivenObjectEnlivables: function (object, context, callback) {\n      var enlivenProps = fabric.Object.ENLIVEN_PROPS.filter(function (key) { return !!object[key]; });\n      fabric.util.enlivenObjects(enlivenProps.map(function (key) { return object[key]; }), function (enlivedProps) {\n        var objects = {};\n        enlivenProps.forEach(function (key, index) {\n          objects[key] = enlivedProps[index];\n          context && (context[key] = enlivedProps[index]);\n        });\n        callback && callback(objects);\n      });\n    },\n\n    /**\n     * Create and wait for loading of patterns\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} patterns Objects to enliven\n     * @param {Function} callback Callback to invoke when all objects are created\n     * called after each fabric object created.\n     */\n    enlivenPatterns: function(patterns, callback) {\n      patterns = patterns || [];\n\n      function onLoaded() {\n        if (++numLoadedPatterns === numPatterns) {\n          callback && callback(enlivenedPatterns);\n        }\n      }\n\n      var enlivenedPatterns = [],\n          numLoadedPatterns = 0,\n          numPatterns = patterns.length;\n\n      if (!numPatterns) {\n        callback && callback(enlivenedPatterns);\n        return;\n      }\n\n      patterns.forEach(function (p, index) {\n        if (p && p.source) {\n          new fabric.Pattern(p, function(pattern) {\n            enlivenedPatterns[index] = pattern;\n            onLoaded();\n          });\n        }\n        else {\n          enlivenedPatterns[index] = p;\n          onLoaded();\n        }\n      });\n    },\n\n    /**\n     * Groups SVG elements (usually those retrieved from SVG document)\n     * @static\n     * @memberOf fabric.util\n     * @param {Array} elements SVG elements to group\n     * @param {Object} [options] Options object\n     * @param {String} path Value to set sourcePath to\n     * @return {fabric.Object|fabric.Group}\n     */\n    groupSVGElements: function(elements, options, path) {\n      var object;\n      if (elements && elements.length === 1) {\n        if (typeof path !== 'undefined') {\n          elements[0].sourcePath = path;\n        }\n        return elements[0];\n      }\n      if (options) {\n        if (options.width && options.height) {\n          options.centerPoint = {\n            x: options.width / 2,\n            y: options.height / 2\n          };\n        }\n        else {\n          delete options.width;\n          delete options.height;\n        }\n      }\n      object = new fabric.Group(elements, options);\n      if (typeof path !== 'undefined') {\n        object.sourcePath = path;\n      }\n      return object;\n    },\n\n    /**\n     * Populates an object with properties of another object\n     * @static\n     * @memberOf fabric.util\n     * @param {Object} source Source object\n     * @param {Object} destination Destination object\n     * @return {Array} properties Properties names to include\n     */\n    populateWithProperties: function(source, destination, properties) {\n      if (properties && Array.isArray(properties)) {\n        for (var i = 0, len = properties.length; i < len; i++) {\n          if (properties[i] in source) {\n            destination[properties[i]] = source[properties[i]];\n          }\n        }\n      }\n    },\n\n    /**\n     * Creates canvas element\n     * @static\n     * @memberOf fabric.util\n     * @return {CanvasElement} initialized canvas element\n     */\n    createCanvasElement: function() {\n      return fabric.document.createElement('canvas');\n    },\n\n    /**\n     * Creates a canvas element that is a copy of another and is also painted\n     * @param {CanvasElement} canvas to copy size and content of\n     * @static\n     * @memberOf fabric.util\n     * @return {CanvasElement} initialized canvas element\n     */\n    copyCanvasElement: function(canvas) {\n      var newCanvas = fabric.util.createCanvasElement();\n      newCanvas.width = canvas.width;\n      newCanvas.height = canvas.height;\n      newCanvas.getContext('2d').drawImage(canvas, 0, 0);\n      return newCanvas;\n    },\n\n    /**\n     * since 2.6.0 moved from canvas instance to utility.\n     * @param {CanvasElement} canvasEl to copy size and content of\n     * @param {String} format 'jpeg' or 'png', in some browsers 'webp' is ok too\n     * @param {Number} quality <= 1 and > 0\n     * @static\n     * @memberOf fabric.util\n     * @return {String} data url\n     */\n    toDataURL: function(canvasEl, format, quality) {\n      return canvasEl.toDataURL('image/' + format, quality);\n    },\n\n    /**\n     * Creates image element (works on client and node)\n     * @static\n     * @memberOf fabric.util\n     * @return {HTMLImageElement} HTML image element\n     */\n    createImage: function() {\n      return fabric.document.createElement('img');\n    },\n\n    /**\n     * Multiply matrix A by matrix B to nest transformations\n     * @static\n     * @memberOf fabric.util\n     * @param  {Array} a First transformMatrix\n     * @param  {Array} b Second transformMatrix\n     * @param  {Boolean} is2x2 flag to multiply matrices as 2x2 matrices\n     * @return {Array} The product of the two transform matrices\n     */\n    multiplyTransformMatrices: function(a, b, is2x2) {\n      // Matrix multiply a * b\n      return [\n        a[0] * b[0] + a[2] * b[1],\n        a[1] * b[0] + a[3] * b[1],\n        a[0] * b[2] + a[2] * b[3],\n        a[1] * b[2] + a[3] * b[3],\n        is2x2 ? 0 : a[0] * b[4] + a[2] * b[5] + a[4],\n        is2x2 ? 0 : a[1] * b[4] + a[3] * b[5] + a[5]\n      ];\n    },\n\n    /**\n     * Decomposes standard 2x3 matrix into transform components\n     * @static\n     * @memberOf fabric.util\n     * @param  {Array} a transformMatrix\n     * @return {Object} Components of transform\n     */\n    qrDecompose: function(a) {\n      var angle = atan2(a[1], a[0]),\n          denom = pow(a[0], 2) + pow(a[1], 2),\n          scaleX = sqrt(denom),\n          scaleY = (a[0] * a[3] - a[2] * a[1]) / scaleX,\n          skewX = atan2(a[0] * a[2] + a[1] * a [3], denom);\n      return {\n        angle: angle / PiBy180,\n        scaleX: scaleX,\n        scaleY: scaleY,\n        skewX: skewX / PiBy180,\n        skewY: 0,\n        translateX: a[4],\n        translateY: a[5]\n      };\n    },\n\n    /**\n     * Returns a transform matrix starting from an object of the same kind of\n     * the one returned from qrDecompose, useful also if you want to calculate some\n     * transformations from an object that is not enlived yet\n     * @static\n     * @memberOf fabric.util\n     * @param  {Object} options\n     * @param  {Number} [options.angle] angle in degrees\n     * @return {Number[]} transform matrix\n     */\n    calcRotateMatrix: function(options) {\n      if (!options.angle) {\n        return fabric.iMatrix.concat();\n      }\n      var theta = fabric.util.degreesToRadians(options.angle),\n          cos = fabric.util.cos(theta),\n          sin = fabric.util.sin(theta);\n      return [cos, sin, -sin, cos, 0, 0];\n    },\n\n    /**\n     * Returns a transform matrix starting from an object of the same kind of\n     * the one returned from qrDecompose, useful also if you want to calculate some\n     * transformations from an object that is not enlived yet.\n     * is called DimensionsTransformMatrix because those properties are the one that influence\n     * the size of the resulting box of the object.\n     * @static\n     * @memberOf fabric.util\n     * @param  {Object} options\n     * @param  {Number} [options.scaleX]\n     * @param  {Number} [options.scaleY]\n     * @param  {Boolean} [options.flipX]\n     * @param  {Boolean} [options.flipY]\n     * @param  {Number} [options.skewX]\n     * @param  {Number} [options.skewY]\n     * @return {Number[]} transform matrix\n     */\n    calcDimensionsMatrix: function(options) {\n      var scaleX = typeof options.scaleX === 'undefined' ? 1 : options.scaleX,\n          scaleY = typeof options.scaleY === 'undefined' ? 1 : options.scaleY,\n          scaleMatrix = [\n            options.flipX ? -scaleX : scaleX,\n            0,\n            0,\n            options.flipY ? -scaleY : scaleY,\n            0,\n            0],\n          multiply = fabric.util.multiplyTransformMatrices,\n          degreesToRadians = fabric.util.degreesToRadians;\n      if (options.skewX) {\n        scaleMatrix = multiply(\n          scaleMatrix,\n          [1, 0, Math.tan(degreesToRadians(options.skewX)), 1],\n          true);\n      }\n      if (options.skewY) {\n        scaleMatrix = multiply(\n          scaleMatrix,\n          [1, Math.tan(degreesToRadians(options.skewY)), 0, 1],\n          true);\n      }\n      return scaleMatrix;\n    },\n\n    /**\n     * Returns a transform matrix starting from an object of the same kind of\n     * the one returned from qrDecompose, useful also if you want to calculate some\n     * transformations from an object that is not enlived yet\n     * @static\n     * @memberOf fabric.util\n     * @param  {Object} options\n     * @param  {Number} [options.angle]\n     * @param  {Number} [options.scaleX]\n     * @param  {Number} [options.scaleY]\n     * @param  {Boolean} [options.flipX]\n     * @param  {Boolean} [options.flipY]\n     * @param  {Number} [options.skewX]\n     * @param  {Number} [options.skewX]\n     * @param  {Number} [options.translateX]\n     * @param  {Number} [options.translateY]\n     * @return {Number[]} transform matrix\n     */\n    composeMatrix: function(options) {\n      var matrix = [1, 0, 0, 1, options.translateX || 0, options.translateY || 0],\n          multiply = fabric.util.multiplyTransformMatrices;\n      if (options.angle) {\n        matrix = multiply(matrix, fabric.util.calcRotateMatrix(options));\n      }\n      if (options.scaleX !== 1 || options.scaleY !== 1 ||\n          options.skewX || options.skewY || options.flipX || options.flipY) {\n        matrix = multiply(matrix, fabric.util.calcDimensionsMatrix(options));\n      }\n      return matrix;\n    },\n\n    /**\n     * reset an object transform state to neutral. Top and left are not accounted for\n     * @static\n     * @memberOf fabric.util\n     * @param  {fabric.Object} target object to transform\n     */\n    resetObjectTransform: function (target) {\n      target.scaleX = 1;\n      target.scaleY = 1;\n      target.skewX = 0;\n      target.skewY = 0;\n      target.flipX = false;\n      target.flipY = false;\n      target.rotate(0);\n    },\n\n    /**\n     * Extract Object transform values\n     * @static\n     * @memberOf fabric.util\n     * @param  {fabric.Object} target object to read from\n     * @return {Object} Components of transform\n     */\n    saveObjectTransform: function (target) {\n      return {\n        scaleX: target.scaleX,\n        scaleY: target.scaleY,\n        skewX: target.skewX,\n        skewY: target.skewY,\n        angle: target.angle,\n        left: target.left,\n        flipX: target.flipX,\n        flipY: target.flipY,\n        top: target.top\n      };\n    },\n\n    /**\n     * Returns true if context has transparent pixel\n     * at specified location (taking tolerance into account)\n     * @param {CanvasRenderingContext2D} ctx context\n     * @param {Number} x x coordinate\n     * @param {Number} y y coordinate\n     * @param {Number} tolerance Tolerance\n     */\n    isTransparent: function(ctx, x, y, tolerance) {\n\n      // If tolerance is > 0 adjust start coords to take into account.\n      // If moves off Canvas fix to 0\n      if (tolerance > 0) {\n        if (x > tolerance) {\n          x -= tolerance;\n        }\n        else {\n          x = 0;\n        }\n        if (y > tolerance) {\n          y -= tolerance;\n        }\n        else {\n          y = 0;\n        }\n      }\n\n      var _isTransparent = true, i, temp,\n          imageData = ctx.getImageData(x, y, (tolerance * 2) || 1, (tolerance * 2) || 1),\n          l = imageData.data.length;\n\n      // Split image data - for tolerance > 1, pixelDataSize = 4;\n      for (i = 3; i < l; i += 4) {\n        temp = imageData.data[i];\n        _isTransparent = temp <= 0;\n        if (_isTransparent === false) {\n          break; // Stop if colour found\n        }\n      }\n\n      imageData = null;\n\n      return _isTransparent;\n    },\n\n    /**\n     * Parse preserveAspectRatio attribute from element\n     * @param {string} attribute to be parsed\n     * @return {Object} an object containing align and meetOrSlice attribute\n     */\n    parsePreserveAspectRatioAttribute: function(attribute) {\n      var meetOrSlice = 'meet', alignX = 'Mid', alignY = 'Mid',\n          aspectRatioAttrs = attribute.split(' '), align;\n\n      if (aspectRatioAttrs && aspectRatioAttrs.length) {\n        meetOrSlice = aspectRatioAttrs.pop();\n        if (meetOrSlice !== 'meet' && meetOrSlice !== 'slice') {\n          align = meetOrSlice;\n          meetOrSlice = 'meet';\n        }\n        else if (aspectRatioAttrs.length) {\n          align = aspectRatioAttrs.pop();\n        }\n      }\n      //divide align in alignX and alignY\n      alignX = align !== 'none' ? align.slice(1, 4) : 'none';\n      alignY = align !== 'none' ? align.slice(5, 8) : 'none';\n      return {\n        meetOrSlice: meetOrSlice,\n        alignX: alignX,\n        alignY: alignY\n      };\n    },\n\n    /**\n     * Clear char widths cache for the given font family or all the cache if no\n     * fontFamily is specified.\n     * Use it if you know you are loading fonts in a lazy way and you are not waiting\n     * for custom fonts to load properly when adding text objects to the canvas.\n     * If a text object is added when its own font is not loaded yet, you will get wrong\n     * measurement and so wrong bounding boxes.\n     * After the font cache is cleared, either change the textObject text content or call\n     * initDimensions() to trigger a recalculation\n     * @memberOf fabric.util\n     * @param {String} [fontFamily] font family to clear\n     */\n    clearFabricFontCache: function(fontFamily) {\n      fontFamily = (fontFamily || '').toLowerCase();\n      if (!fontFamily) {\n        fabric.charWidthsCache = { };\n      }\n      else if (fabric.charWidthsCache[fontFamily]) {\n        delete fabric.charWidthsCache[fontFamily];\n      }\n    },\n\n    /**\n     * Given current aspect ratio, determines the max width and height that can\n     * respect the total allowed area for the cache.\n     * @memberOf fabric.util\n     * @param {Number} ar aspect ratio\n     * @param {Number} maximumArea Maximum area you want to achieve\n     * @return {Object.x} Limited dimensions by X\n     * @return {Object.y} Limited dimensions by Y\n     */\n    limitDimsByArea: function(ar, maximumArea) {\n      var roughWidth = Math.sqrt(maximumArea * ar),\n          perfLimitSizeY = Math.floor(maximumArea / roughWidth);\n      return { x: Math.floor(roughWidth), y: perfLimitSizeY };\n    },\n\n    capValue: function(min, value, max) {\n      return Math.max(min, Math.min(value, max));\n    },\n\n    /**\n     * Finds the scale for the object source to fit inside the object destination,\n     * keeping aspect ratio intact.\n     * respect the total allowed area for the cache.\n     * @memberOf fabric.util\n     * @param {Object | fabric.Object} source\n     * @param {Number} source.height natural unscaled height of the object\n     * @param {Number} source.width natural unscaled width of the object\n     * @param {Object | fabric.Object} destination\n     * @param {Number} destination.height natural unscaled height of the object\n     * @param {Number} destination.width natural unscaled width of the object\n     * @return {Number} scale factor to apply to source to fit into destination\n     */\n    findScaleToFit: function(source, destination) {\n      return Math.min(destination.width / source.width, destination.height / source.height);\n    },\n\n    /**\n     * Finds the scale for the object source to cover entirely the object destination,\n     * keeping aspect ratio intact.\n     * respect the total allowed area for the cache.\n     * @memberOf fabric.util\n     * @param {Object | fabric.Object} source\n     * @param {Number} source.height natural unscaled height of the object\n     * @param {Number} source.width natural unscaled width of the object\n     * @param {Object | fabric.Object} destination\n     * @param {Number} destination.height natural unscaled height of the object\n     * @param {Number} destination.width natural unscaled width of the object\n     * @return {Number} scale factor to apply to source to cover destination\n     */\n    findScaleToCover: function(source, destination) {\n      return Math.max(destination.width / source.width, destination.height / source.height);\n    },\n\n    /**\n     * given an array of 6 number returns something like `\"matrix(...numbers)\"`\n     * @memberOf fabric.util\n     * @param {Array} transform an array with 6 numbers\n     * @return {String} transform matrix for svg\n     * @return {Object.y} Limited dimensions by Y\n     */\n    matrixToSVG: function(transform) {\n      return 'matrix(' + transform.map(function(value) {\n        return fabric.util.toFixed(value, fabric.Object.NUM_FRACTION_DIGITS);\n      }).join(' ') + ')';\n    },\n\n    /**\n     * given an object and a transform, apply the inverse transform to the object,\n     * this is equivalent to remove from that object that transformation, so that\n     * added in a space with the removed transform, the object will be the same as before.\n     * Removing from an object a transform that scale by 2 is like scaling it by 1/2.\n     * Removing from an object a transfrom that rotate by 30deg is like rotating by 30deg\n     * in the opposite direction.\n     * This util is used to add objects inside transformed groups or nested groups.\n     * @memberOf fabric.util\n     * @param {fabric.Object} object the object you want to transform\n     * @param {Array} transform the destination transform\n     */\n    removeTransformFromObject: function(object, transform) {\n      var inverted = fabric.util.invertTransform(transform),\n          finalTransform = fabric.util.multiplyTransformMatrices(inverted, object.calcOwnMatrix());\n      fabric.util.applyTransformToObject(object, finalTransform);\n    },\n\n    /**\n     * given an object and a transform, apply the transform to the object.\n     * this is equivalent to change the space where the object is drawn.\n     * Adding to an object a transform that scale by 2 is like scaling it by 2.\n     * This is used when removing an object from an active selection for example.\n     * @memberOf fabric.util\n     * @param {fabric.Object} object the object you want to transform\n     * @param {Array} transform the destination transform\n     */\n    addTransformToObject: function(object, transform) {\n      fabric.util.applyTransformToObject(\n        object,\n        fabric.util.multiplyTransformMatrices(transform, object.calcOwnMatrix())\n      );\n    },\n\n    /**\n     * discard an object transform state and apply the one from the matrix.\n     * @memberOf fabric.util\n     * @param {fabric.Object} object the object you want to transform\n     * @param {Array} transform the destination transform\n     */\n    applyTransformToObject: function(object, transform) {\n      var options = fabric.util.qrDecompose(transform),\n          center = new fabric.Point(options.translateX, options.translateY);\n      object.flipX = false;\n      object.flipY = false;\n      object.set('scaleX', options.scaleX);\n      object.set('scaleY', options.scaleY);\n      object.skewX = options.skewX;\n      object.skewY = options.skewY;\n      object.angle = options.angle;\n      object.setPositionByOrigin(center, 'center', 'center');\n    },\n\n    /**\n     * given a width and height, return the size of the bounding box\n     * that can contains the box with width/height with applied transform\n     * described in options.\n     * Use to calculate the boxes around objects for controls.\n     * @memberOf fabric.util\n     * @param {Number} width\n     * @param {Number} height\n     * @param {Object} options\n     * @param {Number} options.scaleX\n     * @param {Number} options.scaleY\n     * @param {Number} options.skewX\n     * @param {Number} options.skewY\n     * @return {Object.x} width of containing\n     * @return {Object.y} height of containing\n     */\n    sizeAfterTransform: function(width, height, options) {\n      var dimX = width / 2, dimY = height / 2,\n          points = [\n            {\n              x: -dimX,\n              y: -dimY\n            },\n            {\n              x: dimX,\n              y: -dimY\n            },\n            {\n              x: -dimX,\n              y: dimY\n            },\n            {\n              x: dimX,\n              y: dimY\n            }],\n          transformMatrix = fabric.util.calcDimensionsMatrix(options),\n          bbox = fabric.util.makeBoundingBoxFromPoints(points, transformMatrix);\n      return {\n        x: bbox.width,\n        y: bbox.height,\n      };\n    },\n\n    /**\n     * Merges 2 clip paths into one visually equal clip path\n     *\n     * **IMPORTANT**:\\\n     * Does **NOT** clone the arguments, clone them proir if necessary.\n     *\n     * Creates a wrapper (group) that contains one clip path and is clipped by the other so content is kept where both overlap.\n     * Use this method if both the clip paths may have nested clip paths of their own, so assigning one to the other's clip path property is not possible.\n     *\n     * In order to handle the `inverted` property we follow logic described in the following cases:\\\n     * **(1)** both clip paths are inverted - the clip paths pass the inverted prop to the wrapper and loose it themselves.\\\n     * **(2)** one is inverted and the other isn't - the wrapper shouldn't become inverted and the inverted clip path must clip the non inverted one to produce an identical visual effect.\\\n     * **(3)** both clip paths are not inverted - wrapper and clip paths remain unchanged.\n     *\n     * @memberOf fabric.util\n     * @param {fabric.Object} c1\n     * @param {fabric.Object} c2\n     * @returns {fabric.Object} merged clip path\n     */\n    mergeClipPaths: function (c1, c2) {\n      var a = c1, b = c2;\n      if (a.inverted && !b.inverted) {\n        //  case (2)\n        a = c2;\n        b = c1;\n      }\n      //  `b` becomes `a`'s clip path so we transform `b` to `a` coordinate plane\n      fabric.util.applyTransformToObject(\n        b,\n        fabric.util.multiplyTransformMatrices(\n          fabric.util.invertTransform(a.calcTransformMatrix()),\n          b.calcTransformMatrix()\n        )\n      );\n      //  assign the `inverted` prop to the wrapping group\n      var inverted = a.inverted && b.inverted;\n      if (inverted) {\n        //  case (1)\n        a.inverted = b.inverted = false;\n      }\n      return new fabric.Group([a], { clipPath: b, inverted: inverted });\n    },\n\n    /**\n     * @memberOf fabric.util\n     * @param {Object} prevStyle first style to compare\n     * @param {Object} thisStyle second style to compare\n     * @param {boolean} forTextSpans whether to check overline, underline, and line-through properties\n     * @return {boolean} true if the style changed\n     */\n    hasStyleChanged: function(prevStyle, thisStyle, forTextSpans) {\n      forTextSpans = forTextSpans || false;\n      return (prevStyle.fill !== thisStyle.fill ||\n              prevStyle.stroke !== thisStyle.stroke ||\n              prevStyle.strokeWidth !== thisStyle.strokeWidth ||\n              prevStyle.fontSize !== thisStyle.fontSize ||\n              prevStyle.fontFamily !== thisStyle.fontFamily ||\n              prevStyle.fontWeight !== thisStyle.fontWeight ||\n              prevStyle.fontStyle !== thisStyle.fontStyle ||\n              prevStyle.textBackgroundColor !== thisStyle.textBackgroundColor ||\n              prevStyle.deltaY !== thisStyle.deltaY) ||\n              (forTextSpans &&\n                (prevStyle.overline !== thisStyle.overline ||\n                prevStyle.underline !== thisStyle.underline ||\n                prevStyle.linethrough !== thisStyle.linethrough));\n    },\n\n    /**\n     * Returns the array form of a text object's inline styles property with styles grouped in ranges\n     * rather than per character. This format is less verbose, and is better suited for storage\n     * so it is used in serialization (not during runtime).\n     * @memberOf fabric.util\n     * @param {object} styles per character styles for a text object\n     * @param {String} text the text string that the styles are applied to\n     * @return {{start: number, end: number, style: object}[]}\n     */\n    stylesToArray: function(styles, text) {\n      // clone style structure to prevent mutation\n      var styles = fabric.util.object.clone(styles, true),\n          textLines = text.split('\\n'),\n          charIndex = -1, prevStyle = {}, stylesArray = [];\n      //loop through each textLine\n      for (var i = 0; i < textLines.length; i++) {\n        if (!styles[i]) {\n          //no styles exist for this line, so add the line's length to the charIndex total\n          charIndex += textLines[i].length;\n          continue;\n        }\n        //loop through each character of the current line\n        for (var c = 0; c < textLines[i].length; c++) {\n          charIndex++;\n          var thisStyle = styles[i][c];\n          //check if style exists for this character\n          if (thisStyle && Object.keys(thisStyle).length > 0) {\n            var styleChanged = fabric.util.hasStyleChanged(prevStyle, thisStyle, true);\n            if (styleChanged) {\n              stylesArray.push({\n                start: charIndex,\n                end: charIndex + 1,\n                style: thisStyle\n              });\n            }\n            else {\n              //if style is the same as previous character, increase end index\n              stylesArray[stylesArray.length - 1].end++;\n            }\n          }\n          prevStyle = thisStyle || {};\n        }\n      }\n      return stylesArray;\n    },\n\n    /**\n     * Returns the object form of the styles property with styles that are assigned per\n     * character rather than grouped by range. This format is more verbose, and is\n     * only used during runtime (not for serialization/storage)\n     * @memberOf fabric.util\n     * @param {Array} styles the serialized form of a text object's styles\n     * @param {String} text the text string that the styles are applied to\n     * @return {Object}\n     */\n    stylesFromArray: function(styles, text) {\n      if (!Array.isArray(styles)) {\n        return styles;\n      }\n      var textLines = text.split('\\n'),\n          charIndex = -1, styleIndex = 0, stylesObject = {};\n      //loop through each textLine\n      for (var i = 0; i < textLines.length; i++) {\n        //loop through each character of the current line\n        for (var c = 0; c < textLines[i].length; c++) {\n          charIndex++;\n          //check if there's a style collection that includes the current character\n          if (styles[styleIndex]\n            && styles[styleIndex].start <= charIndex\n            && charIndex < styles[styleIndex].end) {\n            //create object for line index if it doesn't exist\n            stylesObject[i] = stylesObject[i] || {};\n            //assign a style at this character's index\n            stylesObject[i][c] = Object.assign({}, styles[styleIndex].style);\n            //if character is at the end of the current style collection, move to the next\n            if (charIndex === styles[styleIndex].end - 1) {\n              styleIndex++;\n            }\n          }\n        }\n      }\n      return stylesObject;\n    }\n  };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n  var _join = Array.prototype.join,\n      commandLengths = {\n        m: 2,\n        l: 2,\n        h: 1,\n        v: 1,\n        c: 6,\n        s: 4,\n        q: 4,\n        t: 2,\n        a: 7\n      },\n      repeatedCommands = {\n        m: 'l',\n        M: 'L'\n      };\n  function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) {\n    var costh2 = fabric.util.cos(th2),\n        sinth2 = fabric.util.sin(th2),\n        costh3 = fabric.util.cos(th3),\n        sinth3 = fabric.util.sin(th3),\n        toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1,\n        toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1,\n        cp1X = fromX + mT * ( -cosTh * rx * sinth2 - sinTh * ry * costh2),\n        cp1Y = fromY + mT * ( -sinTh * rx * sinth2 + cosTh * ry * costh2),\n        cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3),\n        cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3);\n\n    return ['C',\n      cp1X, cp1Y,\n      cp2X, cp2Y,\n      toX, toY\n    ];\n  }\n\n  /* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp\n   * by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here\n   * http://mozilla.org/MPL/2.0/\n   */\n  function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) {\n    var PI = Math.PI, th = rotateX * PI / 180,\n        sinTh = fabric.util.sin(th),\n        cosTh = fabric.util.cos(th),\n        fromX = 0, fromY = 0;\n\n    rx = Math.abs(rx);\n    ry = Math.abs(ry);\n\n    var px = -cosTh * toX * 0.5 - sinTh * toY * 0.5,\n        py = -cosTh * toY * 0.5 + sinTh * toX * 0.5,\n        rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px,\n        pl = rx2 * ry2 - rx2 * py2 - ry2 * px2,\n        root = 0;\n\n    if (pl < 0) {\n      var s = Math.sqrt(1 - pl / (rx2 * ry2));\n      rx *= s;\n      ry *= s;\n    }\n    else {\n      root = (large === sweep ? -1.0 : 1.0) *\n              Math.sqrt( pl / (rx2 * py2 + ry2 * px2));\n    }\n\n    var cx = root * rx * py / ry,\n        cy = -root * ry * px / rx,\n        cx1 = cosTh * cx - sinTh * cy + toX * 0.5,\n        cy1 = sinTh * cx + cosTh * cy + toY * 0.5,\n        mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry),\n        dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px - cx) / rx, (-py - cy) / ry);\n\n    if (sweep === 0 && dtheta > 0) {\n      dtheta -= 2 * PI;\n    }\n    else if (sweep === 1 && dtheta < 0) {\n      dtheta += 2 * PI;\n    }\n\n    // Convert into cubic bezier segments <= 90deg\n    var segments = Math.ceil(Math.abs(dtheta / PI * 2)),\n        result = [], mDelta = dtheta / segments,\n        mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2),\n        th3 = mTheta + mDelta;\n\n    for (var i = 0; i < segments; i++) {\n      result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY);\n      fromX = result[i][5];\n      fromY = result[i][6];\n      mTheta = th3;\n      th3 += mDelta;\n    }\n    return result;\n  }\n\n  /*\n   * Private\n   */\n  function calcVectorAngle(ux, uy, vx, vy) {\n    var ta = Math.atan2(uy, ux),\n        tb = Math.atan2(vy, vx);\n    if (tb >= ta) {\n      return tb - ta;\n    }\n    else {\n      return 2 * Math.PI - (ta - tb);\n    }\n  }\n\n  /**\n   * Calculate bounding box of a beziercurve\n   * @param {Number} x0 starting point\n   * @param {Number} y0\n   * @param {Number} x1 first control point\n   * @param {Number} y1\n   * @param {Number} x2 secondo control point\n   * @param {Number} y2\n   * @param {Number} x3 end of bezier\n   * @param {Number} y3\n   */\n  // taken from http://jsbin.com/ivomiq/56/edit  no credits available for that.\n  // TODO: can we normalize this with the starting points set at 0 and then translated the bbox?\n  function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) {\n    var argsString;\n    if (fabric.cachesBoundsOfCurve) {\n      argsString = _join.call(arguments);\n      if (fabric.boundsOfCurveCache[argsString]) {\n        return fabric.boundsOfCurveCache[argsString];\n      }\n    }\n\n    var sqrt = Math.sqrt,\n        min = Math.min, max = Math.max,\n        abs = Math.abs, tvalues = [],\n        bounds = [[], []],\n        a, b, c, t, t1, t2, b2ac, sqrtb2ac;\n\n    b = 6 * x0 - 12 * x1 + 6 * x2;\n    a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;\n    c = 3 * x1 - 3 * x0;\n\n    for (var i = 0; i < 2; ++i) {\n      if (i > 0) {\n        b = 6 * y0 - 12 * y1 + 6 * y2;\n        a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;\n        c = 3 * y1 - 3 * y0;\n      }\n\n      if (abs(a) < 1e-12) {\n        if (abs(b) < 1e-12) {\n          continue;\n        }\n        t = -c / b;\n        if (0 < t && t < 1) {\n          tvalues.push(t);\n        }\n        continue;\n      }\n      b2ac = b * b - 4 * c * a;\n      if (b2ac < 0) {\n        continue;\n      }\n      sqrtb2ac = sqrt(b2ac);\n      t1 = (-b + sqrtb2ac) / (2 * a);\n      if (0 < t1 && t1 < 1) {\n        tvalues.push(t1);\n      }\n      t2 = (-b - sqrtb2ac) / (2 * a);\n      if (0 < t2 && t2 < 1) {\n        tvalues.push(t2);\n      }\n    }\n\n    var x, y, j = tvalues.length, jlen = j, mt;\n    while (j--) {\n      t = tvalues[j];\n      mt = 1 - t;\n      x = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);\n      bounds[0][j] = x;\n\n      y = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);\n      bounds[1][j] = y;\n    }\n\n    bounds[0][jlen] = x0;\n    bounds[1][jlen] = y0;\n    bounds[0][jlen + 1] = x3;\n    bounds[1][jlen + 1] = y3;\n    var result = [\n      {\n        x: min.apply(null, bounds[0]),\n        y: min.apply(null, bounds[1])\n      },\n      {\n        x: max.apply(null, bounds[0]),\n        y: max.apply(null, bounds[1])\n      }\n    ];\n    if (fabric.cachesBoundsOfCurve) {\n      fabric.boundsOfCurveCache[argsString] = result;\n    }\n    return result;\n  }\n\n  /**\n   * Converts arc to a bunch of bezier curves\n   * @param {Number} fx starting point x\n   * @param {Number} fy starting point y\n   * @param {Array} coords Arc command\n   */\n  function fromArcToBeziers(fx, fy, coords) {\n    var rx = coords[1],\n        ry = coords[2],\n        rot = coords[3],\n        large = coords[4],\n        sweep = coords[5],\n        tx = coords[6],\n        ty = coords[7],\n        segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);\n\n    for (var i = 0, len = segsNorm.length; i < len; i++) {\n      segsNorm[i][1] += fx;\n      segsNorm[i][2] += fy;\n      segsNorm[i][3] += fx;\n      segsNorm[i][4] += fy;\n      segsNorm[i][5] += fx;\n      segsNorm[i][6] += fy;\n    }\n    return segsNorm;\n  };\n\n  /**\n   * This function take a parsed SVG path and make it simpler for fabricJS logic.\n   * simplification consist of: only UPPERCASE absolute commands ( relative converted to absolute )\n   * S converted in C, T converted in Q, A converted in C.\n   * @param {Array} path the array of commands of a parsed svg path for fabric.Path\n   * @return {Array} the simplified array of commands of a parsed svg path for fabric.Path\n   */\n  function makePathSimpler(path) {\n    // x and y represent the last point of the path. the previous command point.\n    // we add them to each relative command to make it an absolute comment.\n    // we also swap the v V h H with L, because are easier to transform.\n    var x = 0, y = 0, len = path.length,\n        // x1 and y1 represent the last point of the subpath. the subpath is started with\n        // m or M command. When a z or Z command is drawn, x and y need to be resetted to\n        // the last x1 and y1.\n        x1 = 0, y1 = 0, current, i, converted,\n        // previous will host the letter of the previous command, to handle S and T.\n        // controlX and controlY will host the previous reflected control point\n        destinationPath = [], previous, controlX, controlY;\n    for (i = 0; i < len; ++i) {\n      converted = false;\n      current = path[i].slice(0);\n      switch (current[0]) { // first letter\n        case 'l': // lineto, relative\n          current[0] = 'L';\n          current[1] += x;\n          current[2] += y;\n          // falls through\n        case 'L':\n          x = current[1];\n          y = current[2];\n          break;\n        case 'h': // horizontal lineto, relative\n          current[1] += x;\n          // falls through\n        case 'H':\n          current[0] = 'L';\n          current[2] = y;\n          x = current[1];\n          break;\n        case 'v': // vertical lineto, relative\n          current[1] += y;\n          // falls through\n        case 'V':\n          current[0] = 'L';\n          y = current[1];\n          current[1] = x;\n          current[2] = y;\n          break;\n        case 'm': // moveTo, relative\n          current[0] = 'M';\n          current[1] += x;\n          current[2] += y;\n          // falls through\n        case 'M':\n          x = current[1];\n          y = current[2];\n          x1 = current[1];\n          y1 = current[2];\n          break;\n        case 'c': // bezierCurveTo, relative\n          current[0] = 'C';\n          current[1] += x;\n          current[2] += y;\n          current[3] += x;\n          current[4] += y;\n          current[5] += x;\n          current[6] += y;\n          // falls through\n        case 'C':\n          controlX = current[3];\n          controlY = current[4];\n          x = current[5];\n          y = current[6];\n          break;\n        case 's': // shorthand cubic bezierCurveTo, relative\n          current[0] = 'S';\n          current[1] += x;\n          current[2] += y;\n          current[3] += x;\n          current[4] += y;\n          // falls through\n        case 'S':\n          // would be sScC but since we are swapping sSc for C, we check just that.\n          if (previous === 'C') {\n            // calculate reflection of previous control points\n            controlX = 2 * x - controlX;\n            controlY = 2 * y - controlY;\n          }\n          else {\n            // If there is no previous command or if the previous command was not a C, c, S, or s,\n            // the control point is coincident with the current point\n            controlX = x;\n            controlY = y;\n          }\n          x = current[3];\n          y = current[4];\n          current[0] = 'C';\n          current[5] = current[3];\n          current[6] = current[4];\n          current[3] = current[1];\n          current[4] = current[2];\n          current[1] = controlX;\n          current[2] = controlY;\n          // current[3] and current[4] are NOW the second control point.\n          // we keep it for the next reflection.\n          controlX = current[3];\n          controlY = current[4];\n          break;\n        case 'q': // quadraticCurveTo, relative\n          current[0] = 'Q';\n          current[1] += x;\n          current[2] += y;\n          current[3] += x;\n          current[4] += y;\n          // falls through\n        case 'Q':\n          controlX = current[1];\n          controlY = current[2];\n          x = current[3];\n          y = current[4];\n          break;\n        case 't': // shorthand quadraticCurveTo, relative\n          current[0] = 'T';\n          current[1] += x;\n          current[2] += y;\n          // falls through\n        case 'T':\n          if (previous === 'Q') {\n            // calculate reflection of previous control point\n            controlX = 2 * x - controlX;\n            controlY = 2 * y - controlY;\n          }\n          else {\n            // If there is no previous command or if the previous command was not a Q, q, T or t,\n            // assume the control point is coincident with the current point\n            controlX = x;\n            controlY = y;\n          }\n          current[0] = 'Q';\n          x = current[1];\n          y = current[2];\n          current[1] = controlX;\n          current[2] = controlY;\n          current[3] = x;\n          current[4] = y;\n          break;\n        case 'a':\n          current[0] = 'A';\n          current[6] += x;\n          current[7] += y;\n          // falls through\n        case 'A':\n          converted = true;\n          destinationPath = destinationPath.concat(fromArcToBeziers(x, y, current));\n          x = current[6];\n          y = current[7];\n          break;\n        case 'z':\n        case 'Z':\n          x = x1;\n          y = y1;\n          break;\n        default:\n      }\n      if (!converted) {\n        destinationPath.push(current);\n      }\n      previous = current[0];\n    }\n    return destinationPath;\n  };\n\n  /**\n   * Calc length from point x1,y1 to x2,y2\n   * @param {Number} x1 starting point x\n   * @param {Number} y1 starting point y\n   * @param {Number} x2 starting point x\n   * @param {Number} y2 starting point y\n   * @return {Number} length of segment\n   */\n  function calcLineLength(x1, y1, x2, y2) {\n    return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n  }\n\n  // functions for the Cubic beizer\n  // taken from: https://github.com/konvajs/konva/blob/7.0.5/src/shapes/Path.ts#L350\n  function CB1(t) {\n    return t * t * t;\n  }\n  function CB2(t) {\n    return 3 * t * t * (1 - t);\n  }\n  function CB3(t) {\n    return 3 * t * (1 - t) * (1 - t);\n  }\n  function CB4(t) {\n    return (1 - t) * (1 - t) * (1 - t);\n  }\n\n  function getPointOnCubicBezierIterator(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) {\n    return function(pct) {\n      var c1 = CB1(pct), c2 = CB2(pct), c3 = CB3(pct), c4 = CB4(pct);\n      return {\n        x: p4x * c1 + p3x * c2 + p2x * c3 + p1x * c4,\n        y: p4y * c1 + p3y * c2 + p2y * c3 + p1y * c4\n      };\n    };\n  }\n\n  function getTangentCubicIterator(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) {\n    return function (pct) {\n      var invT = 1 - pct,\n          tangentX = (3 * invT * invT * (p2x - p1x)) + (6 * invT * pct * (p3x - p2x)) +\n          (3 * pct * pct * (p4x - p3x)),\n          tangentY = (3 * invT * invT * (p2y - p1y)) + (6 * invT * pct * (p3y - p2y)) +\n          (3 * pct * pct * (p4y - p3y));\n      return Math.atan2(tangentY, tangentX);\n    };\n  }\n\n  function QB1(t) {\n    return t * t;\n  }\n\n  function QB2(t) {\n    return 2 * t * (1 - t);\n  }\n\n  function QB3(t) {\n    return (1 - t) * (1 - t);\n  }\n\n  function getPointOnQuadraticBezierIterator(p1x, p1y, p2x, p2y, p3x, p3y) {\n    return function(pct) {\n      var c1 = QB1(pct), c2 = QB2(pct), c3 = QB3(pct);\n      return {\n        x: p3x * c1 + p2x * c2 + p1x * c3,\n        y: p3y * c1 + p2y * c2 + p1y * c3\n      };\n    };\n  }\n\n  function getTangentQuadraticIterator(p1x, p1y, p2x, p2y, p3x, p3y) {\n    return function (pct) {\n      var invT = 1 - pct,\n          tangentX = (2 * invT * (p2x - p1x)) + (2 * pct * (p3x - p2x)),\n          tangentY = (2 * invT * (p2y - p1y)) + (2 * pct * (p3y - p2y));\n      return Math.atan2(tangentY, tangentX);\n    };\n  }\n\n\n  // this will run over a path segment ( a cubic or quadratic segment) and approximate it\n  // with 100 segemnts. This will good enough to calculate the length of the curve\n  function pathIterator(iterator, x1, y1) {\n    var tempP = { x: x1, y: y1 }, p, tmpLen = 0, perc;\n    for (perc = 1; perc <= 100; perc += 1) {\n      p = iterator(perc / 100);\n      tmpLen += calcLineLength(tempP.x, tempP.y, p.x, p.y);\n      tempP = p;\n    }\n    return tmpLen;\n  }\n\n  /**\n   * Given a pathInfo, and a distance in pixels, find the percentage from 0 to 1\n   * that correspond to that pixels run over the path.\n   * The percentage will be then used to find the correct point on the canvas for the path.\n   * @param {Array} segInfo fabricJS collection of information on a parsed path\n   * @param {Number} distance from starting point, in pixels.\n   * @return {Object} info object with x and y ( the point on canvas ) and angle, the tangent on that point;\n   */\n  function findPercentageForDistance(segInfo, distance) {\n    var perc = 0, tmpLen = 0, iterator = segInfo.iterator, tempP = { x: segInfo.x, y: segInfo.y },\n        p, nextLen, nextStep = 0.01, angleFinder = segInfo.angleFinder, lastPerc;\n    // nextStep > 0.0001 covers 0.00015625 that 1/64th of 1/100\n    // the path\n    while (tmpLen < distance && nextStep > 0.0001) {\n      p = iterator(perc);\n      lastPerc = perc;\n      nextLen = calcLineLength(tempP.x, tempP.y, p.x, p.y);\n      // compare tmpLen each cycle with distance, decide next perc to test.\n      if ((nextLen + tmpLen) > distance) {\n        // we discard this step and we make smaller steps.\n        perc -= nextStep;\n        nextStep /= 2;\n      }\n      else {\n        tempP = p;\n        perc += nextStep;\n        tmpLen += nextLen;\n      }\n    }\n    p.angle = angleFinder(lastPerc);\n    return p;\n  }\n\n  /**\n   * Run over a parsed and simplifed path and extrac some informations.\n   * informations are length of each command and starting point\n   * @param {Array} path fabricJS parsed path commands\n   * @return {Array} path commands informations\n   */\n  function getPathSegmentsInfo(path) {\n    var totalLength = 0, len = path.length, current,\n        //x2 and y2 are the coords of segment start\n        //x1 and y1 are the coords of the current point\n        x1 = 0, y1 = 0, x2 = 0, y2 = 0, info = [], iterator, tempInfo, angleFinder;\n    for (var i = 0; i < len; i++) {\n      current = path[i];\n      tempInfo = {\n        x: x1,\n        y: y1,\n        command: current[0],\n      };\n      switch (current[0]) { //first letter\n        case 'M':\n          tempInfo.length = 0;\n          x2 = x1 = current[1];\n          y2 = y1 = current[2];\n          break;\n        case 'L':\n          tempInfo.length = calcLineLength(x1, y1, current[1], current[2]);\n          x1 = current[1];\n          y1 = current[2];\n          break;\n        case 'C':\n          iterator = getPointOnCubicBezierIterator(\n            x1,\n            y1,\n            current[1],\n            current[2],\n            current[3],\n            current[4],\n            current[5],\n            current[6]\n          );\n          angleFinder = getTangentCubicIterator(\n            x1,\n            y1,\n            current[1],\n            current[2],\n            current[3],\n            current[4],\n            current[5],\n            current[6]\n          );\n          tempInfo.iterator = iterator;\n          tempInfo.angleFinder = angleFinder;\n          tempInfo.length = pathIterator(iterator, x1, y1);\n          x1 = current[5];\n          y1 = current[6];\n          break;\n        case 'Q':\n          iterator = getPointOnQuadraticBezierIterator(\n            x1,\n            y1,\n            current[1],\n            current[2],\n            current[3],\n            current[4]\n          );\n          angleFinder = getTangentQuadraticIterator(\n            x1,\n            y1,\n            current[1],\n            current[2],\n            current[3],\n            current[4]\n          );\n          tempInfo.iterator = iterator;\n          tempInfo.angleFinder = angleFinder;\n          tempInfo.length = pathIterator(iterator, x1, y1);\n          x1 = current[3];\n          y1 = current[4];\n          break;\n        case 'Z':\n        case 'z':\n          // we add those in order to ease calculations later\n          tempInfo.destX = x2;\n          tempInfo.destY = y2;\n          tempInfo.length = calcLineLength(x1, y1, x2, y2);\n          x1 = x2;\n          y1 = y2;\n          break;\n      }\n      totalLength += tempInfo.length;\n      info.push(tempInfo);\n    }\n    info.push({ length: totalLength, x: x1, y: y1 });\n    return info;\n  }\n\n  function getPointOnPath(path, distance, infos) {\n    if (!infos) {\n      infos = getPathSegmentsInfo(path);\n    }\n    var i = 0;\n    while ((distance - infos[i].length > 0) && i < (infos.length - 2)) {\n      distance -= infos[i].length;\n      i++;\n    }\n    // var distance = infos[infos.length - 1] * perc;\n    var segInfo = infos[i], segPercent = distance / segInfo.length,\n        command = segInfo.command, segment = path[i], info;\n\n    switch (command) {\n      case 'M':\n        return { x: segInfo.x, y: segInfo.y, angle: 0 };\n      case 'Z':\n      case 'z':\n        info = new fabric.Point(segInfo.x, segInfo.y).lerp(\n          new fabric.Point(segInfo.destX, segInfo.destY),\n          segPercent\n        );\n        info.angle = Math.atan2(segInfo.destY - segInfo.y, segInfo.destX - segInfo.x);\n        return info;\n      case 'L':\n        info = new fabric.Point(segInfo.x, segInfo.y).lerp(\n          new fabric.Point(segment[1], segment[2]),\n          segPercent\n        );\n        info.angle = Math.atan2(segment[2] - segInfo.y, segment[1] - segInfo.x);\n        return info;\n      case 'C':\n        return findPercentageForDistance(segInfo, distance);\n      case 'Q':\n        return findPercentageForDistance(segInfo, distance);\n    }\n  }\n\n  /**\n   *\n   * @param {string} pathString\n   * @return {(string|number)[][]} An array of SVG path commands\n   * @example <caption>Usage</caption>\n   * parsePath('M 3 4 Q 3 5 2 1 4 0 Q 9 12 2 1 4 0') === [\n   *   ['M', 3, 4],\n   *   ['Q', 3, 5, 2, 1, 4, 0],\n   *   ['Q', 9, 12, 2, 1, 4, 0],\n   * ];\n   *\n   */\n  function parsePath(pathString) {\n    var result = [],\n        coords = [],\n        currentPath,\n        parsed,\n        re = fabric.rePathCommand,\n        rNumber = '[-+]?(?:\\\\d*\\\\.\\\\d+|\\\\d+\\\\.?)(?:[eE][-+]?\\\\d+)?\\\\s*',\n        rNumberCommaWsp = '(' + rNumber + ')' + fabric.commaWsp,\n        rFlagCommaWsp = '([01])' + fabric.commaWsp + '?',\n        rArcSeq = rNumberCommaWsp + '?' + rNumberCommaWsp + '?' + rNumberCommaWsp + rFlagCommaWsp + rFlagCommaWsp +\n          rNumberCommaWsp + '?(' + rNumber + ')',\n        regArcArgumentSequence = new RegExp(rArcSeq, 'g'),\n        match,\n        coordsStr,\n        // one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values)\n        path;\n    if (!pathString || !pathString.match) {\n      return result;\n    }\n    path = pathString.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);\n\n    for (var i = 0, coordsParsed, len = path.length; i < len; i++) {\n      currentPath = path[i];\n\n      coordsStr = currentPath.slice(1).trim();\n      coords.length = 0;\n\n      var command = currentPath.charAt(0);\n      coordsParsed = [command];\n\n      if (command.toLowerCase() === 'a') {\n        // arcs have special flags that apparently don't require spaces so handle special\n        for (var args; (args = regArcArgumentSequence.exec(coordsStr));) {\n          for (var j = 1; j < args.length; j++) {\n            coords.push(args[j]);\n          }\n        }\n      }\n      else {\n        while ((match = re.exec(coordsStr))) {\n          coords.push(match[0]);\n        }\n      }\n\n      for (var j = 0, jlen = coords.length; j < jlen; j++) {\n        parsed = parseFloat(coords[j]);\n        if (!isNaN(parsed)) {\n          coordsParsed.push(parsed);\n        }\n      }\n\n      var commandLength = commandLengths[command.toLowerCase()],\n          repeatedCommand = repeatedCommands[command] || command;\n\n      if (coordsParsed.length - 1 > commandLength) {\n        for (var k = 1, klen = coordsParsed.length; k < klen; k += commandLength) {\n          result.push([command].concat(coordsParsed.slice(k, k + commandLength)));\n          command = repeatedCommand;\n        }\n      }\n      else {\n        result.push(coordsParsed);\n      }\n    }\n\n    return result;\n  };\n\n  /**\n   *\n   * Converts points to a smooth SVG path\n   * @param {{ x: number,y: number }[]} points Array of points\n   * @param {number} [correction] Apply a correction to the path (usually we use `width / 1000`). If value is undefined 0 is used as the correction value.\n   * @return {(string|number)[][]} An array of SVG path commands\n   */\n  function getSmoothPathFromPoints(points, correction) {\n    var path = [], i,\n        p1 = new fabric.Point(points[0].x, points[0].y),\n        p2 = new fabric.Point(points[1].x, points[1].y),\n        len = points.length, multSignX = 1, multSignY = 0, manyPoints = len > 2;\n    correction = correction || 0;\n\n    if (manyPoints) {\n      multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;\n      multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1;\n    }\n    path.push(['M', p1.x - multSignX * correction, p1.y - multSignY * correction]);\n    for (i = 1; i < len; i++) {\n      if (!p1.eq(p2)) {\n        var midPoint = p1.midPointFrom(p2);\n        // p1 is our bezier control point\n        // midpoint is our endpoint\n        // start point is p(i-1) value.\n        path.push(['Q', p1.x, p1.y, midPoint.x, midPoint.y]);\n      }\n      p1 = points[i];\n      if ((i + 1) < points.length) {\n        p2 = points[i + 1];\n      }\n    }\n    if (manyPoints) {\n      multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;\n      multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;\n    }\n    path.push(['L', p1.x + multSignX * correction, p1.y + multSignY * correction]);\n    return path;\n  }\n  /**\n   * Transform a path by transforming each segment.\n   * it has to be a simplified path or it won't work.\n   * WARNING: this depends from pathOffset for correct operation\n   * @param {Array} path fabricJS parsed and simplified path commands\n   * @param {Array} transform matrix that represent the transformation\n   * @param {Object} [pathOffset] the fabric.Path pathOffset\n   * @param {Number} pathOffset.x\n   * @param {Number} pathOffset.y\n   * @returns {Array} the transformed path\n   */\n  function transformPath(path, transform, pathOffset) {\n    if (pathOffset) {\n      transform = fabric.util.multiplyTransformMatrices(\n        transform,\n        [1, 0, 0, 1, -pathOffset.x, -pathOffset.y]\n      );\n    }\n    return path.map(function(pathSegment) {\n      var newSegment = pathSegment.slice(0), point = {};\n      for (var i = 1; i < pathSegment.length - 1; i += 2) {\n        point.x = pathSegment[i];\n        point.y = pathSegment[i + 1];\n        point = fabric.util.transformPoint(point, transform);\n        newSegment[i] = point.x;\n        newSegment[i + 1] = point.y;\n      }\n      return newSegment;\n    });\n  }\n\n  /**\n   * Join path commands to go back to svg format\n   * @param {Array} pathData fabricJS parsed path commands\n   * @return {String} joined path 'M 0 0 L 20 30'\n   */\n  fabric.util.joinPath = function(pathData) {\n    return pathData.map(function (segment) { return segment.join(' '); }).join(' ');\n  };\n  fabric.util.parsePath = parsePath;\n  fabric.util.makePathSimpler = makePathSimpler;\n  fabric.util.getSmoothPathFromPoints = getSmoothPathFromPoints;\n  fabric.util.getPathSegmentsInfo = getPathSegmentsInfo;\n  fabric.util.getBoundsOfCurve = getBoundsOfCurve;\n  fabric.util.getPointOnPath = getPointOnPath;\n  fabric.util.transformPath = transformPath;\n})();\n\n\n(function() {\n\n  var slice = Array.prototype.slice;\n\n  /**\n   * Invokes method on all items in a given array\n   * @memberOf fabric.util.array\n   * @param {Array} array Array to iterate over\n   * @param {String} method Name of a method to invoke\n   * @return {Array}\n   */\n  function invoke(array, method) {\n    var args = slice.call(arguments, 2), result = [];\n    for (var i = 0, len = array.length; i < len; i++) {\n      result[i] = args.length ? array[i][method].apply(array[i], args) : array[i][method].call(array[i]);\n    }\n    return result;\n  }\n\n  /**\n   * Finds maximum value in array (not necessarily \"first\" one)\n   * @memberOf fabric.util.array\n   * @param {Array} array Array to iterate over\n   * @param {String} byProperty\n   * @return {*}\n   */\n  function max(array, byProperty) {\n    return find(array, byProperty, function(value1, value2) {\n      return value1 >= value2;\n    });\n  }\n\n  /**\n   * Finds minimum value in array (not necessarily \"first\" one)\n   * @memberOf fabric.util.array\n   * @param {Array} array Array to iterate over\n   * @param {String} byProperty\n   * @return {*}\n   */\n  function min(array, byProperty) {\n    return find(array, byProperty, function(value1, value2) {\n      return value1 < value2;\n    });\n  }\n\n  /**\n   * @private\n   */\n  function fill(array, value) {\n    var k = array.length;\n    while (k--) {\n      array[k] = value;\n    }\n    return array;\n  }\n\n  /**\n   * @private\n   */\n  function find(array, byProperty, condition) {\n    if (!array || array.length === 0) {\n      return;\n    }\n\n    var i = array.length - 1,\n        result = byProperty ? array[i][byProperty] : array[i];\n    if (byProperty) {\n      while (i--) {\n        if (condition(array[i][byProperty], result)) {\n          result = array[i][byProperty];\n        }\n      }\n    }\n    else {\n      while (i--) {\n        if (condition(array[i], result)) {\n          result = array[i];\n        }\n      }\n    }\n    return result;\n  }\n\n  /**\n   * @namespace fabric.util.array\n   */\n  fabric.util.array = {\n    fill: fill,\n    invoke: invoke,\n    min: min,\n    max: max\n  };\n\n})();\n\n\n(function() {\n  /**\n   * Copies all enumerable properties of one js object to another\n   * this does not and cannot compete with generic utils.\n   * Does not clone or extend fabric.Object subclasses.\n   * This is mostly for internal use and has extra handling for fabricJS objects\n   * it skips the canvas and group properties in deep cloning.\n   * @memberOf fabric.util.object\n   * @param {Object} destination Where to copy to\n   * @param {Object} source Where to copy from\n   * @param {Boolean} [deep] Whether to extend nested objects\n   * @return {Object}\n   */\n\n  function extend(destination, source, deep) {\n    // JScript DontEnum bug is not taken care of\n    // the deep clone is for internal use, is not meant to avoid\n    // javascript traps or cloning html element or self referenced objects.\n    if (deep) {\n      if (!fabric.isLikelyNode && source instanceof Element) {\n        // avoid cloning deep images, canvases,\n        destination = source;\n      }\n      else if (source instanceof Array) {\n        destination = [];\n        for (var i = 0, len = source.length; i < len; i++) {\n          destination[i] = extend({ }, source[i], deep);\n        }\n      }\n      else if (source && typeof source === 'object') {\n        for (var property in source) {\n          if (property === 'canvas' || property === 'group') {\n            // we do not want to clone this props at all.\n            // we want to keep the keys in the copy\n            destination[property] = null;\n          }\n          else if (source.hasOwnProperty(property)) {\n            destination[property] = extend({ }, source[property], deep);\n          }\n        }\n      }\n      else {\n        // this sounds odd for an extend but is ok for recursive use\n        destination = source;\n      }\n    }\n    else {\n      for (var property in source) {\n        destination[property] = source[property];\n      }\n    }\n    return destination;\n  }\n\n  /**\n   * Creates an empty object and copies all enumerable properties of another object to it\n   * This method is mostly for internal use, and not intended for duplicating shapes in canvas. \n   * @memberOf fabric.util.object\n   * @param {Object} object Object to clone\n   * @param {Boolean} [deep] Whether to clone nested objects\n   * @return {Object}\n   */\n\n  //TODO: this function return an empty object if you try to clone null\n  function clone(object, deep) {\n    return extend({ }, object, deep);\n  }\n\n  /** @namespace fabric.util.object */\n  fabric.util.object = {\n    extend: extend,\n    clone: clone\n  };\n  fabric.util.object.extend(fabric.util, fabric.Observable);\n})();\n\n\n(function() {\n\n  /**\n   * Camelizes a string\n   * @memberOf fabric.util.string\n   * @param {String} string String to camelize\n   * @return {String} Camelized version of a string\n   */\n  function camelize(string) {\n    return string.replace(/-+(.)?/g, function(match, character) {\n      return character ? character.toUpperCase() : '';\n    });\n  }\n\n  /**\n   * Capitalizes a string\n   * @memberOf fabric.util.string\n   * @param {String} string String to capitalize\n   * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized\n   * and other letters stay untouched, if false first letter is capitalized\n   * and other letters are converted to lowercase.\n   * @return {String} Capitalized version of a string\n   */\n  function capitalize(string, firstLetterOnly) {\n    return string.charAt(0).toUpperCase() +\n      (firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase());\n  }\n\n  /**\n   * Escapes XML in a string\n   * @memberOf fabric.util.string\n   * @param {String} string String to escape\n   * @return {String} Escaped version of a string\n   */\n  function escapeXml(string) {\n    return string.replace(/&/g, '&amp;')\n      .replace(/\"/g, '&quot;')\n      .replace(/'/g, '&apos;')\n      .replace(/</g, '&lt;')\n      .replace(/>/g, '&gt;');\n  }\n\n  /**\n   * Divide a string in the user perceived single units\n   * @memberOf fabric.util.string\n   * @param {String} textstring String to escape\n   * @return {Array} array containing the graphemes\n   */\n  function graphemeSplit(textstring) {\n    var i = 0, chr, graphemes = [];\n    for (i = 0, chr; i < textstring.length; i++) {\n      if ((chr = getWholeChar(textstring, i)) === false) {\n        continue;\n      }\n      graphemes.push(chr);\n    }\n    return graphemes;\n  }\n\n  // taken from mdn in the charAt doc page.\n  function getWholeChar(str, i) {\n    var code = str.charCodeAt(i);\n\n    if (isNaN(code)) {\n      return ''; // Position not found\n    }\n    if (code < 0xD800 || code > 0xDFFF) {\n      return str.charAt(i);\n    }\n\n    // High surrogate (could change last hex to 0xDB7F to treat high private\n    // surrogates as single characters)\n    if (0xD800 <= code && code <= 0xDBFF) {\n      if (str.length <= (i + 1)) {\n        throw 'High surrogate without following low surrogate';\n      }\n      var next = str.charCodeAt(i + 1);\n      if (0xDC00 > next || next > 0xDFFF) {\n        throw 'High surrogate without following low surrogate';\n      }\n      return str.charAt(i) + str.charAt(i + 1);\n    }\n    // Low surrogate (0xDC00 <= code && code <= 0xDFFF)\n    if (i === 0) {\n      throw 'Low surrogate without preceding high surrogate';\n    }\n    var prev = str.charCodeAt(i - 1);\n\n    // (could change last hex to 0xDB7F to treat high private\n    // surrogates as single characters)\n    if (0xD800 > prev || prev > 0xDBFF) {\n      throw 'Low surrogate without preceding high surrogate';\n    }\n    // We can pass over low surrogates now as the second component\n    // in a pair which we have already processed\n    return false;\n  }\n\n\n  /**\n   * String utilities\n   * @namespace fabric.util.string\n   */\n  fabric.util.string = {\n    camelize: camelize,\n    capitalize: capitalize,\n    escapeXml: escapeXml,\n    graphemeSplit: graphemeSplit\n  };\n})();\n\n\n(function() {\n\n  var slice = Array.prototype.slice, emptyFunction = function() { },\n\n      IS_DONTENUM_BUGGY = (function() {\n        for (var p in { toString: 1 }) {\n          if (p === 'toString') {\n            return false;\n          }\n        }\n        return true;\n      })(),\n\n      /** @ignore */\n      addMethods = function(klass, source, parent) {\n        for (var property in source) {\n\n          if (property in klass.prototype &&\n              typeof klass.prototype[property] === 'function' &&\n              (source[property] + '').indexOf('callSuper') > -1) {\n\n            klass.prototype[property] = (function(property) {\n              return function() {\n\n                var superclass = this.constructor.superclass;\n                this.constructor.superclass = parent;\n                var returnValue = source[property].apply(this, arguments);\n                this.constructor.superclass = superclass;\n\n                if (property !== 'initialize') {\n                  return returnValue;\n                }\n              };\n            })(property);\n          }\n          else {\n            klass.prototype[property] = source[property];\n          }\n\n          if (IS_DONTENUM_BUGGY) {\n            if (source.toString !== Object.prototype.toString) {\n              klass.prototype.toString = source.toString;\n            }\n            if (source.valueOf !== Object.prototype.valueOf) {\n              klass.prototype.valueOf = source.valueOf;\n            }\n          }\n        }\n      };\n\n  function Subclass() { }\n\n  function callSuper(methodName) {\n    var parentMethod = null,\n        _this = this;\n\n    // climb prototype chain to find method not equal to callee's method\n    while (_this.constructor.superclass) {\n      var superClassMethod = _this.constructor.superclass.prototype[methodName];\n      if (_this[methodName] !== superClassMethod) {\n        parentMethod = superClassMethod;\n        break;\n      }\n      // eslint-disable-next-line\n      _this = _this.constructor.superclass.prototype;\n    }\n\n    if (!parentMethod) {\n      return console.log('tried to callSuper ' + methodName + ', method not found in prototype chain', this);\n    }\n\n    return (arguments.length > 1)\n      ? parentMethod.apply(this, slice.call(arguments, 1))\n      : parentMethod.call(this);\n  }\n\n  /**\n   * Helper for creation of \"classes\".\n   * @memberOf fabric.util\n   * @param {Function} [parent] optional \"Class\" to inherit from\n   * @param {Object} [properties] Properties shared by all instances of this class\n   *                  (be careful modifying objects defined here as this would affect all instances)\n   */\n  function createClass() {\n    var parent = null,\n        properties = slice.call(arguments, 0);\n\n    if (typeof properties[0] === 'function') {\n      parent = properties.shift();\n    }\n    function klass() {\n      this.initialize.apply(this, arguments);\n    }\n\n    klass.superclass = parent;\n    klass.subclasses = [];\n\n    if (parent) {\n      Subclass.prototype = parent.prototype;\n      klass.prototype = new Subclass();\n      parent.subclasses.push(klass);\n    }\n    for (var i = 0, length = properties.length; i < length; i++) {\n      addMethods(klass, properties[i], parent);\n    }\n    if (!klass.prototype.initialize) {\n      klass.prototype.initialize = emptyFunction;\n    }\n    klass.prototype.constructor = klass;\n    klass.prototype.callSuper = callSuper;\n    return klass;\n  }\n\n  fabric.util.createClass = createClass;\n})();\n\n\n(function () {\n  // since ie11 can use addEventListener but they do not support options, i need to check\n  var couldUseAttachEvent = !!fabric.document.createElement('div').attachEvent,\n      touchEvents = ['touchstart', 'touchmove', 'touchend'];\n  /**\n   * Adds an event listener to an element\n   * @function\n   * @memberOf fabric.util\n   * @param {HTMLElement} element\n   * @param {String} eventName\n   * @param {Function} handler\n   */\n  fabric.util.addListener = function(element, eventName, handler, options) {\n    element && element.addEventListener(eventName, handler, couldUseAttachEvent ? false : options);\n  };\n\n  /**\n   * Removes an event listener from an element\n   * @function\n   * @memberOf fabric.util\n   * @param {HTMLElement} element\n   * @param {String} eventName\n   * @param {Function} handler\n   */\n  fabric.util.removeListener = function(element, eventName, handler, options) {\n    element && element.removeEventListener(eventName, handler, couldUseAttachEvent ? false : options);\n  };\n\n  function getTouchInfo(event) {\n    var touchProp = event.changedTouches;\n    if (touchProp && touchProp[0]) {\n      return touchProp[0];\n    }\n    return event;\n  }\n\n  fabric.util.getPointer = function(event) {\n    var element = event.target,\n        scroll = fabric.util.getScrollLeftTop(element),\n        _evt = getTouchInfo(event);\n    return {\n      x: _evt.clientX + scroll.left,\n      y: _evt.clientY + scroll.top\n    };\n  };\n\n  fabric.util.isTouchEvent = function(event) {\n    return touchEvents.indexOf(event.type) > -1 || event.pointerType === 'touch';\n  };\n})();\n\n\n(function () {\n\n  /**\n   * Cross-browser wrapper for setting element's style\n   * @memberOf fabric.util\n   * @param {HTMLElement} element\n   * @param {Object} styles\n   * @return {HTMLElement} Element that was passed as a first argument\n   */\n  function setStyle(element, styles) {\n    var elementStyle = element.style;\n    if (!elementStyle) {\n      return element;\n    }\n    if (typeof styles === 'string') {\n      element.style.cssText += ';' + styles;\n      return styles.indexOf('opacity') > -1\n        ? setOpacity(element, styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1])\n        : element;\n    }\n    for (var property in styles) {\n      if (property === 'opacity') {\n        setOpacity(element, styles[property]);\n      }\n      else {\n        var normalizedProperty = (property === 'float' || property === 'cssFloat')\n          ? (typeof elementStyle.styleFloat === 'undefined' ? 'cssFloat' : 'styleFloat')\n          : property;\n        elementStyle.setProperty(normalizedProperty, styles[property]);\n      }\n    }\n    return element;\n  }\n\n  var parseEl = fabric.document.createElement('div'),\n      supportsOpacity = typeof parseEl.style.opacity === 'string',\n      supportsFilters = typeof parseEl.style.filter === 'string',\n      reOpacity = /alpha\\s*\\(\\s*opacity\\s*=\\s*([^\\)]+)\\)/,\n\n      /** @ignore */\n      setOpacity = function (element) { return element; };\n\n  if (supportsOpacity) {\n    /** @ignore */\n    setOpacity = function(element, value) {\n      element.style.opacity = value;\n      return element;\n    };\n  }\n  else if (supportsFilters) {\n    /** @ignore */\n    setOpacity = function(element, value) {\n      var es = element.style;\n      if (element.currentStyle && !element.currentStyle.hasLayout) {\n        es.zoom = 1;\n      }\n      if (reOpacity.test(es.filter)) {\n        value = value >= 0.9999 ? '' : ('alpha(opacity=' + (value * 100) + ')');\n        es.filter = es.filter.replace(reOpacity, value);\n      }\n      else {\n        es.filter += ' alpha(opacity=' + (value * 100) + ')';\n      }\n      return element;\n    };\n  }\n\n  fabric.util.setStyle = setStyle;\n\n})();\n\n\n(function() {\n\n  var _slice = Array.prototype.slice;\n\n  /**\n   * Takes id and returns an element with that id (if one exists in a document)\n   * @memberOf fabric.util\n   * @param {String|HTMLElement} id\n   * @return {HTMLElement|null}\n   */\n  function getById(id) {\n    return typeof id === 'string' ? fabric.document.getElementById(id) : id;\n  }\n\n  var sliceCanConvertNodelists,\n      /**\n       * Converts an array-like object (e.g. arguments or NodeList) to an array\n       * @memberOf fabric.util\n       * @param {Object} arrayLike\n       * @return {Array}\n       */\n      toArray = function(arrayLike) {\n        return _slice.call(arrayLike, 0);\n      };\n\n  try {\n    sliceCanConvertNodelists = toArray(fabric.document.childNodes) instanceof Array;\n  }\n  catch (err) { }\n\n  if (!sliceCanConvertNodelists) {\n    toArray = function(arrayLike) {\n      var arr = new Array(arrayLike.length), i = arrayLike.length;\n      while (i--) {\n        arr[i] = arrayLike[i];\n      }\n      return arr;\n    };\n  }\n\n  /**\n   * Creates specified element with specified attributes\n   * @memberOf fabric.util\n   * @param {String} tagName Type of an element to create\n   * @param {Object} [attributes] Attributes to set on an element\n   * @return {HTMLElement} Newly created element\n   */\n  function makeElement(tagName, attributes) {\n    var el = fabric.document.createElement(tagName);\n    for (var prop in attributes) {\n      if (prop === 'class') {\n        el.className = attributes[prop];\n      }\n      else if (prop === 'for') {\n        el.htmlFor = attributes[prop];\n      }\n      else {\n        el.setAttribute(prop, attributes[prop]);\n      }\n    }\n    return el;\n  }\n\n  /**\n   * Adds class to an element\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to add class to\n   * @param {String} className Class to add to an element\n   */\n  function addClass(element, className) {\n    if (element && (' ' + element.className + ' ').indexOf(' ' + className + ' ') === -1) {\n      element.className += (element.className ? ' ' : '') + className;\n    }\n  }\n\n  /**\n   * Wraps element with another element\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to wrap\n   * @param {HTMLElement|String} wrapper Element to wrap with\n   * @param {Object} [attributes] Attributes to set on a wrapper\n   * @return {HTMLElement} wrapper\n   */\n  function wrapElement(element, wrapper, attributes) {\n    if (typeof wrapper === 'string') {\n      wrapper = makeElement(wrapper, attributes);\n    }\n    if (element.parentNode) {\n      element.parentNode.replaceChild(wrapper, element);\n    }\n    wrapper.appendChild(element);\n    return wrapper;\n  }\n\n  /**\n   * Returns element scroll offsets\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to operate on\n   * @return {Object} Object with left/top values\n   */\n  function getScrollLeftTop(element) {\n\n    var left = 0,\n        top = 0,\n        docElement = fabric.document.documentElement,\n        body = fabric.document.body || {\n          scrollLeft: 0, scrollTop: 0\n        };\n\n    // While loop checks (and then sets element to) .parentNode OR .host\n    //  to account for ShadowDOM. We still want to traverse up out of ShadowDOM,\n    //  but the .parentNode of a root ShadowDOM node will always be null, instead\n    //  it should be accessed through .host. See http://stackoverflow.com/a/24765528/4383938\n    while (element && (element.parentNode || element.host)) {\n\n      // Set element to element parent, or 'host' in case of ShadowDOM\n      element = element.parentNode || element.host;\n\n      if (element === fabric.document) {\n        left = body.scrollLeft || docElement.scrollLeft || 0;\n        top = body.scrollTop ||  docElement.scrollTop || 0;\n      }\n      else {\n        left += element.scrollLeft || 0;\n        top += element.scrollTop || 0;\n      }\n\n      if (element.nodeType === 1 && element.style.position === 'fixed') {\n        break;\n      }\n    }\n\n    return { left: left, top: top };\n  }\n\n  /**\n   * Returns offset for a given element\n   * @function\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to get offset for\n   * @return {Object} Object with \"left\" and \"top\" properties\n   */\n  function getElementOffset(element) {\n    var docElem,\n        doc = element && element.ownerDocument,\n        box = { left: 0, top: 0 },\n        offset = { left: 0, top: 0 },\n        scrollLeftTop,\n        offsetAttributes = {\n          borderLeftWidth: 'left',\n          borderTopWidth:  'top',\n          paddingLeft:     'left',\n          paddingTop:      'top'\n        };\n\n    if (!doc) {\n      return offset;\n    }\n\n    for (var attr in offsetAttributes) {\n      offset[offsetAttributes[attr]] += parseInt(getElementStyle(element, attr), 10) || 0;\n    }\n\n    docElem = doc.documentElement;\n    if ( typeof element.getBoundingClientRect !== 'undefined' ) {\n      box = element.getBoundingClientRect();\n    }\n\n    scrollLeftTop = getScrollLeftTop(element);\n\n    return {\n      left: box.left + scrollLeftTop.left - (docElem.clientLeft || 0) + offset.left,\n      top: box.top + scrollLeftTop.top - (docElem.clientTop || 0)  + offset.top\n    };\n  }\n\n  /**\n   * Returns style attribute value of a given element\n   * @memberOf fabric.util\n   * @param {HTMLElement} element Element to get style attribute for\n   * @param {String} attr Style attribute to get for element\n   * @return {String} Style attribute value of the given element.\n   */\n  var getElementStyle;\n  if (fabric.document.defaultView && fabric.document.defaultView.getComputedStyle) {\n    getElementStyle = function(element, attr) {\n      var style = fabric.document.defaultView.getComputedStyle(element, null);\n      return style ? style[attr] : undefined;\n    };\n  }\n  else {\n    getElementStyle = function(element, attr) {\n      var value = element.style[attr];\n      if (!value && element.currentStyle) {\n        value = element.currentStyle[attr];\n      }\n      return value;\n    };\n  }\n\n  (function () {\n    var style = fabric.document.documentElement.style,\n        selectProp = 'userSelect' in style\n          ? 'userSelect'\n          : 'MozUserSelect' in style\n            ? 'MozUserSelect'\n            : 'WebkitUserSelect' in style\n              ? 'WebkitUserSelect'\n              : 'KhtmlUserSelect' in style\n                ? 'KhtmlUserSelect'\n                : '';\n\n    /**\n     * Makes element unselectable\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to make unselectable\n     * @return {HTMLElement} Element that was passed in\n     */\n    function makeElementUnselectable(element) {\n      if (typeof element.onselectstart !== 'undefined') {\n        element.onselectstart = fabric.util.falseFunction;\n      }\n      if (selectProp) {\n        element.style[selectProp] = 'none';\n      }\n      else if (typeof element.unselectable === 'string') {\n        element.unselectable = 'on';\n      }\n      return element;\n    }\n\n    /**\n     * Makes element selectable\n     * @memberOf fabric.util\n     * @param {HTMLElement} element Element to make selectable\n     * @return {HTMLElement} Element that was passed in\n     */\n    function makeElementSelectable(element) {\n      if (typeof element.onselectstart !== 'undefined') {\n        element.onselectstart = null;\n      }\n      if (selectProp) {\n        element.style[selectProp] = '';\n      }\n      else if (typeof element.unselectable === 'string') {\n        element.unselectable = '';\n      }\n      return element;\n    }\n\n    fabric.util.makeElementUnselectable = makeElementUnselectable;\n    fabric.util.makeElementSelectable = makeElementSelectable;\n  })();\n\n  function getNodeCanvas(element) {\n    var impl = fabric.jsdomImplForWrapper(element);\n    return impl._canvas || impl._image;\n  };\n\n  function cleanUpJsdomNode(element) {\n    if (!fabric.isLikelyNode) {\n      return;\n    }\n    var impl = fabric.jsdomImplForWrapper(element);\n    if (impl) {\n      impl._image = null;\n      impl._canvas = null;\n      // unsure if necessary\n      impl._currentSrc = null;\n      impl._attributes = null;\n      impl._classList = null;\n    }\n  }\n\n  function setImageSmoothing(ctx, value) {\n    ctx.imageSmoothingEnabled = ctx.imageSmoothingEnabled || ctx.webkitImageSmoothingEnabled\n      || ctx.mozImageSmoothingEnabled || ctx.msImageSmoothingEnabled || ctx.oImageSmoothingEnabled;\n    ctx.imageSmoothingEnabled = value;\n  }\n\n  /**\n   * setImageSmoothing sets the context imageSmoothingEnabled property.\n   * Used by canvas and by ImageObject.\n   * @memberOf fabric.util\n   * @since 4.0.0\n   * @param {HTMLRenderingContext2D} ctx to set on\n   * @param {Boolean} value true or false\n   */\n  fabric.util.setImageSmoothing = setImageSmoothing;\n  fabric.util.getById = getById;\n  fabric.util.toArray = toArray;\n  fabric.util.addClass = addClass;\n  fabric.util.makeElement = makeElement;\n  fabric.util.wrapElement = wrapElement;\n  fabric.util.getScrollLeftTop = getScrollLeftTop;\n  fabric.util.getElementOffset = getElementOffset;\n  fabric.util.getNodeCanvas = getNodeCanvas;\n  fabric.util.cleanUpJsdomNode = cleanUpJsdomNode;\n\n})();\n\n\n(function() {\n\n  function addParamToUrl(url, param) {\n    return url + (/\\?/.test(url) ? '&' : '?') + param;\n  }\n\n  function emptyFn() { }\n\n  /**\n   * Cross-browser abstraction for sending XMLHttpRequest\n   * @memberOf fabric.util\n   * @param {String} url URL to send XMLHttpRequest to\n   * @param {Object} [options] Options object\n   * @param {String} [options.method=\"GET\"]\n   * @param {String} [options.parameters] parameters to append to url in GET or in body\n   * @param {String} [options.body] body to send with POST or PUT request\n   * @param {Function} options.onComplete Callback to invoke when request is completed\n   * @return {XMLHttpRequest} request\n   */\n  function request(url, options) {\n    options || (options = { });\n\n    var method = options.method ? options.method.toUpperCase() : 'GET',\n        onComplete = options.onComplete || function() { },\n        xhr = new fabric.window.XMLHttpRequest(),\n        body = options.body || options.parameters;\n\n    /** @ignore */\n    xhr.onreadystatechange = function() {\n      if (xhr.readyState === 4) {\n        onComplete(xhr);\n        xhr.onreadystatechange = emptyFn;\n      }\n    };\n\n    if (method === 'GET') {\n      body = null;\n      if (typeof options.parameters === 'string') {\n        url = addParamToUrl(url, options.parameters);\n      }\n    }\n\n    xhr.open(method, url, true);\n\n    if (method === 'POST' || method === 'PUT') {\n      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n    }\n\n    xhr.send(body);\n    return xhr;\n  }\n\n  fabric.util.request = request;\n})();\n\n\n/**\n * Wrapper around `console.log` (when available)\n * @param {*} [values] Values to log\n */\nfabric.log = console.log;\n\n/**\n * Wrapper around `console.warn` (when available)\n * @param {*} [values] Values to log as a warning\n */\nfabric.warn = console.warn;\n\n\n(function () {\n\n  var extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone;\n\n  /**\n   * @typedef {Object} AnimationOptions\n   * Animation of a value or list of values.\n   * When using lists, think of something like this:\n   * fabric.util.animate({\n   *   startValue: [1, 2, 3],\n   *   endValue: [2, 4, 6],\n   *   onChange: function([a, b, c]) {\n   *     canvas.zoomToPoint({x: b, y: c}, a)\n   *     canvas.renderAll()\n   *   }\n   * });\n   * @example\n   * @property {Function} [onChange] Callback; invoked on every value change\n   * @property {Function} [onComplete] Callback; invoked when value change is completed\n   * @example\n   * // Note: startValue, endValue, and byValue must match the type\n   * var animationOptions = { startValue: 0, endValue: 1, byValue: 0.25 }\n   * var animationOptions = { startValue: [0, 1], endValue: [1, 2], byValue: [0.25, 0.25] }\n   * @property {number | number[]} [startValue=0] Starting value\n   * @property {number | number[]} [endValue=100] Ending value\n   * @property {number | number[]} [byValue=100] Value to modify the property by\n   * @property {Function} [easing] Easing function\n   * @property {Number} [duration=500] Duration of change (in ms)\n   * @property {Function} [abort] Additional function with logic. If returns true, animation aborts.\n   *\n   * @typedef {() => void} CancelFunction\n   *\n   * @typedef {Object} AnimationCurrentState\n   * @property {number | number[]} currentValue value in range [`startValue`, `endValue`]\n   * @property {number} completionRate value in range [0, 1]\n   * @property {number} durationRate value in range [0, 1]\n   *\n   * @typedef {(AnimationOptions & AnimationCurrentState & { cancel: CancelFunction }} AnimationContext\n   */\n\n  /**\n   * Array holding all running animations\n   * @memberof fabric\n   * @type {AnimationContext[]}\n   */\n  var RUNNING_ANIMATIONS = [];\n  fabric.util.object.extend(RUNNING_ANIMATIONS, {\n\n    /**\n     * cancel all running animations at the next requestAnimFrame\n     * @returns {AnimationContext[]}\n     */\n    cancelAll: function () {\n      var animations = this.splice(0);\n      animations.forEach(function (animation) {\n        animation.cancel();\n      });\n      return animations;\n    },\n\n    /**\n     * cancel all running animations attached to canvas at the next requestAnimFrame\n     * @param {fabric.Canvas} canvas\n     * @returns {AnimationContext[]}\n     */\n    cancelByCanvas: function (canvas) {\n      if (!canvas) {\n        return [];\n      }\n      var cancelled = this.filter(function (animation) {\n        return typeof animation.target === 'object' && animation.target.canvas === canvas;\n      });\n      cancelled.forEach(function (animation) {\n        animation.cancel();\n      });\n      return cancelled;\n    },\n\n    /**\n     * cancel all running animations for target at the next requestAnimFrame\n     * @param {*} target\n     * @returns {AnimationContext[]}\n     */\n    cancelByTarget: function (target) {\n      var cancelled = this.findAnimationsByTarget(target);\n      cancelled.forEach(function (animation) {\n        animation.cancel();\n      });\n      return cancelled;\n    },\n\n    /**\n     *\n     * @param {CancelFunction} cancelFunc the function returned by animate\n     * @returns {number}\n     */\n    findAnimationIndex: function (cancelFunc) {\n      return this.indexOf(this.findAnimation(cancelFunc));\n    },\n\n    /**\n     *\n     * @param {CancelFunction} cancelFunc the function returned by animate\n     * @returns {AnimationContext | undefined} animation's options object\n     */\n    findAnimation: function (cancelFunc) {\n      return this.find(function (animation) {\n        return animation.cancel === cancelFunc;\n      });\n    },\n\n    /**\n     *\n     * @param {*} target the object that is assigned to the target property of the animation context\n     * @returns {AnimationContext[]} array of animation options object associated with target\n     */\n    findAnimationsByTarget: function (target) {\n      if (!target) {\n        return [];\n      }\n      return this.filter(function (animation) {\n        return animation.target === target;\n      });\n    }\n  });\n\n  function noop() {\n    return false;\n  }\n\n  function defaultEasing(t, b, c, d) {\n    return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;\n  }\n\n  /**\n   * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.\n   * @memberOf fabric.util\n   * @param {AnimationOptions} [options] Animation options\n   * @example\n   * // Note: startValue, endValue, and byValue must match the type\n   * fabric.util.animate({ startValue: 0, endValue: 1, byValue: 0.25 })\n   * fabric.util.animate({ startValue: [0, 1], endValue: [1, 2], byValue: [0.25, 0.25] })\n   * @returns {CancelFunction} cancel function\n   */\n  function animate(options) {\n    options || (options = {});\n    var cancel = false,\n        context,\n        removeFromRegistry = function () {\n          var index = fabric.runningAnimations.indexOf(context);\n          return index > -1 && fabric.runningAnimations.splice(index, 1)[0];\n        };\n\n    context = extend(clone(options), {\n      cancel: function () {\n        cancel = true;\n        return removeFromRegistry();\n      },\n      currentValue: 'startValue' in options ? options.startValue : 0,\n      completionRate: 0,\n      durationRate: 0\n    });\n    fabric.runningAnimations.push(context);\n\n    requestAnimFrame(function(timestamp) {\n      var start = timestamp || +new Date(),\n          duration = options.duration || 500,\n          finish = start + duration, time,\n          onChange = options.onChange || noop,\n          abort = options.abort || noop,\n          onComplete = options.onComplete || noop,\n          easing = options.easing || defaultEasing,\n          isMany = 'startValue' in options ? options.startValue.length > 0 : false,\n          startValue = 'startValue' in options ? options.startValue : 0,\n          endValue = 'endValue' in options ? options.endValue : 100,\n          byValue = options.byValue || (isMany ? startValue.map(function(value, i) {\n            return endValue[i] - startValue[i];\n          }) : endValue - startValue);\n\n      options.onStart && options.onStart();\n\n      (function tick(ticktime) {\n        time = ticktime || +new Date();\n        var currentTime = time > finish ? duration : (time - start),\n            timePerc = currentTime / duration,\n            current = isMany ? startValue.map(function(_value, i) {\n              return easing(currentTime, startValue[i], byValue[i], duration);\n            }) : easing(currentTime, startValue, byValue, duration),\n            valuePerc = isMany ? Math.abs((current[0] - startValue[0]) / byValue[0])\n              : Math.abs((current - startValue) / byValue);\n        //  update context\n        context.currentValue = isMany ? current.slice() : current;\n        context.completionRate = valuePerc;\n        context.durationRate = timePerc;\n        if (cancel) {\n          return;\n        }\n        if (abort(current, valuePerc, timePerc)) {\n          removeFromRegistry();\n          return;\n        }\n        if (time > finish) {\n          //  update context\n          context.currentValue = isMany ? endValue.slice() : endValue;\n          context.completionRate = 1;\n          context.durationRate = 1;\n          //  execute callbacks\n          onChange(isMany ? endValue.slice() : endValue, 1, 1);\n          onComplete(endValue, 1, 1);\n          removeFromRegistry();\n          return;\n        }\n        else {\n          onChange(current, valuePerc, timePerc);\n          requestAnimFrame(tick);\n        }\n      })(start);\n    });\n\n    return context.cancel;\n  }\n\n  var _requestAnimFrame = fabric.window.requestAnimationFrame       ||\n                          fabric.window.webkitRequestAnimationFrame ||\n                          fabric.window.mozRequestAnimationFrame    ||\n                          fabric.window.oRequestAnimationFrame      ||\n                          fabric.window.msRequestAnimationFrame     ||\n                          function(callback) {\n                            return fabric.window.setTimeout(callback, 1000 / 60);\n                          };\n\n  var _cancelAnimFrame = fabric.window.cancelAnimationFrame || fabric.window.clearTimeout;\n\n  /**\n   * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/\n   * In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method\n   * @memberOf fabric.util\n   * @param {Function} callback Callback to invoke\n   * @param {DOMElement} element optional Element to associate with animation\n   */\n  function requestAnimFrame() {\n    return _requestAnimFrame.apply(fabric.window, arguments);\n  }\n\n  function cancelAnimFrame() {\n    return _cancelAnimFrame.apply(fabric.window, arguments);\n  }\n\n  fabric.util.animate = animate;\n  fabric.util.requestAnimFrame = requestAnimFrame;\n  fabric.util.cancelAnimFrame = cancelAnimFrame;\n  fabric.runningAnimations = RUNNING_ANIMATIONS;\n})();\n\n\n(function() {\n  // Calculate an in-between color. Returns a \"rgba()\" string.\n  // Credit: Edwin Martin <edwin@bitstorm.org>\n  //         http://www.bitstorm.org/jquery/color-animation/jquery.animate-colors.js\n  function calculateColor(begin, end, pos) {\n    var color = 'rgba('\n        + parseInt((begin[0] + pos * (end[0] - begin[0])), 10) + ','\n        + parseInt((begin[1] + pos * (end[1] - begin[1])), 10) + ','\n        + parseInt((begin[2] + pos * (end[2] - begin[2])), 10);\n\n    color += ',' + (begin && end ? parseFloat(begin[3] + pos * (end[3] - begin[3])) : 1);\n    color += ')';\n    return color;\n  }\n\n  /**\n   * Changes the color from one to another within certain period of time, invoking callbacks as value is being changed.\n   * @memberOf fabric.util\n   * @param {String} fromColor The starting color in hex or rgb(a) format.\n   * @param {String} toColor The starting color in hex or rgb(a) format.\n   * @param {Number} [duration] Duration of change (in ms).\n   * @param {Object} [options] Animation options\n   * @param {Function} [options.onChange] Callback; invoked on every value change\n   * @param {Function} [options.onComplete] Callback; invoked when value change is completed\n   * @param {Function} [options.colorEasing] Easing function. Note that this function only take two arguments (currentTime, duration). Thus the regular animation easing functions cannot be used.\n   * @param {Function} [options.abort] Additional function with logic. If returns true, onComplete is called.\n   * @returns {Function} abort function\n   */\n  function animateColor(fromColor, toColor, duration, options) {\n    var startColor = new fabric.Color(fromColor).getSource(),\n        endColor = new fabric.Color(toColor).getSource(),\n        originalOnComplete = options.onComplete,\n        originalOnChange = options.onChange;\n    options = options || {};\n\n    return fabric.util.animate(fabric.util.object.extend(options, {\n      duration: duration || 500,\n      startValue: startColor,\n      endValue: endColor,\n      byValue: endColor,\n      easing: function (currentTime, startValue, byValue, duration) {\n        var posValue = options.colorEasing\n          ? options.colorEasing(currentTime, duration)\n          : 1 - Math.cos(currentTime / duration * (Math.PI / 2));\n        return calculateColor(startValue, byValue, posValue);\n      },\n      // has to take in account for color restoring;\n      onComplete: function(current, valuePerc, timePerc) {\n        if (originalOnComplete) {\n          return originalOnComplete(\n            calculateColor(endColor, endColor, 0),\n            valuePerc,\n            timePerc\n          );\n        }\n      },\n      onChange: function(current, valuePerc, timePerc) {\n        if (originalOnChange) {\n          if (Array.isArray(current)) {\n            return originalOnChange(\n              calculateColor(current, current, 0),\n              valuePerc,\n              timePerc\n            );\n          }\n          originalOnChange(current, valuePerc, timePerc);\n        }\n      }\n    }));\n  }\n\n  fabric.util.animateColor = animateColor;\n\n})();\n\n\n(function() {\n\n  function normalize(a, c, p, s) {\n    if (a < Math.abs(c)) {\n      a = c;\n      s = p / 4;\n    }\n    else {\n      //handle the 0/0 case:\n      if (c === 0 && a === 0) {\n        s = p / (2 * Math.PI) * Math.asin(1);\n      }\n      else {\n        s = p / (2 * Math.PI) * Math.asin(c / a);\n      }\n    }\n    return { a: a, c: c, p: p, s: s };\n  }\n\n  function elastic(opts, t, d) {\n    return opts.a *\n      Math.pow(2, 10 * (t -= 1)) *\n      Math.sin( (t * d - opts.s) * (2 * Math.PI) / opts.p );\n  }\n\n  /**\n   * Cubic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutCubic(t, b, c, d) {\n    return c * ((t = t / d - 1) * t * t + 1) + b;\n  }\n\n  /**\n   * Cubic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutCubic(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * t * t * t + b;\n    }\n    return c / 2 * ((t -= 2) * t * t + 2) + b;\n  }\n\n  /**\n   * Quartic easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInQuart(t, b, c, d) {\n    return c * (t /= d) * t * t * t + b;\n  }\n\n  /**\n   * Quartic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutQuart(t, b, c, d) {\n    return -c * ((t = t / d - 1) * t * t * t - 1) + b;\n  }\n\n  /**\n   * Quartic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutQuart(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * t * t * t * t + b;\n    }\n    return -c / 2 * ((t -= 2) * t * t * t - 2) + b;\n  }\n\n  /**\n   * Quintic easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInQuint(t, b, c, d) {\n    return c * (t /= d) * t * t * t * t + b;\n  }\n\n  /**\n   * Quintic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutQuint(t, b, c, d) {\n    return c * ((t = t / d - 1) * t * t * t * t + 1) + b;\n  }\n\n  /**\n   * Quintic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutQuint(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * t * t * t * t * t + b;\n    }\n    return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;\n  }\n\n  /**\n   * Sinusoidal easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInSine(t, b, c, d) {\n    return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;\n  }\n\n  /**\n   * Sinusoidal easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutSine(t, b, c, d) {\n    return c * Math.sin(t / d * (Math.PI / 2)) + b;\n  }\n\n  /**\n   * Sinusoidal easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutSine(t, b, c, d) {\n    return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n  }\n\n  /**\n   * Exponential easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInExpo(t, b, c, d) {\n    return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n  }\n\n  /**\n   * Exponential easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutExpo(t, b, c, d) {\n    return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n  }\n\n  /**\n   * Exponential easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutExpo(t, b, c, d) {\n    if (t === 0) {\n      return b;\n    }\n    if (t === d) {\n      return b + c;\n    }\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n    }\n    return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n  }\n\n  /**\n   * Circular easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInCirc(t, b, c, d) {\n    return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;\n  }\n\n  /**\n   * Circular easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutCirc(t, b, c, d) {\n    return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;\n  }\n\n  /**\n   * Circular easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutCirc(t, b, c, d) {\n    t /= d / 2;\n    if (t < 1) {\n      return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;\n    }\n    return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;\n  }\n\n  /**\n   * Elastic easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInElastic(t, b, c, d) {\n    var s = 1.70158, p = 0, a = c;\n    if (t === 0) {\n      return b;\n    }\n    t /= d;\n    if (t === 1) {\n      return b + c;\n    }\n    if (!p) {\n      p = d * 0.3;\n    }\n    var opts = normalize(a, c, p, s);\n    return -elastic(opts, t, d) + b;\n  }\n\n  /**\n   * Elastic easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutElastic(t, b, c, d) {\n    var s = 1.70158, p = 0, a = c;\n    if (t === 0) {\n      return b;\n    }\n    t /= d;\n    if (t === 1) {\n      return b + c;\n    }\n    if (!p) {\n      p = d * 0.3;\n    }\n    var opts = normalize(a, c, p, s);\n    return opts.a * Math.pow(2, -10 * t) * Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) + opts.c + b;\n  }\n\n  /**\n   * Elastic easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutElastic(t, b, c, d) {\n    var s = 1.70158, p = 0, a = c;\n    if (t === 0) {\n      return b;\n    }\n    t /= d / 2;\n    if (t === 2) {\n      return b + c;\n    }\n    if (!p) {\n      p = d * (0.3 * 1.5);\n    }\n    var opts = normalize(a, c, p, s);\n    if (t < 1) {\n      return -0.5 * elastic(opts, t, d) + b;\n    }\n    return opts.a * Math.pow(2, -10 * (t -= 1)) *\n      Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) * 0.5 + opts.c + b;\n  }\n\n  /**\n   * Backwards easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInBack(t, b, c, d, s) {\n    if (s === undefined) {\n      s = 1.70158;\n    }\n    return c * (t /= d) * t * ((s + 1) * t - s) + b;\n  }\n\n  /**\n   * Backwards easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutBack(t, b, c, d, s) {\n    if (s === undefined) {\n      s = 1.70158;\n    }\n    return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;\n  }\n\n  /**\n   * Backwards easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutBack(t, b, c, d, s) {\n    if (s === undefined) {\n      s = 1.70158;\n    }\n    t /= d / 2;\n    if (t < 1) {\n      return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;\n    }\n    return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;\n  }\n\n  /**\n   * Bouncing easing in\n   * @memberOf fabric.util.ease\n   */\n  function easeInBounce(t, b, c, d) {\n    return c - easeOutBounce (d - t, 0, c, d) + b;\n  }\n\n  /**\n   * Bouncing easing out\n   * @memberOf fabric.util.ease\n   */\n  function easeOutBounce(t, b, c, d) {\n    if ((t /= d) < (1 / 2.75)) {\n      return c * (7.5625 * t * t) + b;\n    }\n    else if (t < (2 / 2.75)) {\n      return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;\n    }\n    else if (t < (2.5 / 2.75)) {\n      return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;\n    }\n    else {\n      return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;\n    }\n  }\n\n  /**\n   * Bouncing easing in and out\n   * @memberOf fabric.util.ease\n   */\n  function easeInOutBounce(t, b, c, d) {\n    if (t < d / 2) {\n      return easeInBounce (t * 2, 0, c, d) * 0.5 + b;\n    }\n    return easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;\n  }\n\n  /**\n   * Easing functions\n   * See <a href=\"http://gizma.com/easing/\">Easing Equations by Robert Penner</a>\n   * @namespace fabric.util.ease\n   */\n  fabric.util.ease = {\n\n    /**\n     * Quadratic easing in\n     * @memberOf fabric.util.ease\n     */\n    easeInQuad: function(t, b, c, d) {\n      return c * (t /= d) * t + b;\n    },\n\n    /**\n     * Quadratic easing out\n     * @memberOf fabric.util.ease\n     */\n    easeOutQuad: function(t, b, c, d) {\n      return -c * (t /= d) * (t - 2) + b;\n    },\n\n    /**\n     * Quadratic easing in and out\n     * @memberOf fabric.util.ease\n     */\n    easeInOutQuad: function(t, b, c, d) {\n      t /= (d / 2);\n      if (t < 1) {\n        return c / 2 * t * t + b;\n      }\n      return -c / 2 * ((--t) * (t - 2) - 1) + b;\n    },\n\n    /**\n     * Cubic easing in\n     * @memberOf fabric.util.ease\n     */\n    easeInCubic: function(t, b, c, d) {\n      return c * (t /= d) * t * t + b;\n    },\n\n    easeOutCubic: easeOutCubic,\n    easeInOutCubic: easeInOutCubic,\n    easeInQuart: easeInQuart,\n    easeOutQuart: easeOutQuart,\n    easeInOutQuart: easeInOutQuart,\n    easeInQuint: easeInQuint,\n    easeOutQuint: easeOutQuint,\n    easeInOutQuint: easeInOutQuint,\n    easeInSine: easeInSine,\n    easeOutSine: easeOutSine,\n    easeInOutSine: easeInOutSine,\n    easeInExpo: easeInExpo,\n    easeOutExpo: easeOutExpo,\n    easeInOutExpo: easeInOutExpo,\n    easeInCirc: easeInCirc,\n    easeOutCirc: easeOutCirc,\n    easeInOutCirc: easeInOutCirc,\n    easeInElastic: easeInElastic,\n    easeOutElastic: easeOutElastic,\n    easeInOutElastic: easeInOutElastic,\n    easeInBack: easeInBack,\n    easeOutBack: easeOutBack,\n    easeInOutBack: easeInOutBack,\n    easeInBounce: easeInBounce,\n    easeOutBounce: easeOutBounce,\n    easeInOutBounce: easeInOutBounce\n  };\n\n})();\n\n\n(function(global) {\n\n  'use strict';\n\n  /**\n   * @name fabric\n   * @namespace\n   */\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone,\n      toFixed = fabric.util.toFixed,\n      parseUnit = fabric.util.parseUnit,\n      multiplyTransformMatrices = fabric.util.multiplyTransformMatrices,\n\n      svgValidTagNames = ['path', 'circle', 'polygon', 'polyline', 'ellipse', 'rect', 'line',\n        'image', 'text'],\n      svgViewBoxElements = ['symbol', 'image', 'marker', 'pattern', 'view', 'svg'],\n      svgInvalidAncestors = ['pattern', 'defs', 'symbol', 'metadata', 'clipPath', 'mask', 'desc'],\n      svgValidParents = ['symbol', 'g', 'a', 'svg', 'clipPath', 'defs'],\n\n      attributesMap = {\n        cx:                   'left',\n        x:                    'left',\n        r:                    'radius',\n        cy:                   'top',\n        y:                    'top',\n        display:              'visible',\n        visibility:           'visible',\n        transform:            'transformMatrix',\n        'fill-opacity':       'fillOpacity',\n        'fill-rule':          'fillRule',\n        'font-family':        'fontFamily',\n        'font-size':          'fontSize',\n        'font-style':         'fontStyle',\n        'font-weight':        'fontWeight',\n        'letter-spacing':     'charSpacing',\n        'paint-order':        'paintFirst',\n        'stroke-dasharray':   'strokeDashArray',\n        'stroke-dashoffset':  'strokeDashOffset',\n        'stroke-linecap':     'strokeLineCap',\n        'stroke-linejoin':    'strokeLineJoin',\n        'stroke-miterlimit':  'strokeMiterLimit',\n        'stroke-opacity':     'strokeOpacity',\n        'stroke-width':       'strokeWidth',\n        'text-decoration':    'textDecoration',\n        'text-anchor':        'textAnchor',\n        opacity:              'opacity',\n        'clip-path':          'clipPath',\n        'clip-rule':          'clipRule',\n        'vector-effect':      'strokeUniform',\n        'image-rendering':    'imageSmoothing',\n      },\n\n      colorAttributes = {\n        stroke: 'strokeOpacity',\n        fill:   'fillOpacity'\n      },\n\n      fSize = 'font-size', cPath = 'clip-path';\n\n  fabric.svgValidTagNamesRegEx = getSvgRegex(svgValidTagNames);\n  fabric.svgViewBoxElementsRegEx = getSvgRegex(svgViewBoxElements);\n  fabric.svgInvalidAncestorsRegEx = getSvgRegex(svgInvalidAncestors);\n  fabric.svgValidParentsRegEx = getSvgRegex(svgValidParents);\n\n  fabric.cssRules = { };\n  fabric.gradientDefs = { };\n  fabric.clipPaths = { };\n\n  function normalizeAttr(attr) {\n    // transform attribute names\n    if (attr in attributesMap) {\n      return attributesMap[attr];\n    }\n    return attr;\n  }\n\n  function normalizeValue(attr, value, parentAttributes, fontSize) {\n    var isArray = Array.isArray(value), parsed;\n\n    if ((attr === 'fill' || attr === 'stroke') && value === 'none') {\n      value = '';\n    }\n    else if (attr === 'strokeUniform') {\n      return (value === 'non-scaling-stroke');\n    }\n    else if (attr === 'strokeDashArray') {\n      if (value === 'none') {\n        value = null;\n      }\n      else {\n        value = value.replace(/,/g, ' ').split(/\\s+/).map(parseFloat);\n      }\n    }\n    else if (attr === 'transformMatrix') {\n      if (parentAttributes && parentAttributes.transformMatrix) {\n        value = multiplyTransformMatrices(\n          parentAttributes.transformMatrix, fabric.parseTransformAttribute(value));\n      }\n      else {\n        value = fabric.parseTransformAttribute(value);\n      }\n    }\n    else if (attr === 'visible') {\n      value = value !== 'none' && value !== 'hidden';\n      // display=none on parent element always takes precedence over child element\n      if (parentAttributes && parentAttributes.visible === false) {\n        value = false;\n      }\n    }\n    else if (attr === 'opacity') {\n      value = parseFloat(value);\n      if (parentAttributes && typeof parentAttributes.opacity !== 'undefined') {\n        value *= parentAttributes.opacity;\n      }\n    }\n    else if (attr === 'textAnchor' /* text-anchor */) {\n      value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center';\n    }\n    else if (attr === 'charSpacing') {\n      // parseUnit returns px and we convert it to em\n      parsed = parseUnit(value, fontSize) / fontSize * 1000;\n    }\n    else if (attr === 'paintFirst') {\n      var fillIndex = value.indexOf('fill');\n      var strokeIndex = value.indexOf('stroke');\n      var value = 'fill';\n      if (fillIndex > -1 && strokeIndex > -1 && strokeIndex < fillIndex) {\n        value = 'stroke';\n      }\n      else if (fillIndex === -1 && strokeIndex > -1) {\n        value = 'stroke';\n      }\n    }\n    else if (attr === 'href' || attr === 'xlink:href' || attr === 'font') {\n      return value;\n    }\n    else if (attr === 'imageSmoothing') {\n      return (value === 'optimizeQuality');\n    }\n    else {\n      parsed = isArray ? value.map(parseUnit) : parseUnit(value, fontSize);\n    }\n\n    return (!isArray && isNaN(parsed) ? value : parsed);\n  }\n\n  /**\n    * @private\n    */\n  function getSvgRegex(arr) {\n    return new RegExp('^(' + arr.join('|') + ')\\\\b', 'i');\n  }\n\n  /**\n   * @private\n   * @param {Object} attributes Array of attributes to parse\n   */\n  function _setStrokeFillOpacity(attributes) {\n    for (var attr in colorAttributes) {\n\n      if (typeof attributes[colorAttributes[attr]] === 'undefined' || attributes[attr] === '') {\n        continue;\n      }\n\n      if (typeof attributes[attr] === 'undefined') {\n        if (!fabric.Object.prototype[attr]) {\n          continue;\n        }\n        attributes[attr] = fabric.Object.prototype[attr];\n      }\n\n      if (attributes[attr].indexOf('url(') === 0) {\n        continue;\n      }\n\n      var color = new fabric.Color(attributes[attr]);\n      attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba();\n    }\n    return attributes;\n  }\n\n  /**\n   * @private\n   */\n  function _getMultipleNodes(doc, nodeNames) {\n    var nodeName, nodeArray = [], nodeList, i, len;\n    for (i = 0, len = nodeNames.length; i < len; i++) {\n      nodeName = nodeNames[i];\n      nodeList = doc.getElementsByTagName(nodeName);\n      nodeArray = nodeArray.concat(Array.prototype.slice.call(nodeList));\n    }\n    return nodeArray;\n  }\n\n  /**\n   * Parses \"transform\" attribute, returning an array of values\n   * @static\n   * @function\n   * @memberOf fabric\n   * @param {String} attributeValue String containing attribute value\n   * @return {Array} Array of 6 elements representing transformation matrix\n   */\n  fabric.parseTransformAttribute = (function() {\n    function rotateMatrix(matrix, args) {\n      var cos = fabric.util.cos(args[0]), sin = fabric.util.sin(args[0]),\n          x = 0, y = 0;\n      if (args.length === 3) {\n        x = args[1];\n        y = args[2];\n      }\n\n      matrix[0] = cos;\n      matrix[1] = sin;\n      matrix[2] = -sin;\n      matrix[3] = cos;\n      matrix[4] = x - (cos * x - sin * y);\n      matrix[5] = y - (sin * x + cos * y);\n    }\n\n    function scaleMatrix(matrix, args) {\n      var multiplierX = args[0],\n          multiplierY = (args.length === 2) ? args[1] : args[0];\n\n      matrix[0] = multiplierX;\n      matrix[3] = multiplierY;\n    }\n\n    function skewMatrix(matrix, args, pos) {\n      matrix[pos] = Math.tan(fabric.util.degreesToRadians(args[0]));\n    }\n\n    function translateMatrix(matrix, args) {\n      matrix[4] = args[0];\n      if (args.length === 2) {\n        matrix[5] = args[1];\n      }\n    }\n\n    // identity matrix\n    var iMatrix = fabric.iMatrix,\n\n        // == begin transform regexp\n        number = fabric.reNum,\n\n        commaWsp = fabric.commaWsp,\n\n        skewX = '(?:(skewX)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n        skewY = '(?:(skewY)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n        rotate = '(?:(rotate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                    commaWsp + '(' + number + ')' +\n                    commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n        scale = '(?:(scale)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                    commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n        translate = '(?:(translate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n                    commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n        matrix = '(?:(matrix)\\\\s*\\\\(\\\\s*' +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' + commaWsp +\n                  '(' + number + ')' +\n                  '\\\\s*\\\\))',\n\n        transform = '(?:' +\n                    matrix + '|' +\n                    translate + '|' +\n                    scale + '|' +\n                    rotate + '|' +\n                    skewX + '|' +\n                    skewY +\n                    ')',\n\n        transforms = '(?:' + transform + '(?:' + commaWsp + '*' + transform + ')*' + ')',\n\n        transformList = '^\\\\s*(?:' + transforms + '?)\\\\s*$',\n\n        // http://www.w3.org/TR/SVG/coords.html#TransformAttribute\n        reTransformList = new RegExp(transformList),\n        // == end transform regexp\n\n        reTransform = new RegExp(transform, 'g');\n\n    return function(attributeValue) {\n\n      // start with identity matrix\n      var matrix = iMatrix.concat(),\n          matrices = [];\n\n      // return if no argument was given or\n      // an argument does not match transform attribute regexp\n      if (!attributeValue || (attributeValue && !reTransformList.test(attributeValue))) {\n        return matrix;\n      }\n\n      attributeValue.replace(reTransform, function(match) {\n\n        var m = new RegExp(transform).exec(match).filter(function (match) {\n              // match !== '' && match != null\n              return (!!match);\n            }),\n            operation = m[1],\n            args = m.slice(2).map(parseFloat);\n\n        switch (operation) {\n          case 'translate':\n            translateMatrix(matrix, args);\n            break;\n          case 'rotate':\n            args[0] = fabric.util.degreesToRadians(args[0]);\n            rotateMatrix(matrix, args);\n            break;\n          case 'scale':\n            scaleMatrix(matrix, args);\n            break;\n          case 'skewX':\n            skewMatrix(matrix, args, 2);\n            break;\n          case 'skewY':\n            skewMatrix(matrix, args, 1);\n            break;\n          case 'matrix':\n            matrix = args;\n            break;\n        }\n\n        // snapshot current matrix into matrices array\n        matrices.push(matrix.concat());\n        // reset\n        matrix = iMatrix.concat();\n      });\n\n      var combinedMatrix = matrices[0];\n      while (matrices.length > 1) {\n        matrices.shift();\n        combinedMatrix = fabric.util.multiplyTransformMatrices(combinedMatrix, matrices[0]);\n      }\n      return combinedMatrix;\n    };\n  })();\n\n  /**\n   * @private\n   */\n  function parseStyleString(style, oStyle) {\n    var attr, value;\n    style.replace(/;\\s*$/, '').split(';').forEach(function (chunk) {\n      var pair = chunk.split(':');\n\n      attr = pair[0].trim().toLowerCase();\n      value =  pair[1].trim();\n\n      oStyle[attr] = value;\n    });\n  }\n\n  /**\n   * @private\n   */\n  function parseStyleObject(style, oStyle) {\n    var attr, value;\n    for (var prop in style) {\n      if (typeof style[prop] === 'undefined') {\n        continue;\n      }\n\n      attr = prop.toLowerCase();\n      value = style[prop];\n\n      oStyle[attr] = value;\n    }\n  }\n\n  /**\n   * @private\n   */\n  function getGlobalStylesForElement(element, svgUid) {\n    var styles = { };\n    for (var rule in fabric.cssRules[svgUid]) {\n      if (elementMatchesRule(element, rule.split(' '))) {\n        for (var property in fabric.cssRules[svgUid][rule]) {\n          styles[property] = fabric.cssRules[svgUid][rule][property];\n        }\n      }\n    }\n    return styles;\n  }\n\n  /**\n   * @private\n   */\n  function elementMatchesRule(element, selectors) {\n    var firstMatching, parentMatching = true;\n    //start from rightmost selector.\n    firstMatching = selectorMatches(element, selectors.pop());\n    if (firstMatching && selectors.length) {\n      parentMatching = doesSomeParentMatch(element, selectors);\n    }\n    return firstMatching && parentMatching && (selectors.length === 0);\n  }\n\n  function doesSomeParentMatch(element, selectors) {\n    var selector, parentMatching = true;\n    while (element.parentNode && element.parentNode.nodeType === 1 && selectors.length) {\n      if (parentMatching) {\n        selector = selectors.pop();\n      }\n      element = element.parentNode;\n      parentMatching = selectorMatches(element, selector);\n    }\n    return selectors.length === 0;\n  }\n\n  /**\n   * @private\n   */\n  function selectorMatches(element, selector) {\n    var nodeName = element.nodeName,\n        classNames = element.getAttribute('class'),\n        id = element.getAttribute('id'), matcher, i;\n    // i check if a selector matches slicing away part from it.\n    // if i get empty string i should match\n    matcher = new RegExp('^' + nodeName, 'i');\n    selector = selector.replace(matcher, '');\n    if (id && selector.length) {\n      matcher = new RegExp('#' + id + '(?![a-zA-Z\\\\-]+)', 'i');\n      selector = selector.replace(matcher, '');\n    }\n    if (classNames && selector.length) {\n      classNames = classNames.split(' ');\n      for (i = classNames.length; i--;) {\n        matcher = new RegExp('\\\\.' + classNames[i] + '(?![a-zA-Z\\\\-]+)', 'i');\n        selector = selector.replace(matcher, '');\n      }\n    }\n    return selector.length === 0;\n  }\n\n  /**\n   * @private\n   * to support IE8 missing getElementById on SVGdocument and on node xmlDOM\n   */\n  function elementById(doc, id) {\n    var el;\n    doc.getElementById && (el = doc.getElementById(id));\n    if (el) {\n      return el;\n    }\n    var node, i, len, nodelist = doc.getElementsByTagName('*');\n    for (i = 0, len = nodelist.length; i < len; i++) {\n      node = nodelist[i];\n      if (id === node.getAttribute('id')) {\n        return node;\n      }\n    }\n  }\n\n  /**\n   * @private\n   */\n  function parseUseDirectives(doc) {\n    var nodelist = _getMultipleNodes(doc, ['use', 'svg:use']), i = 0;\n    while (nodelist.length && i < nodelist.length) {\n      var el = nodelist[i],\n          xlinkAttribute = el.getAttribute('xlink:href') || el.getAttribute('href');\n\n      if (xlinkAttribute === null) {\n        return;\n      }\n\n      var xlink = xlinkAttribute.slice(1),\n          x = el.getAttribute('x') || 0,\n          y = el.getAttribute('y') || 0,\n          el2 = elementById(doc, xlink).cloneNode(true),\n          currentTrans = (el2.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')',\n          parentNode,\n          oldLength = nodelist.length, attr,\n          j,\n          attrs,\n          len,\n          namespace = fabric.svgNS;\n\n      applyViewboxTransform(el2);\n      if (/^svg$/i.test(el2.nodeName)) {\n        var el3 = el2.ownerDocument.createElementNS(namespace, 'g');\n        for (j = 0, attrs = el2.attributes, len = attrs.length; j < len; j++) {\n          attr = attrs.item(j);\n          el3.setAttributeNS(namespace, attr.nodeName, attr.nodeValue);\n        }\n        // el2.firstChild != null\n        while (el2.firstChild) {\n          el3.appendChild(el2.firstChild);\n        }\n        el2 = el3;\n      }\n\n      for (j = 0, attrs = el.attributes, len = attrs.length; j < len; j++) {\n        attr = attrs.item(j);\n        if (attr.nodeName === 'x' || attr.nodeName === 'y' ||\n          attr.nodeName === 'xlink:href' || attr.nodeName === 'href') {\n          continue;\n        }\n\n        if (attr.nodeName === 'transform') {\n          currentTrans = attr.nodeValue + ' ' + currentTrans;\n        }\n        else {\n          el2.setAttribute(attr.nodeName, attr.nodeValue);\n        }\n      }\n\n      el2.setAttribute('transform', currentTrans);\n      el2.setAttribute('instantiated_by_use', '1');\n      el2.removeAttribute('id');\n      parentNode = el.parentNode;\n      parentNode.replaceChild(el2, el);\n      // some browsers do not shorten nodelist after replaceChild (IE8)\n      if (nodelist.length === oldLength) {\n        i++;\n      }\n    }\n  }\n\n  // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute\n  // matches, e.g.: +14.56e-12, etc.\n  var reViewBoxAttrValue = new RegExp(\n    '^' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n    '\\\\s*(' + fabric.reNum + '+)\\\\s*' +\n    '$'\n  );\n\n  /**\n   * Add a <g> element that envelop all child elements and makes the viewbox transformMatrix descend on all elements\n   */\n  function applyViewboxTransform(element) {\n    if (!fabric.svgViewBoxElementsRegEx.test(element.nodeName)) {\n      return {};\n    }\n    var viewBoxAttr = element.getAttribute('viewBox'),\n        scaleX = 1,\n        scaleY = 1,\n        minX = 0,\n        minY = 0,\n        viewBoxWidth, viewBoxHeight, matrix, el,\n        widthAttr = element.getAttribute('width'),\n        heightAttr = element.getAttribute('height'),\n        x = element.getAttribute('x') || 0,\n        y = element.getAttribute('y') || 0,\n        preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '',\n        missingViewBox = (!viewBoxAttr || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue))),\n        missingDimAttr = (!widthAttr || !heightAttr || widthAttr === '100%' || heightAttr === '100%'),\n        toBeParsed = missingViewBox && missingDimAttr,\n        parsedDim = { }, translateMatrix = '', widthDiff = 0, heightDiff = 0;\n\n    parsedDim.width = 0;\n    parsedDim.height = 0;\n    parsedDim.toBeParsed = toBeParsed;\n\n    if (missingViewBox) {\n      if (((x || y) && element.parentNode && element.parentNode.nodeName !== '#document')) {\n        translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') ';\n        matrix = (element.getAttribute('transform') || '') + translateMatrix;\n        element.setAttribute('transform', matrix);\n        element.removeAttribute('x');\n        element.removeAttribute('y');\n      }\n    }\n\n    if (toBeParsed) {\n      return parsedDim;\n    }\n\n    if (missingViewBox) {\n      parsedDim.width = parseUnit(widthAttr);\n      parsedDim.height = parseUnit(heightAttr);\n      // set a transform for elements that have x y and are inner(only) SVGs\n      return parsedDim;\n    }\n    minX = -parseFloat(viewBoxAttr[1]);\n    minY = -parseFloat(viewBoxAttr[2]);\n    viewBoxWidth = parseFloat(viewBoxAttr[3]);\n    viewBoxHeight = parseFloat(viewBoxAttr[4]);\n    parsedDim.minX = minX;\n    parsedDim.minY = minY;\n    parsedDim.viewBoxWidth = viewBoxWidth;\n    parsedDim.viewBoxHeight = viewBoxHeight;\n    if (!missingDimAttr) {\n      parsedDim.width = parseUnit(widthAttr);\n      parsedDim.height = parseUnit(heightAttr);\n      scaleX = parsedDim.width / viewBoxWidth;\n      scaleY = parsedDim.height / viewBoxHeight;\n    }\n    else {\n      parsedDim.width = viewBoxWidth;\n      parsedDim.height = viewBoxHeight;\n    }\n\n    // default is to preserve aspect ratio\n    preserveAspectRatio = fabric.util.parsePreserveAspectRatioAttribute(preserveAspectRatio);\n    if (preserveAspectRatio.alignX !== 'none') {\n      //translate all container for the effect of Mid, Min, Max\n      if (preserveAspectRatio.meetOrSlice === 'meet') {\n        scaleY = scaleX = (scaleX > scaleY ? scaleY : scaleX);\n        // calculate additional translation to move the viewbox\n      }\n      if (preserveAspectRatio.meetOrSlice === 'slice') {\n        scaleY = scaleX = (scaleX > scaleY ? scaleX : scaleY);\n        // calculate additional translation to move the viewbox\n      }\n      widthDiff = parsedDim.width - viewBoxWidth * scaleX;\n      heightDiff = parsedDim.height - viewBoxHeight * scaleX;\n      if (preserveAspectRatio.alignX === 'Mid') {\n        widthDiff /= 2;\n      }\n      if (preserveAspectRatio.alignY === 'Mid') {\n        heightDiff /= 2;\n      }\n      if (preserveAspectRatio.alignX === 'Min') {\n        widthDiff = 0;\n      }\n      if (preserveAspectRatio.alignY === 'Min') {\n        heightDiff = 0;\n      }\n    }\n\n    if (scaleX === 1 && scaleY === 1 && minX === 0 && minY === 0 && x === 0 && y === 0) {\n      return parsedDim;\n    }\n    if ((x || y) && element.parentNode.nodeName !== '#document') {\n      translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') ';\n    }\n\n    matrix = translateMatrix + ' matrix(' + scaleX +\n                  ' 0' +\n                  ' 0 ' +\n                  scaleY + ' ' +\n                  (minX * scaleX + widthDiff) + ' ' +\n                  (minY * scaleY + heightDiff) + ') ';\n    // seems unused.\n    // parsedDim.viewboxTransform = fabric.parseTransformAttribute(matrix);\n    if (element.nodeName === 'svg') {\n      el = element.ownerDocument.createElementNS(fabric.svgNS, 'g');\n      // element.firstChild != null\n      while (element.firstChild) {\n        el.appendChild(element.firstChild);\n      }\n      element.appendChild(el);\n    }\n    else {\n      el = element;\n      el.removeAttribute('x');\n      el.removeAttribute('y');\n      matrix = el.getAttribute('transform') + matrix;\n    }\n    el.setAttribute('transform', matrix);\n    return parsedDim;\n  }\n\n  function hasAncestorWithNodeName(element, nodeName) {\n    while (element && (element = element.parentNode)) {\n      if (element.nodeName && nodeName.test(element.nodeName.replace('svg:', ''))\n        && !element.getAttribute('instantiated_by_use')) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback\n   * @static\n   * @function\n   * @memberOf fabric\n   * @param {SVGDocument} doc SVG document to parse\n   * @param {Function} callback Callback to call when parsing is finished;\n   * It's being passed an array of elements (parsed from a document).\n   * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n   * @param {Object} [parsingOptions] options for parsing document\n   * @param {String} [parsingOptions.crossOrigin] crossOrigin settings\n   */\n  fabric.parseSVGDocument = function(doc, callback, reviver, parsingOptions) {\n    if (!doc) {\n      return;\n    }\n\n    parseUseDirectives(doc);\n\n    var svgUid =  fabric.Object.__uid++, i, len,\n        options = applyViewboxTransform(doc),\n        descendants = fabric.util.toArray(doc.getElementsByTagName('*'));\n    options.crossOrigin = parsingOptions && parsingOptions.crossOrigin;\n    options.svgUid = svgUid;\n\n    if (descendants.length === 0 && fabric.isLikelyNode) {\n      // we're likely in node, where \"o3-xml\" library fails to gEBTN(\"*\")\n      // https://github.com/ajaxorg/node-o3-xml/issues/21\n      descendants = doc.selectNodes('//*[name(.)!=\"svg\"]');\n      var arr = [];\n      for (i = 0, len = descendants.length; i < len; i++) {\n        arr[i] = descendants[i];\n      }\n      descendants = arr;\n    }\n\n    var elements = descendants.filter(function(el) {\n      applyViewboxTransform(el);\n      return fabric.svgValidTagNamesRegEx.test(el.nodeName.replace('svg:', '')) &&\n            !hasAncestorWithNodeName(el, fabric.svgInvalidAncestorsRegEx); // http://www.w3.org/TR/SVG/struct.html#DefsElement\n    });\n    if (!elements || (elements && !elements.length)) {\n      callback && callback([], {});\n      return;\n    }\n    var clipPaths = { };\n    descendants.filter(function(el) {\n      return el.nodeName.replace('svg:', '') === 'clipPath';\n    }).forEach(function(el) {\n      var id = el.getAttribute('id');\n      clipPaths[id] = fabric.util.toArray(el.getElementsByTagName('*')).filter(function(el) {\n        return fabric.svgValidTagNamesRegEx.test(el.nodeName.replace('svg:', ''));\n      });\n    });\n    fabric.gradientDefs[svgUid] = fabric.getGradientDefs(doc);\n    fabric.cssRules[svgUid] = fabric.getCSSRules(doc);\n    fabric.clipPaths[svgUid] = clipPaths;\n    // Precedence of rules:   style > class > attribute\n    fabric.parseElements(elements, function(instances, elements) {\n      if (callback) {\n        callback(instances, options, elements, descendants);\n        delete fabric.gradientDefs[svgUid];\n        delete fabric.cssRules[svgUid];\n        delete fabric.clipPaths[svgUid];\n      }\n    }, clone(options), reviver, parsingOptions);\n  };\n\n  function recursivelyParseGradientsXlink(doc, gradient) {\n    var gradientsAttrs = ['gradientTransform', 'x1', 'x2', 'y1', 'y2', 'gradientUnits', 'cx', 'cy', 'r', 'fx', 'fy'],\n        xlinkAttr = 'xlink:href',\n        xLink = gradient.getAttribute(xlinkAttr).slice(1),\n        referencedGradient = elementById(doc, xLink);\n    if (referencedGradient && referencedGradient.getAttribute(xlinkAttr)) {\n      recursivelyParseGradientsXlink(doc, referencedGradient);\n    }\n    gradientsAttrs.forEach(function(attr) {\n      if (referencedGradient && !gradient.hasAttribute(attr) && referencedGradient.hasAttribute(attr)) {\n        gradient.setAttribute(attr, referencedGradient.getAttribute(attr));\n      }\n    });\n    if (!gradient.children.length) {\n      var referenceClone = referencedGradient.cloneNode(true);\n      while (referenceClone.firstChild) {\n        gradient.appendChild(referenceClone.firstChild);\n      }\n    }\n    gradient.removeAttribute(xlinkAttr);\n  }\n\n  var reFontDeclaration = new RegExp(\n    '(normal|italic)?\\\\s*(normal|small-caps)?\\\\s*' +\n    '(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\\\s*(' +\n      fabric.reNum +\n    '(?:px|cm|mm|em|pt|pc|in)*)(?:\\\\/(normal|' + fabric.reNum + '))?\\\\s+(.*)');\n\n  extend(fabric, {\n    /**\n     * Parses a short font declaration, building adding its properties to a style object\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {String} value font declaration\n     * @param {Object} oStyle definition\n     */\n    parseFontDeclaration: function(value, oStyle) {\n      var match = value.match(reFontDeclaration);\n\n      if (!match) {\n        return;\n      }\n      var fontStyle = match[1],\n          // font variant is not used\n          // fontVariant = match[2],\n          fontWeight = match[3],\n          fontSize = match[4],\n          lineHeight = match[5],\n          fontFamily = match[6];\n\n      if (fontStyle) {\n        oStyle.fontStyle = fontStyle;\n      }\n      if (fontWeight) {\n        oStyle.fontWeight = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight);\n      }\n      if (fontSize) {\n        oStyle.fontSize = parseUnit(fontSize);\n      }\n      if (fontFamily) {\n        oStyle.fontFamily = fontFamily;\n      }\n      if (lineHeight) {\n        oStyle.lineHeight = lineHeight === 'normal' ? 1 : lineHeight;\n      }\n    },\n\n    /**\n     * Parses an SVG document, returning all of the gradient declarations found in it\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {SVGDocument} doc SVG document to parse\n     * @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition element\n     */\n    getGradientDefs: function(doc) {\n      var tagArray = [\n            'linearGradient',\n            'radialGradient',\n            'svg:linearGradient',\n            'svg:radialGradient'],\n          elList = _getMultipleNodes(doc, tagArray),\n          el, j = 0, gradientDefs = { };\n      j = elList.length;\n      while (j--) {\n        el = elList[j];\n        if (el.getAttribute('xlink:href')) {\n          recursivelyParseGradientsXlink(doc, el);\n        }\n        gradientDefs[el.getAttribute('id')] = el;\n      }\n      return gradientDefs;\n    },\n\n    /**\n     * Returns an object of attributes' name/value, given element and an array of attribute names;\n     * Parses parent \"g\" nodes recursively upwards.\n     * @static\n     * @memberOf fabric\n     * @param {DOMElement} element Element to parse\n     * @param {Array} attributes Array of attributes to parse\n     * @return {Object} object containing parsed attributes' names/values\n     */\n    parseAttributes: function(element, attributes, svgUid) {\n\n      if (!element) {\n        return;\n      }\n\n      var value,\n          parentAttributes = { },\n          fontSize, parentFontSize;\n\n      if (typeof svgUid === 'undefined') {\n        svgUid = element.getAttribute('svgUid');\n      }\n      // if there's a parent container (`g` or `a` or `symbol` node), parse its attributes recursively upwards\n      if (element.parentNode && fabric.svgValidParentsRegEx.test(element.parentNode.nodeName)) {\n        parentAttributes = fabric.parseAttributes(element.parentNode, attributes, svgUid);\n      }\n\n      var ownAttributes = attributes.reduce(function(memo, attr) {\n        value = element.getAttribute(attr);\n        if (value) { // eslint-disable-line\n          memo[attr] = value;\n        }\n        return memo;\n      }, { });\n      // add values parsed from style, which take precedence over attributes\n      // (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)\n      var cssAttrs = extend(\n        getGlobalStylesForElement(element, svgUid),\n        fabric.parseStyleAttribute(element)\n      );\n      ownAttributes = extend(\n        ownAttributes,\n        cssAttrs\n      );\n      if (cssAttrs[cPath]) {\n        element.setAttribute(cPath, cssAttrs[cPath]);\n      }\n      fontSize = parentFontSize = parentAttributes.fontSize || fabric.Text.DEFAULT_SVG_FONT_SIZE;\n      if (ownAttributes[fSize]) {\n        // looks like the minimum should be 9px when dealing with ems. this is what looks like in browsers.\n        ownAttributes[fSize] = fontSize = parseUnit(ownAttributes[fSize], parentFontSize);\n      }\n\n      var normalizedAttr, normalizedValue, normalizedStyle = {};\n      for (var attr in ownAttributes) {\n        normalizedAttr = normalizeAttr(attr);\n        normalizedValue = normalizeValue(normalizedAttr, ownAttributes[attr], parentAttributes, fontSize);\n        normalizedStyle[normalizedAttr] = normalizedValue;\n      }\n      if (normalizedStyle && normalizedStyle.font) {\n        fabric.parseFontDeclaration(normalizedStyle.font, normalizedStyle);\n      }\n      var mergedAttrs = extend(parentAttributes, normalizedStyle);\n      return fabric.svgValidParentsRegEx.test(element.nodeName) ? mergedAttrs : _setStrokeFillOpacity(mergedAttrs);\n    },\n\n    /**\n     * Transforms an array of svg elements to corresponding fabric.* instances\n     * @static\n     * @memberOf fabric\n     * @param {Array} elements Array of elements to parse\n     * @param {Function} callback Being passed an array of fabric instances (transformed from SVG elements)\n     * @param {Object} [options] Options object\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     */\n    parseElements: function(elements, callback, options, reviver, parsingOptions) {\n      new fabric.ElementsParser(elements, callback, options, reviver, parsingOptions).parse();\n    },\n\n    /**\n     * Parses \"style\" attribute, retuning an object with values\n     * @static\n     * @memberOf fabric\n     * @param {SVGElement} element Element to parse\n     * @return {Object} Objects with values parsed from style attribute of an element\n     */\n    parseStyleAttribute: function(element) {\n      var oStyle = { },\n          style = element.getAttribute('style');\n\n      if (!style) {\n        return oStyle;\n      }\n\n      if (typeof style === 'string') {\n        parseStyleString(style, oStyle);\n      }\n      else {\n        parseStyleObject(style, oStyle);\n      }\n\n      return oStyle;\n    },\n\n    /**\n     * Parses \"points\" attribute, returning an array of values\n     * @static\n     * @memberOf fabric\n     * @param {String} points points attribute string\n     * @return {Array} array of points\n     */\n    parsePointsAttribute: function(points) {\n\n      // points attribute is required and must not be empty\n      if (!points) {\n        return null;\n      }\n\n      // replace commas with whitespace and remove bookending whitespace\n      points = points.replace(/,/g, ' ').trim();\n\n      points = points.split(/\\s+/);\n      var parsedPoints = [], i, len;\n\n      for (i = 0, len = points.length; i < len; i += 2) {\n        parsedPoints.push({\n          x: parseFloat(points[i]),\n          y: parseFloat(points[i + 1])\n        });\n      }\n\n      // odd number of points is an error\n      // if (parsedPoints.length % 2 !== 0) {\n      //   return null;\n      // }\n\n      return parsedPoints;\n    },\n\n    /**\n     * Returns CSS rules for a given SVG document\n     * @static\n     * @function\n     * @memberOf fabric\n     * @param {SVGDocument} doc SVG document to parse\n     * @return {Object} CSS rules of this document\n     */\n    getCSSRules: function(doc) {\n      var styles = doc.getElementsByTagName('style'), i, len,\n          allRules = { }, rules;\n\n      // very crude parsing of style contents\n      for (i = 0, len = styles.length; i < len; i++) {\n        var styleContents = styles[i].textContent;\n\n        // remove comments\n        styleContents = styleContents.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n        if (styleContents.trim() === '') {\n          continue;\n        }\n        // recovers all the rule in this form `body { style code... }`\n        // rules = styleContents.match(/[^{]*\\{[\\s\\S]*?\\}/g);\n        rules = styleContents.split('}');\n        // remove empty rules.\n        rules = rules.filter(function(rule) { return rule.trim(); });\n        // at this point we have hopefully an array of rules `body { style code... `\n        // eslint-disable-next-line no-loop-func\n        rules.forEach(function(rule) {\n\n          var match = rule.split('{'),\n              ruleObj = { }, declaration = match[1].trim(),\n              propertyValuePairs = declaration.split(';').filter(function(pair) { return pair.trim(); });\n\n          for (i = 0, len = propertyValuePairs.length; i < len; i++) {\n            var pair = propertyValuePairs[i].split(':'),\n                property = pair[0].trim(),\n                value = pair[1].trim();\n            ruleObj[property] = value;\n          }\n          rule = match[0].trim();\n          rule.split(',').forEach(function(_rule) {\n            _rule = _rule.replace(/^svg/i, '').trim();\n            if (_rule === '') {\n              return;\n            }\n            if (allRules[_rule]) {\n              fabric.util.object.extend(allRules[_rule], ruleObj);\n            }\n            else {\n              allRules[_rule] = fabric.util.object.clone(ruleObj);\n            }\n          });\n        });\n      }\n      return allRules;\n    },\n\n    /**\n     * Takes url corresponding to an SVG document, and parses it into a set of fabric objects.\n     * Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy)\n     * @memberOf fabric\n     * @param {String} url\n     * @param {Function} callback\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     * @param {Object} [options] Object containing options for parsing\n     * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources\n     */\n    loadSVGFromURL: function(url, callback, reviver, options) {\n\n      url = url.replace(/^\\n\\s*/, '').trim();\n      new fabric.util.request(url, {\n        method: 'get',\n        onComplete: onComplete\n      });\n\n      function onComplete(r) {\n\n        var xml = r.responseXML;\n        if (!xml || !xml.documentElement) {\n          callback && callback(null);\n          return false;\n        }\n\n        fabric.parseSVGDocument(xml.documentElement, function (results, _options, elements, allElements) {\n          callback && callback(results, _options, elements, allElements);\n        }, reviver, options);\n      }\n    },\n\n    /**\n     * Takes string corresponding to an SVG document, and parses it into a set of fabric objects\n     * @memberOf fabric\n     * @param {String} string\n     * @param {Function} callback\n     * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n     * @param {Object} [options] Object containing options for parsing\n     * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources\n     */\n    loadSVGFromString: function(string, callback, reviver, options) {\n      var parser = new fabric.window.DOMParser(),\n          doc = parser.parseFromString(string.trim(), 'text/xml');\n      fabric.parseSVGDocument(doc.documentElement, function (results, _options, elements, allElements) {\n        callback(results, _options, elements, allElements);\n      }, reviver, options);\n    }\n  });\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.ElementsParser = function(elements, callback, options, reviver, parsingOptions, doc) {\n  this.elements = elements;\n  this.callback = callback;\n  this.options = options;\n  this.reviver = reviver;\n  this.svgUid = (options && options.svgUid) || 0;\n  this.parsingOptions = parsingOptions;\n  this.regexUrl = /^url\\(['\"]?#([^'\"]+)['\"]?\\)/g;\n  this.doc = doc;\n};\n\n(function(proto) {\n  proto.parse = function() {\n    this.instances = new Array(this.elements.length);\n    this.numElements = this.elements.length;\n    this.createObjects();\n  };\n\n  proto.createObjects = function() {\n    var _this = this;\n    this.elements.forEach(function(element, i) {\n      element.setAttribute('svgUid', _this.svgUid);\n      _this.createObject(element, i);\n    });\n  };\n\n  proto.findTag = function(el) {\n    return fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))];\n  };\n\n  proto.createObject = function(el, index) {\n    var klass = this.findTag(el);\n    if (klass && klass.fromElement) {\n      try {\n        klass.fromElement(el, this.createCallback(index, el), this.options);\n      }\n      catch (err) {\n        fabric.log(err);\n      }\n    }\n    else {\n      this.checkIfDone();\n    }\n  };\n\n  proto.createCallback = function(index, el) {\n    var _this = this;\n    return function(obj) {\n      var _options;\n      _this.resolveGradient(obj, el, 'fill');\n      _this.resolveGradient(obj, el, 'stroke');\n      if (obj instanceof fabric.Image && obj._originalElement) {\n        _options = obj.parsePreserveAspectRatioAttribute(el);\n      }\n      obj._removeTransformMatrix(_options);\n      _this.resolveClipPath(obj, el);\n      _this.reviver && _this.reviver(el, obj);\n      _this.instances[index] = obj;\n      _this.checkIfDone();\n    };\n  };\n\n  proto.extractPropertyDefinition = function(obj, property, storage) {\n    var value = obj[property], regex = this.regexUrl;\n    if (!regex.test(value)) {\n      return;\n    }\n    regex.lastIndex = 0;\n    var id = regex.exec(value)[1];\n    regex.lastIndex = 0;\n    return fabric[storage][this.svgUid][id];\n  };\n\n  proto.resolveGradient = function(obj, el, property) {\n    var gradientDef = this.extractPropertyDefinition(obj, property, 'gradientDefs');\n    if (gradientDef) {\n      var opacityAttr = el.getAttribute(property + '-opacity');\n      var gradient = fabric.Gradient.fromElement(gradientDef, obj, opacityAttr, this.options);\n      obj.set(property, gradient);\n    }\n  };\n\n  proto.createClipPathCallback = function(obj, container) {\n    return function(_newObj) {\n      _newObj._removeTransformMatrix();\n      _newObj.fillRule = _newObj.clipRule;\n      container.push(_newObj);\n    };\n  };\n\n  proto.resolveClipPath = function(obj, usingElement) {\n    var clipPath = this.extractPropertyDefinition(obj, 'clipPath', 'clipPaths'),\n        element, klass, objTransformInv, container, gTransform, options;\n    if (clipPath) {\n      container = [];\n      objTransformInv = fabric.util.invertTransform(obj.calcTransformMatrix());\n      // move the clipPath tag as sibling to the real element that is using it\n      var clipPathTag = clipPath[0].parentNode;\n      var clipPathOwner = usingElement;\n      while (clipPathOwner.parentNode && clipPathOwner.getAttribute('clip-path') !== obj.clipPath) {\n        clipPathOwner = clipPathOwner.parentNode;\n      }\n      clipPathOwner.parentNode.appendChild(clipPathTag);\n      for (var i = 0; i < clipPath.length; i++) {\n        element = clipPath[i];\n        klass = this.findTag(element);\n        klass.fromElement(\n          element,\n          this.createClipPathCallback(obj, container),\n          this.options\n        );\n      }\n      if (container.length === 1) {\n        clipPath = container[0];\n      }\n      else {\n        clipPath = new fabric.Group(container);\n      }\n      gTransform = fabric.util.multiplyTransformMatrices(\n        objTransformInv,\n        clipPath.calcTransformMatrix()\n      );\n      if (clipPath.clipPath) {\n        this.resolveClipPath(clipPath, clipPathOwner);\n      }\n      var options = fabric.util.qrDecompose(gTransform);\n      clipPath.flipX = false;\n      clipPath.flipY = false;\n      clipPath.set('scaleX', options.scaleX);\n      clipPath.set('scaleY', options.scaleY);\n      clipPath.angle = options.angle;\n      clipPath.skewX = options.skewX;\n      clipPath.skewY = 0;\n      clipPath.setPositionByOrigin({ x: options.translateX, y: options.translateY }, 'center', 'center');\n      obj.clipPath = clipPath;\n    }\n    else {\n      // if clip-path does not resolve to any element, delete the property.\n      delete obj.clipPath;\n    }\n  };\n\n  proto.checkIfDone = function() {\n    if (--this.numElements === 0) {\n      this.instances = this.instances.filter(function(el) {\n        // eslint-disable-next-line no-eq-null, eqeqeq\n        return el != null;\n      });\n      this.callback(this.instances, this.elements);\n    }\n  };\n})(fabric.ElementsParser.prototype);\n\n\n(function(global) {\n\n  'use strict';\n\n  /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Point) {\n    fabric.warn('fabric.Point is already defined');\n    return;\n  }\n\n  fabric.Point = Point;\n\n  /**\n   * Point class\n   * @class fabric.Point\n   * @memberOf fabric\n   * @constructor\n   * @param {Number} x\n   * @param {Number} y\n   * @return {fabric.Point} thisArg\n   */\n  function Point(x, y) {\n    this.x = x;\n    this.y = y;\n  }\n\n  Point.prototype = /** @lends fabric.Point.prototype */ {\n\n    type: 'point',\n\n    constructor: Point,\n\n    /**\n     * Adds another point to this one and returns another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point} new Point instance with added values\n     */\n    add: function (that) {\n      return new Point(this.x + that.x, this.y + that.y);\n    },\n\n    /**\n     * Adds another point to this one\n     * @param {fabric.Point} that\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    addEquals: function (that) {\n      this.x += that.x;\n      this.y += that.y;\n      return this;\n    },\n\n    /**\n     * Adds value to this point and returns a new one\n     * @param {Number} scalar\n     * @return {fabric.Point} new Point with added value\n     */\n    scalarAdd: function (scalar) {\n      return new Point(this.x + scalar, this.y + scalar);\n    },\n\n    /**\n     * Adds value to this point\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    scalarAddEquals: function (scalar) {\n      this.x += scalar;\n      this.y += scalar;\n      return this;\n    },\n\n    /**\n     * Subtracts another point from this point and returns a new one\n     * @param {fabric.Point} that\n     * @return {fabric.Point} new Point object with subtracted values\n     */\n    subtract: function (that) {\n      return new Point(this.x - that.x, this.y - that.y);\n    },\n\n    /**\n     * Subtracts another point from this point\n     * @param {fabric.Point} that\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    subtractEquals: function (that) {\n      this.x -= that.x;\n      this.y -= that.y;\n      return this;\n    },\n\n    /**\n     * Subtracts value from this point and returns a new one\n     * @param {Number} scalar\n     * @return {fabric.Point}\n     */\n    scalarSubtract: function (scalar) {\n      return new Point(this.x - scalar, this.y - scalar);\n    },\n\n    /**\n     * Subtracts value from this point\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    scalarSubtractEquals: function (scalar) {\n      this.x -= scalar;\n      this.y -= scalar;\n      return this;\n    },\n\n    /**\n     * Multiplies this point by a value and returns a new one\n     * TODO: rename in scalarMultiply in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point}\n     */\n    multiply: function (scalar) {\n      return new Point(this.x * scalar, this.y * scalar);\n    },\n\n    /**\n     * Multiplies this point by a value\n     * TODO: rename in scalarMultiplyEquals in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    multiplyEquals: function (scalar) {\n      this.x *= scalar;\n      this.y *= scalar;\n      return this;\n    },\n\n    /**\n     * Divides this point by a value and returns a new one\n     * TODO: rename in scalarDivide in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point}\n     */\n    divide: function (scalar) {\n      return new Point(this.x / scalar, this.y / scalar);\n    },\n\n    /**\n     * Divides this point by a value\n     * TODO: rename in scalarDivideEquals in 2.0\n     * @param {Number} scalar\n     * @return {fabric.Point} thisArg\n     * @chainable\n     */\n    divideEquals: function (scalar) {\n      this.x /= scalar;\n      this.y /= scalar;\n      return this;\n    },\n\n    /**\n     * Returns true if this point is equal to another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    eq: function (that) {\n      return (this.x === that.x && this.y === that.y);\n    },\n\n    /**\n     * Returns true if this point is less than another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    lt: function (that) {\n      return (this.x < that.x && this.y < that.y);\n    },\n\n    /**\n     * Returns true if this point is less than or equal to another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    lte: function (that) {\n      return (this.x <= that.x && this.y <= that.y);\n    },\n\n    /**\n\n     * Returns true if this point is greater another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    gt: function (that) {\n      return (this.x > that.x && this.y > that.y);\n    },\n\n    /**\n     * Returns true if this point is greater than or equal to another one\n     * @param {fabric.Point} that\n     * @return {Boolean}\n     */\n    gte: function (that) {\n      return (this.x >= that.x && this.y >= that.y);\n    },\n\n    /**\n     * Returns new point which is the result of linear interpolation with this one and another one\n     * @param {fabric.Point} that\n     * @param {Number} t , position of interpolation, between 0 and 1 default 0.5\n     * @return {fabric.Point}\n     */\n    lerp: function (that, t) {\n      if (typeof t === 'undefined') {\n        t = 0.5;\n      }\n      t = Math.max(Math.min(1, t), 0);\n      return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t);\n    },\n\n    /**\n     * Returns distance from this point and another one\n     * @param {fabric.Point} that\n     * @return {Number}\n     */\n    distanceFrom: function (that) {\n      var dx = this.x - that.x,\n          dy = this.y - that.y;\n      return Math.sqrt(dx * dx + dy * dy);\n    },\n\n    /**\n     * Returns the point between this point and another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point}\n     */\n    midPointFrom: function (that) {\n      return this.lerp(that);\n    },\n\n    /**\n     * Returns a new point which is the min of this and another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point}\n     */\n    min: function (that) {\n      return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y));\n    },\n\n    /**\n     * Returns a new point which is the max of this and another one\n     * @param {fabric.Point} that\n     * @return {fabric.Point}\n     */\n    max: function (that) {\n      return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y));\n    },\n\n    /**\n     * Returns string representation of this point\n     * @return {String}\n     */\n    toString: function () {\n      return this.x + ',' + this.y;\n    },\n\n    /**\n     * Sets x/y of this point\n     * @param {Number} x\n     * @param {Number} y\n     * @chainable\n     */\n    setXY: function (x, y) {\n      this.x = x;\n      this.y = y;\n      return this;\n    },\n\n    /**\n     * Sets x of this point\n     * @param {Number} x\n     * @chainable\n     */\n    setX: function (x) {\n      this.x = x;\n      return this;\n    },\n\n    /**\n     * Sets y of this point\n     * @param {Number} y\n     * @chainable\n     */\n    setY: function (y) {\n      this.y = y;\n      return this;\n    },\n\n    /**\n     * Sets x/y of this point from another point\n     * @param {fabric.Point} that\n     * @chainable\n     */\n    setFromPoint: function (that) {\n      this.x = that.x;\n      this.y = that.y;\n      return this;\n    },\n\n    /**\n     * Swaps x/y of this point and another point\n     * @param {fabric.Point} that\n     */\n    swap: function (that) {\n      var x = this.x,\n          y = this.y;\n      this.x = that.x;\n      this.y = that.y;\n      that.x = x;\n      that.y = y;\n    },\n\n    /**\n     * return a cloned instance of the point\n     * @return {fabric.Point}\n     */\n    clone: function () {\n      return new Point(this.x, this.y);\n    }\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Intersection) {\n    fabric.warn('fabric.Intersection is already defined');\n    return;\n  }\n\n  /**\n   * Intersection class\n   * @class fabric.Intersection\n   * @memberOf fabric\n   * @constructor\n   */\n  function Intersection(status) {\n    this.status = status;\n    this.points = [];\n  }\n\n  fabric.Intersection = Intersection;\n\n  fabric.Intersection.prototype = /** @lends fabric.Intersection.prototype */ {\n\n    constructor: Intersection,\n\n    /**\n     * Appends a point to intersection\n     * @param {fabric.Point} point\n     * @return {fabric.Intersection} thisArg\n     * @chainable\n     */\n    appendPoint: function (point) {\n      this.points.push(point);\n      return this;\n    },\n\n    /**\n     * Appends points to intersection\n     * @param {Array} points\n     * @return {fabric.Intersection} thisArg\n     * @chainable\n     */\n    appendPoints: function (points) {\n      this.points = this.points.concat(points);\n      return this;\n    }\n  };\n\n  /**\n   * Checks if one line intersects another\n   * TODO: rename in intersectSegmentSegment\n   * @static\n   * @param {fabric.Point} a1\n   * @param {fabric.Point} a2\n   * @param {fabric.Point} b1\n   * @param {fabric.Point} b2\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) {\n    var result,\n        uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),\n        ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),\n        uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);\n    if (uB !== 0) {\n      var ua = uaT / uB,\n          ub = ubT / uB;\n      if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {\n        result = new Intersection('Intersection');\n        result.appendPoint(new fabric.Point(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)));\n      }\n      else {\n        result = new Intersection();\n      }\n    }\n    else {\n      if (uaT === 0 || ubT === 0) {\n        result = new Intersection('Coincident');\n      }\n      else {\n        result = new Intersection('Parallel');\n      }\n    }\n    return result;\n  };\n\n  /**\n   * Checks if line intersects polygon\n   * TODO: rename in intersectSegmentPolygon\n   * fix detection of coincident\n   * @static\n   * @param {fabric.Point} a1\n   * @param {fabric.Point} a2\n   * @param {Array} points\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectLinePolygon = function(a1, a2, points) {\n    var result = new Intersection(),\n        length = points.length,\n        b1, b2, inter, i;\n\n    for (i = 0; i < length; i++) {\n      b1 = points[i];\n      b2 = points[(i + 1) % length];\n      inter = Intersection.intersectLineLine(a1, a2, b1, b2);\n\n      result.appendPoints(inter.points);\n    }\n    if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n    return result;\n  };\n\n  /**\n   * Checks if polygon intersects another polygon\n   * @static\n   * @param {Array} points1\n   * @param {Array} points2\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectPolygonPolygon = function (points1, points2) {\n    var result = new Intersection(),\n        length = points1.length, i;\n\n    for (i = 0; i < length; i++) {\n      var a1 = points1[i],\n          a2 = points1[(i + 1) % length],\n          inter = Intersection.intersectLinePolygon(a1, a2, points2);\n\n      result.appendPoints(inter.points);\n    }\n    if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n    return result;\n  };\n\n  /**\n   * Checks if polygon intersects rectangle\n   * @static\n   * @param {Array} points\n   * @param {fabric.Point} r1\n   * @param {fabric.Point} r2\n   * @return {fabric.Intersection}\n   */\n  fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) {\n    var min = r1.min(r2),\n        max = r1.max(r2),\n        topRight = new fabric.Point(max.x, min.y),\n        bottomLeft = new fabric.Point(min.x, max.y),\n        inter1 = Intersection.intersectLinePolygon(min, topRight, points),\n        inter2 = Intersection.intersectLinePolygon(topRight, max, points),\n        inter3 = Intersection.intersectLinePolygon(max, bottomLeft, points),\n        inter4 = Intersection.intersectLinePolygon(bottomLeft, min, points),\n        result = new Intersection();\n\n    result.appendPoints(inter1.points);\n    result.appendPoints(inter2.points);\n    result.appendPoints(inter3.points);\n    result.appendPoints(inter4.points);\n\n    if (result.points.length > 0) {\n      result.status = 'Intersection';\n    }\n    return result;\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Color) {\n    fabric.warn('fabric.Color is already defined.');\n    return;\n  }\n\n  /**\n   * Color class\n   * The purpose of {@link fabric.Color} is to abstract and encapsulate common color operations;\n   * {@link fabric.Color} is a constructor and creates instances of {@link fabric.Color} objects.\n   *\n   * @class fabric.Color\n   * @param {String} color optional in hex or rgb(a) or hsl format or from known color list\n   * @return {fabric.Color} thisArg\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#colors}\n   */\n  function Color(color) {\n    if (!color) {\n      this.setSource([0, 0, 0, 1]);\n    }\n    else {\n      this._tryParsingColor(color);\n    }\n  }\n\n  fabric.Color = Color;\n\n  fabric.Color.prototype = /** @lends fabric.Color.prototype */ {\n\n    /**\n     * @private\n     * @param {String|Array} color Color value to parse\n     */\n    _tryParsingColor: function(color) {\n      var source;\n\n      if (color in Color.colorNameMap) {\n        color = Color.colorNameMap[color];\n      }\n\n      if (color === 'transparent') {\n        source = [255, 255, 255, 0];\n      }\n\n      if (!source) {\n        source = Color.sourceFromHex(color);\n      }\n      if (!source) {\n        source = Color.sourceFromRgb(color);\n      }\n      if (!source) {\n        source = Color.sourceFromHsl(color);\n      }\n      if (!source) {\n        //if color is not recognize let's make black as canvas does\n        source = [0, 0, 0, 1];\n      }\n      if (source) {\n        this.setSource(source);\n      }\n    },\n\n    /**\n     * Adapted from <a href=\"https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html\">https://github.com/mjijackson</a>\n     * @private\n     * @param {Number} r Red color value\n     * @param {Number} g Green color value\n     * @param {Number} b Blue color value\n     * @return {Array} Hsl color\n     */\n    _rgbToHsl: function(r, g, b) {\n      r /= 255; g /= 255; b /= 255;\n\n      var h, s, l,\n          max = fabric.util.array.max([r, g, b]),\n          min = fabric.util.array.min([r, g, b]);\n\n      l = (max + min) / 2;\n\n      if (max === min) {\n        h = s = 0; // achromatic\n      }\n      else {\n        var d = max - min;\n        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n        switch (max) {\n          case r:\n            h = (g - b) / d + (g < b ? 6 : 0);\n            break;\n          case g:\n            h = (b - r) / d + 2;\n            break;\n          case b:\n            h = (r - g) / d + 4;\n            break;\n        }\n        h /= 6;\n      }\n\n      return [\n        Math.round(h * 360),\n        Math.round(s * 100),\n        Math.round(l * 100)\n      ];\n    },\n\n    /**\n     * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n     * @return {Array}\n     */\n    getSource: function() {\n      return this._source;\n    },\n\n    /**\n     * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n     * @param {Array} source\n     */\n    setSource: function(source) {\n      this._source = source;\n    },\n\n    /**\n     * Returns color representation in RGB format\n     * @return {String} ex: rgb(0-255,0-255,0-255)\n     */\n    toRgb: function() {\n      var source = this.getSource();\n      return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')';\n    },\n\n    /**\n     * Returns color representation in RGBA format\n     * @return {String} ex: rgba(0-255,0-255,0-255,0-1)\n     */\n    toRgba: function() {\n      var source = this.getSource();\n      return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')';\n    },\n\n    /**\n     * Returns color representation in HSL format\n     * @return {String} ex: hsl(0-360,0%-100%,0%-100%)\n     */\n    toHsl: function() {\n      var source = this.getSource(),\n          hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n      return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)';\n    },\n\n    /**\n     * Returns color representation in HSLA format\n     * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)\n     */\n    toHsla: function() {\n      var source = this.getSource(),\n          hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n      return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')';\n    },\n\n    /**\n     * Returns color representation in HEX format\n     * @return {String} ex: FF5555\n     */\n    toHex: function() {\n      var source = this.getSource(), r, g, b;\n\n      r = source[0].toString(16);\n      r = (r.length === 1) ? ('0' + r) : r;\n\n      g = source[1].toString(16);\n      g = (g.length === 1) ? ('0' + g) : g;\n\n      b = source[2].toString(16);\n      b = (b.length === 1) ? ('0' + b) : b;\n\n      return r.toUpperCase() + g.toUpperCase() + b.toUpperCase();\n    },\n\n    /**\n     * Returns color representation in HEXA format\n     * @return {String} ex: FF5555CC\n     */\n    toHexa: function() {\n      var source = this.getSource(), a;\n\n      a = Math.round(source[3] * 255);\n      a = a.toString(16);\n      a = (a.length === 1) ? ('0' + a) : a;\n\n      return this.toHex() + a.toUpperCase();\n    },\n\n    /**\n     * Gets value of alpha channel for this color\n     * @return {Number} 0-1\n     */\n    getAlpha: function() {\n      return this.getSource()[3];\n    },\n\n    /**\n     * Sets value of alpha channel for this color\n     * @param {Number} alpha Alpha value 0-1\n     * @return {fabric.Color} thisArg\n     */\n    setAlpha: function(alpha) {\n      var source = this.getSource();\n      source[3] = alpha;\n      this.setSource(source);\n      return this;\n    },\n\n    /**\n     * Transforms color to its grayscale representation\n     * @return {fabric.Color} thisArg\n     */\n    toGrayscale: function() {\n      var source = this.getSource(),\n          average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10),\n          currentAlpha = source[3];\n      this.setSource([average, average, average, currentAlpha]);\n      return this;\n    },\n\n    /**\n     * Transforms color to its black and white representation\n     * @param {Number} threshold\n     * @return {fabric.Color} thisArg\n     */\n    toBlackWhite: function(threshold) {\n      var source = this.getSource(),\n          average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0),\n          currentAlpha = source[3];\n\n      threshold = threshold || 127;\n\n      average = (Number(average) < Number(threshold)) ? 0 : 255;\n      this.setSource([average, average, average, currentAlpha]);\n      return this;\n    },\n\n    /**\n     * Overlays color with another color\n     * @param {String|fabric.Color} otherColor\n     * @return {fabric.Color} thisArg\n     */\n    overlayWith: function(otherColor) {\n      if (!(otherColor instanceof Color)) {\n        otherColor = new Color(otherColor);\n      }\n\n      var result = [],\n          alpha = this.getAlpha(),\n          otherAlpha = 0.5,\n          source = this.getSource(),\n          otherSource = otherColor.getSource(), i;\n\n      for (i = 0; i < 3; i++) {\n        result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha)));\n      }\n\n      result[3] = alpha;\n      this.setSource(result);\n      return this;\n    }\n  };\n\n  /**\n   * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgba(255, 100, 10, 0.5), rgba( 255 , 100 , 10 , 0.5 ), rgb(1,1,1), rgba(100%, 60%, 10%, 0.5))\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   */\n  // eslint-disable-next-line max-len\n  fabric.Color.reRGBa = /^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*((?:\\d*\\.?\\d+)?)\\s*)?\\)$/i;\n\n  /**\n   * Regex matching color in HSL or HSLA formats (ex: hsl(200, 80%, 10%), hsla(300, 50%, 80%, 0.5), hsla( 300 , 50% , 80% , 0.5 ))\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   */\n  fabric.Color.reHSLa = /^hsla?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}\\%)\\s*,\\s*(\\d{1,3}\\%)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/i;\n\n  /**\n   * Regex matching color in HEX format (ex: #FF5544CC, #FF5555, 010155, aff)\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   */\n  fabric.Color.reHex = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i;\n\n  /**\n   * Map of the 148 color names with HEX code\n   * @static\n   * @field\n   * @memberOf fabric.Color\n   * @see: https://www.w3.org/TR/css3-color/#svg-color\n   */\n  fabric.Color.colorNameMap = {\n    aliceblue:            '#F0F8FF',\n    antiquewhite:         '#FAEBD7',\n    aqua:                 '#00FFFF',\n    aquamarine:           '#7FFFD4',\n    azure:                '#F0FFFF',\n    beige:                '#F5F5DC',\n    bisque:               '#FFE4C4',\n    black:                '#000000',\n    blanchedalmond:       '#FFEBCD',\n    blue:                 '#0000FF',\n    blueviolet:           '#8A2BE2',\n    brown:                '#A52A2A',\n    burlywood:            '#DEB887',\n    cadetblue:            '#5F9EA0',\n    chartreuse:           '#7FFF00',\n    chocolate:            '#D2691E',\n    coral:                '#FF7F50',\n    cornflowerblue:       '#6495ED',\n    cornsilk:             '#FFF8DC',\n    crimson:              '#DC143C',\n    cyan:                 '#00FFFF',\n    darkblue:             '#00008B',\n    darkcyan:             '#008B8B',\n    darkgoldenrod:        '#B8860B',\n    darkgray:             '#A9A9A9',\n    darkgrey:             '#A9A9A9',\n    darkgreen:            '#006400',\n    darkkhaki:            '#BDB76B',\n    darkmagenta:          '#8B008B',\n    darkolivegreen:       '#556B2F',\n    darkorange:           '#FF8C00',\n    darkorchid:           '#9932CC',\n    darkred:              '#8B0000',\n    darksalmon:           '#E9967A',\n    darkseagreen:         '#8FBC8F',\n    darkslateblue:        '#483D8B',\n    darkslategray:        '#2F4F4F',\n    darkslategrey:        '#2F4F4F',\n    darkturquoise:        '#00CED1',\n    darkviolet:           '#9400D3',\n    deeppink:             '#FF1493',\n    deepskyblue:          '#00BFFF',\n    dimgray:              '#696969',\n    dimgrey:              '#696969',\n    dodgerblue:           '#1E90FF',\n    firebrick:            '#B22222',\n    floralwhite:          '#FFFAF0',\n    forestgreen:          '#228B22',\n    fuchsia:              '#FF00FF',\n    gainsboro:            '#DCDCDC',\n    ghostwhite:           '#F8F8FF',\n    gold:                 '#FFD700',\n    goldenrod:            '#DAA520',\n    gray:                 '#808080',\n    grey:                 '#808080',\n    green:                '#008000',\n    greenyellow:          '#ADFF2F',\n    honeydew:             '#F0FFF0',\n    hotpink:              '#FF69B4',\n    indianred:            '#CD5C5C',\n    indigo:               '#4B0082',\n    ivory:                '#FFFFF0',\n    khaki:                '#F0E68C',\n    lavender:             '#E6E6FA',\n    lavenderblush:        '#FFF0F5',\n    lawngreen:            '#7CFC00',\n    lemonchiffon:         '#FFFACD',\n    lightblue:            '#ADD8E6',\n    lightcoral:           '#F08080',\n    lightcyan:            '#E0FFFF',\n    lightgoldenrodyellow: '#FAFAD2',\n    lightgray:            '#D3D3D3',\n    lightgrey:            '#D3D3D3',\n    lightgreen:           '#90EE90',\n    lightpink:            '#FFB6C1',\n    lightsalmon:          '#FFA07A',\n    lightseagreen:        '#20B2AA',\n    lightskyblue:         '#87CEFA',\n    lightslategray:       '#778899',\n    lightslategrey:       '#778899',\n    lightsteelblue:       '#B0C4DE',\n    lightyellow:          '#FFFFE0',\n    lime:                 '#00FF00',\n    limegreen:            '#32CD32',\n    linen:                '#FAF0E6',\n    magenta:              '#FF00FF',\n    maroon:               '#800000',\n    mediumaquamarine:     '#66CDAA',\n    mediumblue:           '#0000CD',\n    mediumorchid:         '#BA55D3',\n    mediumpurple:         '#9370DB',\n    mediumseagreen:       '#3CB371',\n    mediumslateblue:      '#7B68EE',\n    mediumspringgreen:    '#00FA9A',\n    mediumturquoise:      '#48D1CC',\n    mediumvioletred:      '#C71585',\n    midnightblue:         '#191970',\n    mintcream:            '#F5FFFA',\n    mistyrose:            '#FFE4E1',\n    moccasin:             '#FFE4B5',\n    navajowhite:          '#FFDEAD',\n    navy:                 '#000080',\n    oldlace:              '#FDF5E6',\n    olive:                '#808000',\n    olivedrab:            '#6B8E23',\n    orange:               '#FFA500',\n    orangered:            '#FF4500',\n    orchid:               '#DA70D6',\n    palegoldenrod:        '#EEE8AA',\n    palegreen:            '#98FB98',\n    paleturquoise:        '#AFEEEE',\n    palevioletred:        '#DB7093',\n    papayawhip:           '#FFEFD5',\n    peachpuff:            '#FFDAB9',\n    peru:                 '#CD853F',\n    pink:                 '#FFC0CB',\n    plum:                 '#DDA0DD',\n    powderblue:           '#B0E0E6',\n    purple:               '#800080',\n    rebeccapurple:        '#663399',\n    red:                  '#FF0000',\n    rosybrown:            '#BC8F8F',\n    royalblue:            '#4169E1',\n    saddlebrown:          '#8B4513',\n    salmon:               '#FA8072',\n    sandybrown:           '#F4A460',\n    seagreen:             '#2E8B57',\n    seashell:             '#FFF5EE',\n    sienna:               '#A0522D',\n    silver:               '#C0C0C0',\n    skyblue:              '#87CEEB',\n    slateblue:            '#6A5ACD',\n    slategray:            '#708090',\n    slategrey:            '#708090',\n    snow:                 '#FFFAFA',\n    springgreen:          '#00FF7F',\n    steelblue:            '#4682B4',\n    tan:                  '#D2B48C',\n    teal:                 '#008080',\n    thistle:              '#D8BFD8',\n    tomato:               '#FF6347',\n    turquoise:            '#40E0D0',\n    violet:               '#EE82EE',\n    wheat:                '#F5DEB3',\n    white:                '#FFFFFF',\n    whitesmoke:           '#F5F5F5',\n    yellow:               '#FFFF00',\n    yellowgreen:          '#9ACD32'\n  };\n\n  /**\n   * @private\n   * @param {Number} p\n   * @param {Number} q\n   * @param {Number} t\n   * @return {Number}\n   */\n  function hue2rgb(p, q, t) {\n    if (t < 0) {\n      t += 1;\n    }\n    if (t > 1) {\n      t -= 1;\n    }\n    if (t < 1 / 6) {\n      return p + (q - p) * 6 * t;\n    }\n    if (t < 1 / 2) {\n      return q;\n    }\n    if (t < 2 / 3) {\n      return p + (q - p) * (2 / 3 - t) * 6;\n    }\n    return p;\n  }\n\n  /**\n   * Returns new color object, when given a color in RGB format\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: rgb(0-255,0-255,0-255)\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromRgb = function(color) {\n    return Color.fromSource(Color.sourceFromRgb(color));\n  };\n\n  /**\n   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)\n   * @return {Array} source\n   */\n  fabric.Color.sourceFromRgb = function(color) {\n    var match = color.match(Color.reRGBa);\n    if (match) {\n      var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1),\n          g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1),\n          b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1);\n\n      return [\n        parseInt(r, 10),\n        parseInt(g, 10),\n        parseInt(b, 10),\n        match[4] ? parseFloat(match[4]) : 1\n      ];\n    }\n  };\n\n  /**\n   * Returns new color object, when given a color in RGBA format\n   * @static\n   * @function\n   * @memberOf fabric.Color\n   * @param {String} color\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromRgba = Color.fromRgb;\n\n  /**\n   * Returns new color object, when given a color in HSL format\n   * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)\n   * @memberOf fabric.Color\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromHsl = function(color) {\n    return Color.fromSource(Color.sourceFromHsl(color));\n  };\n\n  /**\n   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.\n   * Adapted from <a href=\"https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html\">https://github.com/mjijackson</a>\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)\n   * @return {Array} source\n   * @see http://http://www.w3.org/TR/css3-color/#hsl-color\n   */\n  fabric.Color.sourceFromHsl = function(color) {\n    var match = color.match(Color.reHSLa);\n    if (!match) {\n      return;\n    }\n\n    var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,\n        s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),\n        l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1),\n        r, g, b;\n\n    if (s === 0) {\n      r = g = b = l;\n    }\n    else {\n      var q = l <= 0.5 ? l * (s + 1) : l + s - l * s,\n          p = l * 2 - q;\n\n      r = hue2rgb(p, q, h + 1 / 3);\n      g = hue2rgb(p, q, h);\n      b = hue2rgb(p, q, h - 1 / 3);\n    }\n\n    return [\n      Math.round(r * 255),\n      Math.round(g * 255),\n      Math.round(b * 255),\n      match[4] ? parseFloat(match[4]) : 1\n    ];\n  };\n\n  /**\n   * Returns new color object, when given a color in HSLA format\n   * @static\n   * @function\n   * @memberOf fabric.Color\n   * @param {String} color\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromHsla = Color.fromHsl;\n\n  /**\n   * Returns new color object, when given a color in HEX format\n   * @static\n   * @memberOf fabric.Color\n   * @param {String} color Color value ex: FF5555\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromHex = function(color) {\n    return Color.fromSource(Color.sourceFromHex(color));\n  };\n\n  /**\n   * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HEX format\n   * @static\n   * @memberOf fabric.Color\n   * @param {String} color ex: FF5555 or FF5544CC (RGBa)\n   * @return {Array} source\n   */\n  fabric.Color.sourceFromHex = function(color) {\n    if (color.match(Color.reHex)) {\n      var value = color.slice(color.indexOf('#') + 1),\n          isShortNotation = (value.length === 3 || value.length === 4),\n          isRGBa = (value.length === 8 || value.length === 4),\n          r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2),\n          g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4),\n          b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6),\n          a = isRGBa ? (isShortNotation ? (value.charAt(3) + value.charAt(3)) : value.substring(6, 8)) : 'FF';\n\n      return [\n        parseInt(r, 16),\n        parseInt(g, 16),\n        parseInt(b, 16),\n        parseFloat((parseInt(a, 16) / 255).toFixed(2))\n      ];\n    }\n  };\n\n  /**\n   * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])\n   * @static\n   * @memberOf fabric.Color\n   * @param {Array} source\n   * @return {fabric.Color}\n   */\n  fabric.Color.fromSource = function(source) {\n    var oColor = new Color();\n    oColor.setSource(source);\n    return oColor;\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      scaleMap = ['e', 'se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'],\n      skewMap = ['ns', 'nesw', 'ew', 'nwse'],\n      controls = {},\n      LEFT = 'left', TOP = 'top', RIGHT = 'right', BOTTOM = 'bottom', CENTER = 'center',\n      opposite = {\n        top: BOTTOM,\n        bottom: TOP,\n        left: RIGHT,\n        right: LEFT,\n        center: CENTER,\n      }, radiansToDegrees = fabric.util.radiansToDegrees,\n      sign = (Math.sign || function(x) { return ((x > 0) - (x < 0)) || +x; });\n\n  /**\n   * Combine control position and object angle to find the control direction compared\n   * to the object center.\n   * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls\n   * @param {fabric.Control} control the control class\n   * @return {Number} 0 - 7 a quadrant number\n   */\n  function findCornerQuadrant(fabricObject, control) {\n    var cornerAngle = fabricObject.angle + radiansToDegrees(Math.atan2(control.y, control.x)) + 360;\n    return Math.round((cornerAngle % 360) / 45);\n  }\n\n  function fireEvent(eventName, options) {\n    var target = options.transform.target,\n        canvas = target.canvas,\n        canvasOptions = fabric.util.object.clone(options);\n    canvasOptions.target = target;\n    canvas && canvas.fire('object:' + eventName, canvasOptions);\n    target.fire(eventName, options);\n  }\n\n  /**\n   * Inspect event and fabricObject properties to understand if the scaling action\n   * @param {Event} eventData from the user action\n   * @param {fabric.Object} fabricObject the fabric object about to scale\n   * @return {Boolean} true if scale is proportional\n   */\n  function scaleIsProportional(eventData, fabricObject) {\n    var canvas = fabricObject.canvas, uniScaleKey = canvas.uniScaleKey,\n        uniformIsToggled = eventData[uniScaleKey];\n    return (canvas.uniformScaling && !uniformIsToggled) ||\n    (!canvas.uniformScaling && uniformIsToggled);\n  }\n\n  /**\n   * Checks if transform is centered\n   * @param {Object} transform transform data\n   * @return {Boolean} true if transform is centered\n   */\n  function isTransformCentered(transform) {\n    return transform.originX === CENTER && transform.originY === CENTER;\n  }\n\n  /**\n   * Inspect fabricObject to understand if the current scaling action is allowed\n   * @param {fabric.Object} fabricObject the fabric object about to scale\n   * @param {String} by 'x' or 'y' or ''\n   * @param {Boolean} scaleProportionally true if we are trying to scale proportionally\n   * @return {Boolean} true if scaling is not allowed at current conditions\n   */\n  function scalingIsForbidden(fabricObject, by, scaleProportionally) {\n    var lockX = fabricObject.lockScalingX, lockY = fabricObject.lockScalingY;\n    if (lockX && lockY) {\n      return true;\n    }\n    if (!by && (lockX || lockY) && scaleProportionally) {\n      return true;\n    }\n    if (lockX && by === 'x') {\n      return true;\n    }\n    if (lockY && by === 'y') {\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * return the correct cursor style for the scale action\n   * @param {Event} eventData the javascript event that is causing the scale\n   * @param {fabric.Control} control the control that is interested in the action\n   * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n   * @return {String} a valid css string for the cursor\n   */\n  function scaleCursorStyleHandler(eventData, control, fabricObject) {\n    var notAllowed = 'not-allowed',\n        scaleProportionally = scaleIsProportional(eventData, fabricObject),\n        by = '';\n    if (control.x !== 0 && control.y === 0) {\n      by = 'x';\n    }\n    else if (control.x === 0 && control.y !== 0) {\n      by = 'y';\n    }\n    if (scalingIsForbidden(fabricObject, by, scaleProportionally)) {\n      return notAllowed;\n    }\n    var n = findCornerQuadrant(fabricObject, control);\n    return scaleMap[n] + '-resize';\n  }\n\n  /**\n   * return the correct cursor style for the skew action\n   * @param {Event} eventData the javascript event that is causing the scale\n   * @param {fabric.Control} control the control that is interested in the action\n   * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n   * @return {String} a valid css string for the cursor\n   */\n  function skewCursorStyleHandler(eventData, control, fabricObject) {\n    var notAllowed = 'not-allowed';\n    if (control.x !== 0 && fabricObject.lockSkewingY) {\n      return notAllowed;\n    }\n    if (control.y !== 0 && fabricObject.lockSkewingX) {\n      return notAllowed;\n    }\n    var n = findCornerQuadrant(fabricObject, control) % 4;\n    return skewMap[n] + '-resize';\n  }\n\n  /**\n   * Combine skew and scale style handlers to cover fabric standard use case\n   * @param {Event} eventData the javascript event that is causing the scale\n   * @param {fabric.Control} control the control that is interested in the action\n   * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n   * @return {String} a valid css string for the cursor\n   */\n  function scaleSkewCursorStyleHandler(eventData, control, fabricObject) {\n    if (eventData[fabricObject.canvas.altActionKey]) {\n      return controls.skewCursorStyleHandler(eventData, control, fabricObject);\n    }\n    return controls.scaleCursorStyleHandler(eventData, control, fabricObject);\n  }\n\n  /**\n   * Inspect event, control and fabricObject to return the correct action name\n   * @param {Event} eventData the javascript event that is causing the scale\n   * @param {fabric.Control} control the control that is interested in the action\n   * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n   * @return {String} an action name\n   */\n  function scaleOrSkewActionName(eventData, control, fabricObject) {\n    var isAlternative = eventData[fabricObject.canvas.altActionKey];\n    if (control.x === 0) {\n      // then is scaleY or skewX\n      return isAlternative ? 'skewX' : 'scaleY';\n    }\n    if (control.y === 0) {\n      // then is scaleY or skewX\n      return isAlternative ? 'skewY' : 'scaleX';\n    }\n  }\n\n  /**\n   * Find the correct style for the control that is used for rotation.\n   * this function is very simple and it just take care of not-allowed or standard cursor\n   * @param {Event} eventData the javascript event that is causing the scale\n   * @param {fabric.Control} control the control that is interested in the action\n   * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n   * @return {String} a valid css string for the cursor\n   */\n  function rotationStyleHandler(eventData, control, fabricObject) {\n    if (fabricObject.lockRotation) {\n      return 'not-allowed';\n    }\n    return control.cursorStyle;\n  }\n\n  function commonEventInfo(eventData, transform, x, y) {\n    return {\n      e: eventData,\n      transform: transform,\n      pointer: {\n        x: x,\n        y: y,\n      }\n    };\n  }\n\n  /**\n   * Wrap an action handler with saving/restoring object position on the transform.\n   * this is the code that permits to objects to keep their position while transforming.\n   * @param {Function} actionHandler the function to wrap\n   * @return {Function} a function with an action handler signature\n   */\n  function wrapWithFixedAnchor(actionHandler) {\n    return function(eventData, transform, x, y) {\n      var target = transform.target, centerPoint = target.getCenterPoint(),\n          constraint = target.translateToOriginPoint(centerPoint, transform.originX, transform.originY),\n          actionPerformed = actionHandler(eventData, transform, x, y);\n      target.setPositionByOrigin(constraint, transform.originX, transform.originY);\n      return actionPerformed;\n    };\n  }\n\n  /**\n   * Wrap an action handler with firing an event if the action is performed\n   * @param {Function} actionHandler the function to wrap\n   * @return {Function} a function with an action handler signature\n   */\n  function wrapWithFireEvent(eventName, actionHandler) {\n    return function(eventData, transform, x, y) {\n      var actionPerformed = actionHandler(eventData, transform, x, y);\n      if (actionPerformed) {\n        fireEvent(eventName, commonEventInfo(eventData, transform, x, y));\n      }\n      return actionPerformed;\n    };\n  }\n\n  /**\n   * Transforms a point described by x and y in a distance from the top left corner of the object\n   * bounding box.\n   * @param {Object} transform\n   * @param {String} originX\n   * @param {String} originY\n   * @param {number} x\n   * @param {number} y\n   * @return {Fabric.Point} the normalized point\n   */\n  function getLocalPoint(transform, originX, originY, x, y) {\n    var target = transform.target,\n        control = target.controls[transform.corner],\n        zoom = target.canvas.getZoom(),\n        padding = target.padding / zoom,\n        localPoint = target.toLocalPoint(new fabric.Point(x, y), originX, originY);\n    if (localPoint.x >= padding) {\n      localPoint.x -= padding;\n    }\n    if (localPoint.x <= -padding) {\n      localPoint.x += padding;\n    }\n    if (localPoint.y >= padding) {\n      localPoint.y -= padding;\n    }\n    if (localPoint.y <= padding) {\n      localPoint.y += padding;\n    }\n    localPoint.x -= control.offsetX;\n    localPoint.y -= control.offsetY;\n    return localPoint;\n  }\n\n  /**\n   * Detect if the fabric object is flipped on one side.\n   * @param {fabric.Object} target\n   * @return {Boolean} true if one flip, but not two.\n   */\n  function targetHasOneFlip(target) {\n    return target.flipX !== target.flipY;\n  }\n\n  /**\n   * Utility function to compensate the scale factor when skew is applied on both axes\n   * @private\n   */\n  function compensateScaleForSkew(target, oppositeSkew, scaleToCompensate, axis, reference) {\n    if (target[oppositeSkew] !== 0) {\n      var newDim = target._getTransformedDimensions()[axis];\n      var newValue = reference / newDim * target[scaleToCompensate];\n      target.set(scaleToCompensate, newValue);\n    }\n  }\n\n  /**\n   * Action handler for skewing on the X axis\n   * @private\n   */\n  function skewObjectX(eventData, transform, x, y) {\n    var target = transform.target,\n        // find how big the object would be, if there was no skewX. takes in account scaling\n        dimNoSkew = target._getTransformedDimensions(0, target.skewY),\n        localPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y),\n        // the mouse is in the center of the object, and we want it to stay there.\n        // so the object will grow twice as much as the mouse.\n        // this makes the skew growth to localPoint * 2 - dimNoSkew.\n        totalSkewSize = Math.abs(localPoint.x * 2) - dimNoSkew.x,\n        currentSkew = target.skewX, newSkew;\n    if (totalSkewSize < 2) {\n      // let's make it easy to go back to position 0.\n      newSkew = 0;\n    }\n    else {\n      newSkew = radiansToDegrees(\n        Math.atan2((totalSkewSize / target.scaleX), (dimNoSkew.y / target.scaleY))\n      );\n      // now we have to find the sign of the skew.\n      // it mostly depend on the origin of transformation.\n      if (transform.originX === LEFT && transform.originY === BOTTOM) {\n        newSkew = -newSkew;\n      }\n      if (transform.originX === RIGHT && transform.originY === TOP) {\n        newSkew = -newSkew;\n      }\n      if (targetHasOneFlip(target)) {\n        newSkew = -newSkew;\n      }\n    }\n    var hasSkewed = currentSkew !== newSkew;\n    if (hasSkewed) {\n      var dimBeforeSkewing = target._getTransformedDimensions().y;\n      target.set('skewX', newSkew);\n      compensateScaleForSkew(target, 'skewY', 'scaleY', 'y', dimBeforeSkewing);\n    }\n    return hasSkewed;\n  }\n\n  /**\n   * Action handler for skewing on the Y axis\n   * @private\n   */\n  function skewObjectY(eventData, transform, x, y) {\n    var target = transform.target,\n        // find how big the object would be, if there was no skewX. takes in account scaling\n        dimNoSkew = target._getTransformedDimensions(target.skewX, 0),\n        localPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y),\n        // the mouse is in the center of the object, and we want it to stay there.\n        // so the object will grow twice as much as the mouse.\n        // this makes the skew growth to localPoint * 2 - dimNoSkew.\n        totalSkewSize = Math.abs(localPoint.y * 2) - dimNoSkew.y,\n        currentSkew = target.skewY, newSkew;\n    if (totalSkewSize < 2) {\n      // let's make it easy to go back to position 0.\n      newSkew = 0;\n    }\n    else {\n      newSkew = radiansToDegrees(\n        Math.atan2((totalSkewSize / target.scaleY), (dimNoSkew.x / target.scaleX))\n      );\n      // now we have to find the sign of the skew.\n      // it mostly depend on the origin of transformation.\n      if (transform.originX === LEFT && transform.originY === BOTTOM) {\n        newSkew = -newSkew;\n      }\n      if (transform.originX === RIGHT && transform.originY === TOP) {\n        newSkew = -newSkew;\n      }\n      if (targetHasOneFlip(target)) {\n        newSkew = -newSkew;\n      }\n    }\n    var hasSkewed = currentSkew !== newSkew;\n    if (hasSkewed) {\n      var dimBeforeSkewing = target._getTransformedDimensions().x;\n      target.set('skewY', newSkew);\n      compensateScaleForSkew(target, 'skewX', 'scaleX', 'x', dimBeforeSkewing);\n    }\n    return hasSkewed;\n  }\n\n  /**\n   * Wrapped Action handler for skewing on the Y axis, takes care of the\n   * skew direction and determine the correct transform origin for the anchor point\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function skewHandlerX(eventData, transform, x, y) {\n    // step1 figure out and change transform origin.\n    // if skewX > 0 and originY bottom we anchor on right\n    // if skewX > 0 and originY top we anchor on left\n    // if skewX < 0 and originY bottom we anchor on left\n    // if skewX < 0 and originY top we anchor on right\n    // if skewX is 0, we look for mouse position to understand where are we going.\n    var target = transform.target, currentSkew = target.skewX, originX, originY = transform.originY;\n    if (target.lockSkewingX) {\n      return false;\n    }\n    if (currentSkew === 0) {\n      var localPointFromCenter = getLocalPoint(transform, CENTER, CENTER, x, y);\n      if (localPointFromCenter.x > 0) {\n        // we are pulling right, anchor left;\n        originX = LEFT;\n      }\n      else {\n        // we are pulling right, anchor right\n        originX = RIGHT;\n      }\n    }\n    else {\n      if (currentSkew > 0) {\n        originX = originY === TOP ? LEFT : RIGHT;\n      }\n      if (currentSkew < 0) {\n        originX = originY === TOP ? RIGHT : LEFT;\n      }\n      // is the object flipped on one side only? swap the origin.\n      if (targetHasOneFlip(target)) {\n        originX = originX === LEFT ? RIGHT : LEFT;\n      }\n    }\n\n    // once we have the origin, we find the anchor point\n    transform.originX = originX;\n    var finalHandler = wrapWithFireEvent('skewing', wrapWithFixedAnchor(skewObjectX));\n    return finalHandler(eventData, transform, x, y);\n  }\n\n  /**\n   * Wrapped Action handler for skewing on the Y axis, takes care of the\n   * skew direction and determine the correct transform origin for the anchor point\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function skewHandlerY(eventData, transform, x, y) {\n    // step1 figure out and change transform origin.\n    // if skewY > 0 and originX left we anchor on top\n    // if skewY > 0 and originX right we anchor on bottom\n    // if skewY < 0 and originX left we anchor on bottom\n    // if skewY < 0 and originX right we anchor on top\n    // if skewY is 0, we look for mouse position to understand where are we going.\n    var target = transform.target, currentSkew = target.skewY, originY, originX = transform.originX;\n    if (target.lockSkewingY) {\n      return false;\n    }\n    if (currentSkew === 0) {\n      var localPointFromCenter = getLocalPoint(transform, CENTER, CENTER, x, y);\n      if (localPointFromCenter.y > 0) {\n        // we are pulling down, anchor up;\n        originY = TOP;\n      }\n      else {\n        // we are pulling up, anchor down\n        originY = BOTTOM;\n      }\n    }\n    else {\n      if (currentSkew > 0) {\n        originY = originX === LEFT ? TOP : BOTTOM;\n      }\n      if (currentSkew < 0) {\n        originY = originX === LEFT ? BOTTOM : TOP;\n      }\n      // is the object flipped on one side only? swap the origin.\n      if (targetHasOneFlip(target)) {\n        originY = originY === TOP ? BOTTOM : TOP;\n      }\n    }\n\n    // once we have the origin, we find the anchor point\n    transform.originY = originY;\n    var finalHandler = wrapWithFireEvent('skewing', wrapWithFixedAnchor(skewObjectY));\n    return finalHandler(eventData, transform, x, y);\n  }\n\n  /**\n   * Action handler for rotation and snapping, without anchor point.\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   * @private\n   */\n  function rotationWithSnapping(eventData, transform, x, y) {\n    var t = transform,\n        target = t.target,\n        pivotPoint = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY);\n\n    if (target.lockRotation) {\n      return false;\n    }\n\n    var lastAngle = Math.atan2(t.ey - pivotPoint.y, t.ex - pivotPoint.x),\n        curAngle = Math.atan2(y - pivotPoint.y, x - pivotPoint.x),\n        angle = radiansToDegrees(curAngle - lastAngle + t.theta),\n        hasRotated = true;\n\n    if (target.snapAngle > 0) {\n      var snapAngle  = target.snapAngle,\n          snapThreshold  = target.snapThreshold || snapAngle,\n          rightAngleLocked = Math.ceil(angle / snapAngle) * snapAngle,\n          leftAngleLocked = Math.floor(angle / snapAngle) * snapAngle;\n\n      if (Math.abs(angle - leftAngleLocked) < snapThreshold) {\n        angle = leftAngleLocked;\n      }\n      else if (Math.abs(angle - rightAngleLocked) < snapThreshold) {\n        angle = rightAngleLocked;\n      }\n    }\n\n    // normalize angle to positive value\n    if (angle < 0) {\n      angle = 360 + angle;\n    }\n    angle %= 360;\n\n    hasRotated = target.angle !== angle;\n    target.angle = angle;\n    return hasRotated;\n  }\n\n  /**\n   * Basic scaling logic, reused with different constrain for scaling X,Y, freely or equally.\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @param {Object} options additional information for scaling\n   * @param {String} options.by 'x', 'y', 'equally' or '' to indicate type of scaling\n   * @return {Boolean} true if some change happened\n   * @private\n   */\n  function scaleObject(eventData, transform, x, y, options) {\n    options = options || {};\n    var target = transform.target,\n        lockScalingX = target.lockScalingX, lockScalingY = target.lockScalingY,\n        by = options.by, newPoint, scaleX, scaleY, dim,\n        scaleProportionally = scaleIsProportional(eventData, target),\n        forbidScaling = scalingIsForbidden(target, by, scaleProportionally),\n        signX, signY, gestureScale = transform.gestureScale;\n\n    if (forbidScaling) {\n      return false;\n    }\n    if (gestureScale) {\n      scaleX = transform.scaleX * gestureScale;\n      scaleY = transform.scaleY * gestureScale;\n    }\n    else {\n      newPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y);\n      // use of sign: We use sign to detect change of direction of an action. sign usually change when\n      // we cross the origin point with the mouse. So a scale flip for example. There is an issue when scaling\n      // by center and scaling using one middle control ( default: mr, mt, ml, mb), the mouse movement can easily\n      // cross many time the origin point and flip the object. so we need a way to filter out the noise.\n      // This ternary here should be ok to filter out X scaling when we want Y only and vice versa.\n      signX = by !== 'y' ? sign(newPoint.x) : 1;\n      signY = by !== 'x' ? sign(newPoint.y) : 1;\n      if (!transform.signX) {\n        transform.signX = signX;\n      }\n      if (!transform.signY) {\n        transform.signY = signY;\n      }\n\n      if (target.lockScalingFlip &&\n        (transform.signX !== signX || transform.signY !== signY)\n      ) {\n        return false;\n      }\n\n      dim = target._getTransformedDimensions();\n      // missing detection of flip and logic to switch the origin\n      if (scaleProportionally && !by) {\n        // uniform scaling\n        var distance = Math.abs(newPoint.x) + Math.abs(newPoint.y),\n            original = transform.original,\n            originalDistance = Math.abs(dim.x * original.scaleX / target.scaleX) +\n              Math.abs(dim.y * original.scaleY / target.scaleY),\n            scale = distance / originalDistance;\n        scaleX = original.scaleX * scale;\n        scaleY = original.scaleY * scale;\n      }\n      else {\n        scaleX = Math.abs(newPoint.x * target.scaleX / dim.x);\n        scaleY = Math.abs(newPoint.y * target.scaleY / dim.y);\n      }\n      // if we are scaling by center, we need to double the scale\n      if (isTransformCentered(transform)) {\n        scaleX *= 2;\n        scaleY *= 2;\n      }\n      if (transform.signX !== signX && by !== 'y') {\n        transform.originX = opposite[transform.originX];\n        scaleX *= -1;\n        transform.signX = signX;\n      }\n      if (transform.signY !== signY && by !== 'x') {\n        transform.originY = opposite[transform.originY];\n        scaleY *= -1;\n        transform.signY = signY;\n      }\n    }\n    // minScale is taken are in the setter.\n    var oldScaleX = target.scaleX, oldScaleY = target.scaleY;\n    if (!by) {\n      !lockScalingX && target.set('scaleX', scaleX);\n      !lockScalingY && target.set('scaleY', scaleY);\n    }\n    else {\n      // forbidden cases already handled on top here.\n      by === 'x' && target.set('scaleX', scaleX);\n      by === 'y' && target.set('scaleY', scaleY);\n    }\n    return oldScaleX !== target.scaleX || oldScaleY !== target.scaleY;\n  }\n\n  /**\n   * Generic scaling logic, to scale from corners either equally or freely.\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function scaleObjectFromCorner(eventData, transform, x, y) {\n    return scaleObject(eventData, transform, x, y);\n  }\n\n  /**\n   * Scaling logic for the X axis.\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function scaleObjectX(eventData, transform, x, y) {\n    return scaleObject(eventData, transform, x, y , { by: 'x' });\n  }\n\n  /**\n   * Scaling logic for the Y axis.\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function scaleObjectY(eventData, transform, x, y) {\n    return scaleObject(eventData, transform, x, y , { by: 'y' });\n  }\n\n  /**\n   * Composed action handler to either scale Y or skew X\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function scalingYOrSkewingX(eventData, transform, x, y) {\n    // ok some safety needed here.\n    if (eventData[transform.target.canvas.altActionKey]) {\n      return controls.skewHandlerX(eventData, transform, x, y);\n    }\n    return controls.scalingY(eventData, transform, x, y);\n  }\n\n  /**\n   * Composed action handler to either scale X or skew Y\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function scalingXOrSkewingY(eventData, transform, x, y) {\n    // ok some safety needed here.\n    if (eventData[transform.target.canvas.altActionKey]) {\n      return controls.skewHandlerY(eventData, transform, x, y);\n    }\n    return controls.scalingX(eventData, transform, x, y);\n  }\n\n  /**\n   * Action handler to change textbox width\n   * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if some change happened\n   */\n  function changeWidth(eventData, transform, x, y) {\n    var target = transform.target, localPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y),\n        strokePadding = target.strokeWidth / (target.strokeUniform ? target.scaleX : 1),\n        multiplier = isTransformCentered(transform) ? 2 : 1,\n        oldWidth = target.width,\n        newWidth = Math.abs(localPoint.x * multiplier / target.scaleX) - strokePadding;\n    target.set('width', Math.max(newWidth, 0));\n    return oldWidth !== newWidth;\n  }\n\n  /**\n   * Action handler\n   * @private\n   * @param {Event} eventData javascript event that is doing the transform\n   * @param {Object} transform javascript object containing a series of information around the current transform\n   * @param {number} x current mouse x position, canvas normalized\n   * @param {number} y current mouse y position, canvas normalized\n   * @return {Boolean} true if the translation occurred\n   */\n  function dragHandler(eventData, transform, x, y) {\n    var target = transform.target,\n        newLeft = x - transform.offsetX,\n        newTop = y - transform.offsetY,\n        moveX = !target.get('lockMovementX') && target.left !== newLeft,\n        moveY = !target.get('lockMovementY') && target.top !== newTop;\n    moveX && target.set('left', newLeft);\n    moveY && target.set('top', newTop);\n    if (moveX || moveY) {\n      fireEvent('moving', commonEventInfo(eventData, transform, x, y));\n    }\n    return moveX || moveY;\n  }\n\n  controls.scaleCursorStyleHandler = scaleCursorStyleHandler;\n  controls.skewCursorStyleHandler = skewCursorStyleHandler;\n  controls.scaleSkewCursorStyleHandler = scaleSkewCursorStyleHandler;\n  controls.rotationWithSnapping = wrapWithFireEvent('rotating', wrapWithFixedAnchor(rotationWithSnapping));\n  controls.scalingEqually = wrapWithFireEvent('scaling', wrapWithFixedAnchor( scaleObjectFromCorner));\n  controls.scalingX = wrapWithFireEvent('scaling', wrapWithFixedAnchor(scaleObjectX));\n  controls.scalingY = wrapWithFireEvent('scaling', wrapWithFixedAnchor(scaleObjectY));\n  controls.scalingYOrSkewingX = scalingYOrSkewingX;\n  controls.scalingXOrSkewingY = scalingXOrSkewingY;\n  controls.changeWidth = wrapWithFireEvent('resizing', wrapWithFixedAnchor(changeWidth));\n  controls.skewHandlerX = skewHandlerX;\n  controls.skewHandlerY = skewHandlerY;\n  controls.dragHandler = dragHandler;\n  controls.scaleOrSkewActionName = scaleOrSkewActionName;\n  controls.rotationStyleHandler = rotationStyleHandler;\n  controls.fireEvent = fireEvent;\n  controls.wrapWithFixedAnchor = wrapWithFixedAnchor;\n  controls.wrapWithFireEvent = wrapWithFireEvent;\n  controls.getLocalPoint = getLocalPoint;\n  fabric.controlsUtils = controls;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      degreesToRadians = fabric.util.degreesToRadians,\n      controls = fabric.controlsUtils;\n\n  /**\n   * Render a round control, as per fabric features.\n   * This function is written to respect object properties like transparentCorners, cornerSize\n   * cornerColor, cornerStrokeColor\n   * plus the addition of offsetY and offsetX.\n   * @param {CanvasRenderingContext2D} ctx context to render on\n   * @param {Number} left x coordinate where the control center should be\n   * @param {Number} top y coordinate where the control center should be\n   * @param {Object} styleOverride override for fabric.Object controls style\n   * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls\n   */\n  function renderCircleControl (ctx, left, top, styleOverride, fabricObject) {\n    styleOverride = styleOverride || {};\n    var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\n        ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\n        transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ?\n          styleOverride.transparentCorners : fabricObject.transparentCorners,\n        methodName = transparentCorners ? 'stroke' : 'fill',\n        stroke = !transparentCorners && (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor),\n        myLeft = left,\n        myTop = top, size;\n    ctx.save();\n    ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor;\n    ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor;\n    // as soon as fabric react v5, remove ie11, use proper ellipse code.\n    if (xSize > ySize) {\n      size = xSize;\n      ctx.scale(1.0, ySize / xSize);\n      myTop = top * xSize / ySize;\n    }\n    else if (ySize > xSize) {\n      size = ySize;\n      ctx.scale(xSize / ySize, 1.0);\n      myLeft = left * ySize / xSize;\n    }\n    else {\n      size = xSize;\n    }\n    // this is still wrong\n    ctx.lineWidth = 1;\n    ctx.beginPath();\n    ctx.arc(myLeft, myTop, size / 2, 0, 2 * Math.PI, false);\n    ctx[methodName]();\n    if (stroke) {\n      ctx.stroke();\n    }\n    ctx.restore();\n  }\n\n  /**\n   * Render a square control, as per fabric features.\n   * This function is written to respect object properties like transparentCorners, cornerSize\n   * cornerColor, cornerStrokeColor\n   * plus the addition of offsetY and offsetX.\n   * @param {CanvasRenderingContext2D} ctx context to render on\n   * @param {Number} left x coordinate where the control center should be\n   * @param {Number} top y coordinate where the control center should be\n   * @param {Object} styleOverride override for fabric.Object controls style\n   * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls\n   */\n  function renderSquareControl(ctx, left, top, styleOverride, fabricObject) {\n    styleOverride = styleOverride || {};\n    var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\n        ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\n        transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ?\n          styleOverride.transparentCorners : fabricObject.transparentCorners,\n        methodName = transparentCorners ? 'stroke' : 'fill',\n        stroke = !transparentCorners && (\n          styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor\n        ), xSizeBy2 = xSize / 2, ySizeBy2 = ySize / 2;\n    ctx.save();\n    ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor;\n    ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor;\n    // this is still wrong\n    ctx.lineWidth = 1;\n    ctx.translate(left, top);\n    ctx.rotate(degreesToRadians(fabricObject.angle));\n    // this does not work, and fixed with ( && ) does not make sense.\n    // to have real transparent corners we need the controls on upperCanvas\n    // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\n    ctx[methodName + 'Rect'](-xSizeBy2, -ySizeBy2, xSize, ySize);\n    if (stroke) {\n      ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\n    }\n    ctx.restore();\n  }\n\n  controls.renderCircleControl = renderCircleControl;\n  controls.renderSquareControl = renderSquareControl;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  function Control(options) {\n    for (var i in options) {\n      this[i] = options[i];\n    }\n  }\n\n  fabric.Control = Control;\n\n  fabric.Control.prototype = /** @lends fabric.Control.prototype */ {\n\n    /**\n     * keep track of control visibility.\n     * mainly for backward compatibility.\n     * if you do not want to see a control, you can remove it\n     * from the controlset.\n     * @type {Boolean}\n     * @default true\n     */\n    visible: true,\n\n    /**\n     * Name of the action that the control will likely execute.\n     * This is optional. FabricJS uses to identify what the user is doing for some\n     * extra optimizations. If you are writing a custom control and you want to know\n     * somewhere else in the code what is going on, you can use this string here.\n     * you can also provide a custom getActionName if your control run multiple actions\n     * depending on some external state.\n     * default to scale since is the most common, used on 4 corners by default\n     * @type {String}\n     * @default 'scale'\n     */\n    actionName: 'scale',\n\n    /**\n     * Drawing angle of the control.\n     * NOT used for now, but name marked as needed for internal logic\n     * example: to reuse the same drawing function for different rotated controls\n     * @type {Number}\n     * @default 0\n     */\n    angle: 0,\n\n    /**\n     * Relative position of the control. X\n     * 0,0 is the center of the Object, while -0.5 (left) or 0.5 (right) are the extremities\n     * of the bounding box.\n     * @type {Number}\n     * @default 0\n     */\n    x: 0,\n\n    /**\n     * Relative position of the control. Y\n     * 0,0 is the center of the Object, while -0.5 (top) or 0.5 (bottom) are the extremities\n     * of the bounding box.\n     * @type {Number}\n     * @default 0\n     */\n    y: 0,\n\n    /**\n     * Horizontal offset of the control from the defined position. In pixels\n     * Positive offset moves the control to the right, negative to the left.\n     * It used when you want to have position of control that does not scale with\n     * the bounding box. Example: rotation control is placed at x:0, y: 0.5 on\n     * the boundindbox, with an offset of 30 pixels vertically. Those 30 pixels will\n     * stay 30 pixels no matter how the object is big. Another example is having 2\n     * controls in the corner, that stay in the same position when the object scale.\n     * of the bounding box.\n     * @type {Number}\n     * @default 0\n     */\n    offsetX: 0,\n\n    /**\n     * Vertical offset of the control from the defined position. In pixels\n     * Positive offset moves the control to the bottom, negative to the top.\n     * @type {Number}\n     * @default 0\n     */\n    offsetY: 0,\n\n    /**\n     * Sets the length of the control. If null, defaults to object's cornerSize.\n     * Expects both sizeX and sizeY to be set when set.\n     * @type {?Number}\n     * @default null\n     */\n    sizeX: null,\n\n    /**\n     * Sets the height of the control. If null, defaults to object's cornerSize.\n     * Expects both sizeX and sizeY to be set when set.\n     * @type {?Number}\n     * @default null\n     */\n    sizeY: null,\n\n    /**\n     * Sets the length of the touch area of the control. If null, defaults to object's touchCornerSize.\n     * Expects both touchSizeX and touchSizeY to be set when set.\n     * @type {?Number}\n     * @default null\n     */\n    touchSizeX: null,\n\n    /**\n     * Sets the height of the touch area of the control. If null, defaults to object's touchCornerSize.\n     * Expects both touchSizeX and touchSizeY to be set when set.\n     * @type {?Number}\n     * @default null\n     */\n    touchSizeY: null,\n\n    /**\n     * Css cursor style to display when the control is hovered.\n     * if the method `cursorStyleHandler` is provided, this property is ignored.\n     * @type {String}\n     * @default 'crosshair'\n     */\n    cursorStyle: 'crosshair',\n\n    /**\n     * If controls has an offsetY or offsetX, draw a line that connects\n     * the control to the bounding box\n     * @type {Boolean}\n     * @default false\n     */\n    withConnection: false,\n\n    /**\n     * The control actionHandler, provide one to handle action ( control being moved )\n     * @param {Event} eventData the native mouse event\n     * @param {Object} transformData properties of the current transform\n     * @param {Number} x x position of the cursor\n     * @param {Number} y y position of the cursor\n     * @return {Boolean} true if the action/event modified the object\n     */\n    actionHandler: function(/* eventData, transformData, x, y */) { },\n\n    /**\n     * The control handler for mouse down, provide one to handle mouse down on control\n     * @param {Event} eventData the native mouse event\n     * @param {Object} transformData properties of the current transform\n     * @param {Number} x x position of the cursor\n     * @param {Number} y y position of the cursor\n     * @return {Boolean} true if the action/event modified the object\n     */\n    mouseDownHandler: function(/* eventData, transformData, x, y */) { },\n\n    /**\n     * The control mouseUpHandler, provide one to handle an effect on mouse up.\n     * @param {Event} eventData the native mouse event\n     * @param {Object} transformData properties of the current transform\n     * @param {Number} x x position of the cursor\n     * @param {Number} y y position of the cursor\n     * @return {Boolean} true if the action/event modified the object\n     */\n    mouseUpHandler: function(/* eventData, transformData, x, y */) { },\n\n    /**\n     * Returns control actionHandler\n     * @param {Event} eventData the native mouse event\n     * @param {fabric.Object} fabricObject on which the control is displayed\n     * @param {fabric.Control} control control for which the action handler is being asked\n     * @return {Function} the action handler\n     */\n    getActionHandler: function(/* eventData, fabricObject, control */) {\n      return this.actionHandler;\n    },\n\n    /**\n     * Returns control mouseDown handler\n     * @param {Event} eventData the native mouse event\n     * @param {fabric.Object} fabricObject on which the control is displayed\n     * @param {fabric.Control} control control for which the action handler is being asked\n     * @return {Function} the action handler\n     */\n    getMouseDownHandler: function(/* eventData, fabricObject, control */) {\n      return this.mouseDownHandler;\n    },\n\n    /**\n     * Returns control mouseUp handler\n     * @param {Event} eventData the native mouse event\n     * @param {fabric.Object} fabricObject on which the control is displayed\n     * @param {fabric.Control} control control for which the action handler is being asked\n     * @return {Function} the action handler\n     */\n    getMouseUpHandler: function(/* eventData, fabricObject, control */) {\n      return this.mouseUpHandler;\n    },\n\n    /**\n     * Returns control cursorStyle for css using cursorStyle. If you need a more elaborate\n     * function you can pass one in the constructor\n     * the cursorStyle property\n     * @param {Event} eventData the native mouse event\n     * @param {fabric.Control} control the current control ( likely this)\n     * @param {fabric.Object} object on which the control is displayed\n     * @return {String}\n     */\n    cursorStyleHandler: function(eventData, control /* fabricObject */) {\n      return control.cursorStyle;\n    },\n\n    /**\n     * Returns the action name. The basic implementation just return the actionName property.\n     * @param {Event} eventData the native mouse event\n     * @param {fabric.Control} control the current control ( likely this)\n     * @param {fabric.Object} object on which the control is displayed\n     * @return {String}\n     */\n    getActionName: function(eventData, control /* fabricObject */) {\n      return control.actionName;\n    },\n\n    /**\n     * Returns controls visibility\n     * @param {fabric.Object} object on which the control is displayed\n     * @param {String} controlKey key where the control is memorized on the\n     * @return {Boolean}\n     */\n    getVisibility: function(fabricObject, controlKey) {\n      var objectVisibility = fabricObject._controlsVisibility;\n      if (objectVisibility && typeof objectVisibility[controlKey] !== 'undefined') {\n        return objectVisibility[controlKey];\n      }\n      return this.visible;\n    },\n\n    /**\n     * Sets controls visibility\n     * @param {Boolean} visibility for the object\n     * @return {Void}\n     */\n    setVisibility: function(visibility /* name, fabricObject */) {\n      this.visible = visibility;\n    },\n\n\n    positionHandler: function(dim, finalMatrix /*, fabricObject, currentControl */) {\n      var point = fabric.util.transformPoint({\n        x: this.x * dim.x + this.offsetX,\n        y: this.y * dim.y + this.offsetY }, finalMatrix);\n      return point;\n    },\n\n    /**\n     * Returns the coords for this control based on object values.\n     * @param {Number} objectAngle angle from the fabric object holding the control\n     * @param {Number} objectCornerSize cornerSize from the fabric object holding the control (or touchCornerSize if\n     *   isTouch is true)\n     * @param {Number} centerX x coordinate where the control center should be\n     * @param {Number} centerY y coordinate where the control center should be\n     * @param {boolean} isTouch true if touch corner, false if normal corner\n     */\n    calcCornerCoords: function(objectAngle, objectCornerSize, centerX, centerY, isTouch) {\n      var cosHalfOffset,\n          sinHalfOffset,\n          cosHalfOffsetComp,\n          sinHalfOffsetComp,\n          xSize = (isTouch) ? this.touchSizeX : this.sizeX,\n          ySize = (isTouch) ? this.touchSizeY : this.sizeY;\n      if (xSize && ySize && xSize !== ySize) {\n        // handle rectangular corners\n        var controlTriangleAngle = Math.atan2(ySize, xSize);\n        var cornerHypotenuse = Math.sqrt(xSize * xSize + ySize * ySize) / 2;\n        var newTheta = controlTriangleAngle - fabric.util.degreesToRadians(objectAngle);\n        var newThetaComp = Math.PI / 2 - controlTriangleAngle - fabric.util.degreesToRadians(objectAngle);\n        cosHalfOffset = cornerHypotenuse * fabric.util.cos(newTheta);\n        sinHalfOffset = cornerHypotenuse * fabric.util.sin(newTheta);\n        // use complementary angle for two corners\n        cosHalfOffsetComp = cornerHypotenuse * fabric.util.cos(newThetaComp);\n        sinHalfOffsetComp = cornerHypotenuse * fabric.util.sin(newThetaComp);\n      }\n      else {\n        // handle square corners\n        // use default object corner size unless size is defined\n        var cornerSize = (xSize && ySize) ? xSize : objectCornerSize;\n        /* 0.7071067812 stands for sqrt(2)/2 */\n        cornerHypotenuse = cornerSize * 0.7071067812;\n        // complementary angles are equal since they're both 45 degrees\n        var newTheta = fabric.util.degreesToRadians(45 - objectAngle);\n        cosHalfOffset = cosHalfOffsetComp = cornerHypotenuse * fabric.util.cos(newTheta);\n        sinHalfOffset = sinHalfOffsetComp = cornerHypotenuse * fabric.util.sin(newTheta);\n      }\n\n      return {\n        tl: {\n          x: centerX - sinHalfOffsetComp,\n          y: centerY - cosHalfOffsetComp,\n        },\n        tr: {\n          x: centerX + cosHalfOffset,\n          y: centerY - sinHalfOffset,\n        },\n        bl: {\n          x: centerX - cosHalfOffset,\n          y: centerY + sinHalfOffset,\n        },\n        br: {\n          x: centerX + sinHalfOffsetComp,\n          y: centerY + cosHalfOffsetComp,\n        },\n      };\n    },\n\n    /**\n    * Render function for the control.\n    * When this function runs the context is unscaled. unrotate. Just retina scaled.\n    * all the functions will have to translate to the point left,top before starting Drawing\n    * if they want to draw a control where the position is detected.\n    * left and top are the result of the positionHandler function\n    * @param {RenderingContext2D} ctx the context where the control will be drawn\n    * @param {Number} left position of the canvas where we are about to render the control.\n    * @param {Number} top position of the canvas where we are about to render the control.\n    * @param {Object} styleOverride\n    * @param {fabric.Object} fabricObject the object where the control is about to be rendered\n    */\n    render: function(ctx, left, top, styleOverride, fabricObject) {\n      styleOverride = styleOverride || {};\n      switch (styleOverride.cornerStyle || fabricObject.cornerStyle) {\n        case 'circle':\n          fabric.controlsUtils.renderCircleControl.call(this, ctx, left, top, styleOverride, fabricObject);\n          break;\n        default:\n          fabric.controlsUtils.renderSquareControl.call(this, ctx, left, top, styleOverride, fabricObject);\n      }\n    },\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  /* _FROM_SVG_START_ */\n  function getColorStop(el, multiplier) {\n    var style = el.getAttribute('style'),\n        offset = el.getAttribute('offset') || 0,\n        color, colorAlpha, opacity, i;\n\n    // convert percents to absolute values\n    offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);\n    offset = offset < 0 ? 0 : offset > 1 ? 1 : offset;\n    if (style) {\n      var keyValuePairs = style.split(/\\s*;\\s*/);\n\n      if (keyValuePairs[keyValuePairs.length - 1] === '') {\n        keyValuePairs.pop();\n      }\n\n      for (i = keyValuePairs.length; i--; ) {\n\n        var split = keyValuePairs[i].split(/\\s*:\\s*/),\n            key = split[0].trim(),\n            value = split[1].trim();\n\n        if (key === 'stop-color') {\n          color = value;\n        }\n        else if (key === 'stop-opacity') {\n          opacity = value;\n        }\n      }\n    }\n\n    if (!color) {\n      color = el.getAttribute('stop-color') || 'rgb(0,0,0)';\n    }\n    if (!opacity) {\n      opacity = el.getAttribute('stop-opacity');\n    }\n\n    color = new fabric.Color(color);\n    colorAlpha = color.getAlpha();\n    opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);\n    opacity *= colorAlpha * multiplier;\n\n    return {\n      offset: offset,\n      color: color.toRgb(),\n      opacity: opacity\n    };\n  }\n\n  function getLinearCoords(el) {\n    return {\n      x1: el.getAttribute('x1') || 0,\n      y1: el.getAttribute('y1') || 0,\n      x2: el.getAttribute('x2') || '100%',\n      y2: el.getAttribute('y2') || 0\n    };\n  }\n\n  function getRadialCoords(el) {\n    return {\n      x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',\n      y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',\n      r1: 0,\n      x2: el.getAttribute('cx') || '50%',\n      y2: el.getAttribute('cy') || '50%',\n      r2: el.getAttribute('r') || '50%'\n    };\n  }\n  /* _FROM_SVG_END_ */\n\n  var clone = fabric.util.object.clone;\n\n  /**\n   * Gradient class\n   * @class fabric.Gradient\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#gradients}\n   * @see {@link fabric.Gradient#initialize} for constructor definition\n   */\n  fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {\n\n    /**\n     * Horizontal offset for aligning gradients coming from SVG when outside pathgroups\n     * @type Number\n     * @default 0\n     */\n    offsetX: 0,\n\n    /**\n     * Vertical offset for aligning gradients coming from SVG when outside pathgroups\n     * @type Number\n     * @default 0\n     */\n    offsetY: 0,\n\n    /**\n     * A transform matrix to apply to the gradient before painting.\n     * Imported from svg gradients, is not applied with the current transform in the center.\n     * Before this transform is applied, the origin point is at the top left corner of the object\n     * plus the addition of offsetY and offsetX.\n     * @type Number[]\n     * @default null\n     */\n    gradientTransform: null,\n\n    /**\n     * coordinates units for coords.\n     * If `pixels`, the number of coords are in the same unit of width / height.\n     * If set as `percentage` the coords are still a number, but 1 means 100% of width\n     * for the X and 100% of the height for the y. It can be bigger than 1 and negative.\n     * allowed values pixels or percentage.\n     * @type String\n     * @default 'pixels'\n     */\n    gradientUnits: 'pixels',\n\n    /**\n     * Gradient type linear or radial\n     * @type String\n     * @default 'pixels'\n     */\n    type: 'linear',\n\n    /**\n     * Constructor\n     * @param {Object} options Options object with type, coords, gradientUnits and colorStops\n     * @param {Object} [options.type] gradient type linear or radial\n     * @param {Object} [options.gradientUnits] gradient units\n     * @param {Object} [options.offsetX] SVG import compatibility\n     * @param {Object} [options.offsetY] SVG import compatibility\n     * @param {Object[]} options.colorStops contains the colorstops.\n     * @param {Object} options.coords contains the coords of the gradient\n     * @param {Number} [options.coords.x1] X coordiante of the first point for linear or of the focal point for radial\n     * @param {Number} [options.coords.y1] Y coordiante of the first point for linear or of the focal point for radial\n     * @param {Number} [options.coords.x2] X coordiante of the second point for linear or of the center point for radial\n     * @param {Number} [options.coords.y2] Y coordiante of the second point for linear or of the center point for radial\n     * @param {Number} [options.coords.r1] only for radial gradient, radius of the inner circle\n     * @param {Number} [options.coords.r2] only for radial gradient, radius of the external circle\n     * @return {fabric.Gradient} thisArg\n     */\n    initialize: function(options) {\n      options || (options = { });\n      options.coords || (options.coords = { });\n\n      var coords, _this = this;\n\n      // sets everything, then coords and colorstops get sets again\n      Object.keys(options).forEach(function(option) {\n        _this[option] = options[option];\n      });\n\n      if (this.id) {\n        this.id += '_' + fabric.Object.__uid++;\n      }\n      else {\n        this.id = fabric.Object.__uid++;\n      }\n\n      coords = {\n        x1: options.coords.x1 || 0,\n        y1: options.coords.y1 || 0,\n        x2: options.coords.x2 || 0,\n        y2: options.coords.y2 || 0\n      };\n\n      if (this.type === 'radial') {\n        coords.r1 = options.coords.r1 || 0;\n        coords.r2 = options.coords.r2 || 0;\n      }\n\n      this.coords = coords;\n      this.colorStops = options.colorStops.slice();\n    },\n\n    /**\n     * Adds another colorStop\n     * @param {Object} colorStop Object with offset and color\n     * @return {fabric.Gradient} thisArg\n     */\n    addColorStop: function(colorStops) {\n      for (var position in colorStops) {\n        var color = new fabric.Color(colorStops[position]);\n        this.colorStops.push({\n          offset: parseFloat(position),\n          color: color.toRgb(),\n          opacity: color.getAlpha()\n        });\n      }\n      return this;\n    },\n\n    /**\n     * Returns object representation of a gradient\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object}\n     */\n    toObject: function(propertiesToInclude) {\n      var object = {\n        type: this.type,\n        coords: this.coords,\n        colorStops: this.colorStops,\n        offsetX: this.offsetX,\n        offsetY: this.offsetY,\n        gradientUnits: this.gradientUnits,\n        gradientTransform: this.gradientTransform ? this.gradientTransform.concat() : this.gradientTransform\n      };\n      fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n      return object;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of an gradient\n     * @param {Object} object Object to create a gradient for\n     * @return {String} SVG representation of an gradient (linear/radial)\n     */\n    toSVG: function(object, options) {\n      var coords = clone(this.coords, true), i, len, options = options || {},\n          markup, commonAttributes, colorStops = clone(this.colorStops, true),\n          needsSwap = coords.r1 > coords.r2,\n          transform = this.gradientTransform ? this.gradientTransform.concat() : fabric.iMatrix.concat(),\n          offsetX = -this.offsetX, offsetY = -this.offsetY,\n          withViewport = !!options.additionalTransform,\n          gradientUnits = this.gradientUnits === 'pixels' ? 'userSpaceOnUse' : 'objectBoundingBox';\n      // colorStops must be sorted ascending\n      colorStops.sort(function(a, b) {\n        return a.offset - b.offset;\n      });\n\n      if (gradientUnits === 'objectBoundingBox') {\n        offsetX /= object.width;\n        offsetY /= object.height;\n      }\n      else {\n        offsetX += object.width / 2;\n        offsetY += object.height / 2;\n      }\n      if (object.type === 'path' && this.gradientUnits !== 'percentage') {\n        offsetX -= object.pathOffset.x;\n        offsetY -= object.pathOffset.y;\n      }\n\n\n      transform[4] -= offsetX;\n      transform[5] -= offsetY;\n\n      commonAttributes = 'id=\"SVGID_' + this.id +\n                     '\" gradientUnits=\"' + gradientUnits + '\"';\n      commonAttributes += ' gradientTransform=\"' + (withViewport ?\n        options.additionalTransform + ' ' : '') + fabric.util.matrixToSVG(transform) + '\" ';\n\n      if (this.type === 'linear') {\n        markup = [\n          '<linearGradient ',\n          commonAttributes,\n          ' x1=\"', coords.x1,\n          '\" y1=\"', coords.y1,\n          '\" x2=\"', coords.x2,\n          '\" y2=\"', coords.y2,\n          '\">\\n'\n        ];\n      }\n      else if (this.type === 'radial') {\n        // svg radial gradient has just 1 radius. the biggest.\n        markup = [\n          '<radialGradient ',\n          commonAttributes,\n          ' cx=\"', needsSwap ? coords.x1 : coords.x2,\n          '\" cy=\"', needsSwap ? coords.y1 : coords.y2,\n          '\" r=\"', needsSwap ? coords.r1 : coords.r2,\n          '\" fx=\"', needsSwap ? coords.x2 : coords.x1,\n          '\" fy=\"', needsSwap ? coords.y2 : coords.y1,\n          '\">\\n'\n        ];\n      }\n\n      if (this.type === 'radial') {\n        if (needsSwap) {\n          // svg goes from internal to external radius. if radius are inverted, swap color stops.\n          colorStops = colorStops.concat();\n          colorStops.reverse();\n          for (i = 0, len = colorStops.length; i < len; i++) {\n            colorStops[i].offset = 1 - colorStops[i].offset;\n          }\n        }\n        var minRadius = Math.min(coords.r1, coords.r2);\n        if (minRadius > 0) {\n          // i have to shift all colorStops and add new one in 0.\n          var maxRadius = Math.max(coords.r1, coords.r2),\n              percentageShift = minRadius / maxRadius;\n          for (i = 0, len = colorStops.length; i < len; i++) {\n            colorStops[i].offset += percentageShift * (1 - colorStops[i].offset);\n          }\n        }\n      }\n\n      for (i = 0, len = colorStops.length; i < len; i++) {\n        var colorStop = colorStops[i];\n        markup.push(\n          '<stop ',\n          'offset=\"', (colorStop.offset * 100) + '%',\n          '\" style=\"stop-color:', colorStop.color,\n          (typeof colorStop.opacity !== 'undefined' ? ';stop-opacity: ' + colorStop.opacity : ';'),\n          '\"/>\\n'\n        );\n      }\n\n      markup.push((this.type === 'linear' ? '</linearGradient>\\n' : '</radialGradient>\\n'));\n\n      return markup.join('');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns an instance of CanvasGradient\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @return {CanvasGradient}\n     */\n    toLive: function(ctx) {\n      var gradient, coords = fabric.util.object.clone(this.coords), i, len;\n\n      if (!this.type) {\n        return;\n      }\n\n      if (this.type === 'linear') {\n        gradient = ctx.createLinearGradient(\n          coords.x1, coords.y1, coords.x2, coords.y2);\n      }\n      else if (this.type === 'radial') {\n        gradient = ctx.createRadialGradient(\n          coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2);\n      }\n\n      for (i = 0, len = this.colorStops.length; i < len; i++) {\n        var color = this.colorStops[i].color,\n            opacity = this.colorStops[i].opacity,\n            offset = this.colorStops[i].offset;\n\n        if (typeof opacity !== 'undefined') {\n          color = new fabric.Color(color).setAlpha(opacity).toRgba();\n        }\n        gradient.addColorStop(offset, color);\n      }\n\n      return gradient;\n    }\n  });\n\n  fabric.util.object.extend(fabric.Gradient, {\n\n    /* _FROM_SVG_START_ */\n    /**\n     * Returns {@link fabric.Gradient} instance from an SVG element\n     * @static\n     * @memberOf fabric.Gradient\n     * @param {SVGGradientElement} el SVG gradient element\n     * @param {fabric.Object} instance\n     * @param {String} opacityAttr A fill-opacity or stroke-opacity attribute to multiply to each stop's opacity.\n     * @param {Object} svgOptions an object containing the size of the SVG in order to parse correctly gradients\n     * that uses gradientUnits as 'userSpaceOnUse' and percentages.\n     * @param {Object.number} viewBoxWidth width part of the viewBox attribute on svg\n     * @param {Object.number} viewBoxHeight height part of the viewBox attribute on svg\n     * @param {Object.number} width width part of the svg tag if viewBox is not specified\n     * @param {Object.number} height height part of the svg tag if viewBox is not specified\n     * @return {fabric.Gradient} Gradient instance\n     * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement\n     * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement\n     */\n    fromElement: function(el, instance, opacityAttr, svgOptions) {\n      /**\n       *  @example:\n       *\n       *  <linearGradient id=\"linearGrad1\">\n       *    <stop offset=\"0%\" stop-color=\"white\"/>\n       *    <stop offset=\"100%\" stop-color=\"black\"/>\n       *  </linearGradient>\n       *\n       *  OR\n       *\n       *  <linearGradient id=\"linearGrad2\">\n       *    <stop offset=\"0\" style=\"stop-color:rgb(255,255,255)\"/>\n       *    <stop offset=\"1\" style=\"stop-color:rgb(0,0,0)\"/>\n       *  </linearGradient>\n       *\n       *  OR\n       *\n       *  <radialGradient id=\"radialGrad1\">\n       *    <stop offset=\"0%\" stop-color=\"white\" stop-opacity=\"1\" />\n       *    <stop offset=\"50%\" stop-color=\"black\" stop-opacity=\"0.5\" />\n       *    <stop offset=\"100%\" stop-color=\"white\" stop-opacity=\"1\" />\n       *  </radialGradient>\n       *\n       *  OR\n       *\n       *  <radialGradient id=\"radialGrad2\">\n       *    <stop offset=\"0\" stop-color=\"rgb(255,255,255)\" />\n       *    <stop offset=\"0.5\" stop-color=\"rgb(0,0,0)\" />\n       *    <stop offset=\"1\" stop-color=\"rgb(255,255,255)\" />\n       *  </radialGradient>\n       *\n       */\n\n      var multiplier = parseFloat(opacityAttr) / (/%$/.test(opacityAttr) ? 100 : 1);\n      multiplier = multiplier < 0 ? 0 : multiplier > 1 ? 1 : multiplier;\n      if (isNaN(multiplier)) {\n        multiplier = 1;\n      }\n\n      var colorStopEls = el.getElementsByTagName('stop'),\n          type,\n          gradientUnits = el.getAttribute('gradientUnits') === 'userSpaceOnUse' ?\n            'pixels' : 'percentage',\n          gradientTransform = el.getAttribute('gradientTransform') || '',\n          colorStops = [],\n          coords, i, offsetX = 0, offsetY = 0,\n          transformMatrix;\n      if (el.nodeName === 'linearGradient' || el.nodeName === 'LINEARGRADIENT') {\n        type = 'linear';\n        coords = getLinearCoords(el);\n      }\n      else {\n        type = 'radial';\n        coords = getRadialCoords(el);\n      }\n\n      for (i = colorStopEls.length; i--; ) {\n        colorStops.push(getColorStop(colorStopEls[i], multiplier));\n      }\n\n      transformMatrix = fabric.parseTransformAttribute(gradientTransform);\n\n      __convertPercentUnitsToValues(instance, coords, svgOptions, gradientUnits);\n\n      if (gradientUnits === 'pixels') {\n        offsetX = -instance.left;\n        offsetY = -instance.top;\n      }\n\n      var gradient = new fabric.Gradient({\n        id: el.getAttribute('id'),\n        type: type,\n        coords: coords,\n        colorStops: colorStops,\n        gradientUnits: gradientUnits,\n        gradientTransform: transformMatrix,\n        offsetX: offsetX,\n        offsetY: offsetY,\n      });\n\n      return gradient;\n    }\n    /* _FROM_SVG_END_ */\n  });\n\n  /**\n   * @private\n   */\n  function __convertPercentUnitsToValues(instance, options, svgOptions, gradientUnits) {\n    var propValue, finalValue;\n    Object.keys(options).forEach(function(prop) {\n      propValue = options[prop];\n      if (propValue === 'Infinity') {\n        finalValue = 1;\n      }\n      else if (propValue === '-Infinity') {\n        finalValue = 0;\n      }\n      else {\n        finalValue = parseFloat(options[prop], 10);\n        if (typeof propValue === 'string' && /^(\\d+\\.\\d+)%|(\\d+)%$/.test(propValue)) {\n          finalValue *= 0.01;\n          if (gradientUnits === 'pixels') {\n            // then we need to fix those percentages here in svg parsing\n            if (prop === 'x1' || prop === 'x2' || prop === 'r2') {\n              finalValue *= svgOptions.viewBoxWidth || svgOptions.width;\n            }\n            if (prop === 'y1' || prop === 'y2') {\n              finalValue *= svgOptions.viewBoxHeight || svgOptions.height;\n            }\n          }\n        }\n      }\n      options[prop] = finalValue;\n    });\n  }\n})();\n\n\n(function() {\n\n  'use strict';\n\n  var toFixed = fabric.util.toFixed;\n\n  /**\n   * Pattern class\n   * @class fabric.Pattern\n   * @see {@link http://fabricjs.com/patterns|Pattern demo}\n   * @see {@link http://fabricjs.com/dynamic-patterns|DynamicPattern demo}\n   * @see {@link fabric.Pattern#initialize} for constructor definition\n   */\n\n\n  fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ {\n\n    /**\n     * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n     * @type String\n     * @default\n     */\n    repeat: 'repeat',\n\n    /**\n     * Pattern horizontal offset from object's left/top corner\n     * @type Number\n     * @default\n     */\n    offsetX: 0,\n\n    /**\n     * Pattern vertical offset from object's left/top corner\n     * @type Number\n     * @default\n     */\n    offsetY: 0,\n\n    /**\n     * crossOrigin value (one of \"\", \"anonymous\", \"use-credentials\")\n     * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes\n     * @type String\n     * @default\n     */\n    crossOrigin: '',\n\n    /**\n     * transform matrix to change the pattern, imported from svgs.\n     * @type Array\n     * @default\n     */\n    patternTransform: null,\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @param {Function} [callback] function to invoke after callback init.\n     * @return {fabric.Pattern} thisArg\n     */\n    initialize: function(options, callback) {\n      options || (options = { });\n\n      this.id = fabric.Object.__uid++;\n      this.setOptions(options);\n      if (!options.source || (options.source && typeof options.source !== 'string')) {\n        callback && callback(this);\n        return;\n      }\n      else {\n        // img src string\n        var _this = this;\n        this.source = fabric.util.createImage();\n        fabric.util.loadImage(options.source, function(img, isError) {\n          _this.source = img;\n          callback && callback(_this, isError);\n        }, null, this.crossOrigin);\n      }\n    },\n\n    /**\n     * Returns object representation of a pattern\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of a pattern instance\n     */\n    toObject: function(propertiesToInclude) {\n      var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n          source, object;\n\n      // <img> element\n      if (typeof this.source.src === 'string') {\n        source = this.source.src;\n      }\n      // <canvas> element\n      else if (typeof this.source === 'object' && this.source.toDataURL) {\n        source = this.source.toDataURL();\n      }\n\n      object = {\n        type: 'pattern',\n        source: source,\n        repeat: this.repeat,\n        crossOrigin: this.crossOrigin,\n        offsetX: toFixed(this.offsetX, NUM_FRACTION_DIGITS),\n        offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS),\n        patternTransform: this.patternTransform ? this.patternTransform.concat() : null\n      };\n      fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n      return object;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of a pattern\n     * @param {fabric.Object} object\n     * @return {String} SVG representation of a pattern\n     */\n    toSVG: function(object) {\n      var patternSource = typeof this.source === 'function' ? this.source() : this.source,\n          patternWidth = patternSource.width / object.width,\n          patternHeight = patternSource.height / object.height,\n          patternOffsetX = this.offsetX / object.width,\n          patternOffsetY = this.offsetY / object.height,\n          patternImgSrc = '';\n      if (this.repeat === 'repeat-x' || this.repeat === 'no-repeat') {\n        patternHeight = 1;\n        if (patternOffsetY) {\n          patternHeight += Math.abs(patternOffsetY);\n        }\n      }\n      if (this.repeat === 'repeat-y' || this.repeat === 'no-repeat') {\n        patternWidth = 1;\n        if (patternOffsetX) {\n          patternWidth += Math.abs(patternOffsetX);\n        }\n\n      }\n      if (patternSource.src) {\n        patternImgSrc = patternSource.src;\n      }\n      else if (patternSource.toDataURL) {\n        patternImgSrc = patternSource.toDataURL();\n      }\n\n      return '<pattern id=\"SVGID_' + this.id +\n                    '\" x=\"' + patternOffsetX +\n                    '\" y=\"' + patternOffsetY +\n                    '\" width=\"' + patternWidth +\n                    '\" height=\"' + patternHeight + '\">\\n' +\n               '<image x=\"0\" y=\"0\"' +\n                      ' width=\"' + patternSource.width +\n                      '\" height=\"' + patternSource.height +\n                      '\" xlink:href=\"' + patternImgSrc +\n               '\"></image>\\n' +\n             '</pattern>\\n';\n    },\n    /* _TO_SVG_END_ */\n\n    setOptions: function(options) {\n      for (var prop in options) {\n        this[prop] = options[prop];\n      }\n    },\n\n    /**\n     * Returns an instance of CanvasPattern\n     * @param {CanvasRenderingContext2D} ctx Context to create pattern\n     * @return {CanvasPattern}\n     */\n    toLive: function(ctx) {\n      var source = this.source;\n      // if the image failed to load, return, and allow rest to continue loading\n      if (!source) {\n        return '';\n      }\n\n      // if an image\n      if (typeof source.src !== 'undefined') {\n        if (!source.complete) {\n          return '';\n        }\n        if (source.naturalWidth === 0 || source.naturalHeight === 0) {\n          return '';\n        }\n      }\n      return ctx.createPattern(source, this.repeat);\n    }\n  });\n})();\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      toFixed = fabric.util.toFixed;\n\n  if (fabric.Shadow) {\n    fabric.warn('fabric.Shadow is already defined.');\n    return;\n  }\n\n  /**\n   * Shadow class\n   * @class fabric.Shadow\n   * @see {@link http://fabricjs.com/shadows|Shadow demo}\n   * @see {@link fabric.Shadow#initialize} for constructor definition\n   */\n  fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {\n\n    /**\n     * Shadow color\n     * @type String\n     * @default\n     */\n    color: 'rgb(0,0,0)',\n\n    /**\n     * Shadow blur\n     * @type Number\n     */\n    blur: 0,\n\n    /**\n     * Shadow horizontal offset\n     * @type Number\n     * @default\n     */\n    offsetX: 0,\n\n    /**\n     * Shadow vertical offset\n     * @type Number\n     * @default\n     */\n    offsetY: 0,\n\n    /**\n     * Whether the shadow should affect stroke operations\n     * @type Boolean\n     * @default\n     */\n    affectStroke: false,\n\n    /**\n     * Indicates whether toObject should include default values\n     * @type Boolean\n     * @default\n     */\n    includeDefaultValues: true,\n\n    /**\n     * When `false`, the shadow will scale with the object.\n     * When `true`, the shadow's offsetX, offsetY, and blur will not be affected by the object's scale.\n     * default to false\n     * @type Boolean\n     * @default\n     */\n    nonScaling: false,\n\n    /**\n     * Constructor\n     * @param {Object|String} [options] Options object with any of color, blur, offsetX, offsetY properties or string (e.g. \"rgba(0,0,0,0.2) 2px 2px 10px\")\n     * @return {fabric.Shadow} thisArg\n     */\n    initialize: function(options) {\n\n      if (typeof options === 'string') {\n        options = this._parseShadow(options);\n      }\n\n      for (var prop in options) {\n        this[prop] = options[prop];\n      }\n\n      this.id = fabric.Object.__uid++;\n    },\n\n    /**\n     * @private\n     * @param {String} shadow Shadow value to parse\n     * @return {Object} Shadow object with color, offsetX, offsetY and blur\n     */\n    _parseShadow: function(shadow) {\n      var shadowStr = shadow.trim(),\n          offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [],\n          color = shadowStr.replace(fabric.Shadow.reOffsetsAndBlur, '') || 'rgb(0,0,0)';\n\n      return {\n        color: color.trim(),\n        offsetX: parseFloat(offsetsAndBlur[1], 10) || 0,\n        offsetY: parseFloat(offsetsAndBlur[2], 10) || 0,\n        blur: parseFloat(offsetsAndBlur[3], 10) || 0\n      };\n    },\n\n    /**\n     * Returns a string representation of an instance\n     * @see http://www.w3.org/TR/css-text-decor-3/#text-shadow\n     * @return {String} Returns CSS3 text-shadow declaration\n     */\n    toString: function() {\n      return [this.offsetX, this.offsetY, this.blur, this.color].join('px ');\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns SVG representation of a shadow\n     * @param {fabric.Object} object\n     * @return {String} SVG representation of a shadow\n     */\n    toSVG: function(object) {\n      var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n          offset = fabric.util.rotateVector(\n            { x: this.offsetX, y: this.offsetY },\n            fabric.util.degreesToRadians(-object.angle)),\n          BLUR_BOX = 20, color = new fabric.Color(this.color);\n\n      if (object.width && object.height) {\n        //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion\n        // we add some extra space to filter box to contain the blur ( 20 )\n        fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;\n        fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;\n      }\n      if (object.flipX) {\n        offset.x *= -1;\n      }\n      if (object.flipY) {\n        offset.y *= -1;\n      }\n\n      return (\n        '<filter id=\"SVGID_' + this.id + '\" y=\"-' + fBoxY + '%\" height=\"' + (100 + 2 * fBoxY) + '%\" ' +\n          'x=\"-' + fBoxX + '%\" width=\"' + (100 + 2 * fBoxX) + '%\" ' + '>\\n' +\n          '\\t<feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"' +\n            toFixed(this.blur ? this.blur / 2 : 0, NUM_FRACTION_DIGITS) + '\"></feGaussianBlur>\\n' +\n          '\\t<feOffset dx=\"' + toFixed(offset.x, NUM_FRACTION_DIGITS) +\n          '\" dy=\"' + toFixed(offset.y, NUM_FRACTION_DIGITS) + '\" result=\"oBlur\" ></feOffset>\\n' +\n          '\\t<feFlood flood-color=\"' + color.toRgb() + '\" flood-opacity=\"' + color.getAlpha() + '\"/>\\n' +\n          '\\t<feComposite in2=\"oBlur\" operator=\"in\" />\\n' +\n          '\\t<feMerge>\\n' +\n            '\\t\\t<feMergeNode></feMergeNode>\\n' +\n            '\\t\\t<feMergeNode in=\"SourceGraphic\"></feMergeNode>\\n' +\n          '\\t</feMerge>\\n' +\n        '</filter>\\n');\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns object representation of a shadow\n     * @return {Object} Object representation of a shadow instance\n     */\n    toObject: function() {\n      if (this.includeDefaultValues) {\n        return {\n          color: this.color,\n          blur: this.blur,\n          offsetX: this.offsetX,\n          offsetY: this.offsetY,\n          affectStroke: this.affectStroke,\n          nonScaling: this.nonScaling\n        };\n      }\n      var obj = { }, proto = fabric.Shadow.prototype;\n\n      ['color', 'blur', 'offsetX', 'offsetY', 'affectStroke', 'nonScaling'].forEach(function(prop) {\n        if (this[prop] !== proto[prop]) {\n          obj[prop] = this[prop];\n        }\n      }, this);\n\n      return obj;\n    }\n  });\n\n  /**\n   * Regex matching shadow offsetX, offsetY and blur (ex: \"2px 2px 10px rgba(0,0,0,0.2)\", \"rgb(0,255,0) 2px 2px\")\n   * @static\n   * @field\n   * @memberOf fabric.Shadow\n   */\n  // eslint-disable-next-line max-len\n  fabric.Shadow.reOffsetsAndBlur = /(?:\\s|^)(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?(\\d+(?:\\.\\d*)?(?:px)?)?(?:\\s?|$)(?:$|\\s)/;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function () {\n\n  'use strict';\n\n  if (fabric.StaticCanvas) {\n    fabric.warn('fabric.StaticCanvas is already defined.');\n    return;\n  }\n\n  // aliases for faster resolution\n  var extend = fabric.util.object.extend,\n      getElementOffset = fabric.util.getElementOffset,\n      removeFromArray = fabric.util.removeFromArray,\n      toFixed = fabric.util.toFixed,\n      transformPoint = fabric.util.transformPoint,\n      invertTransform = fabric.util.invertTransform,\n      getNodeCanvas = fabric.util.getNodeCanvas,\n      createCanvasElement = fabric.util.createCanvasElement,\n\n      CANVAS_INIT_ERROR = new Error('Could not initialize `canvas` element');\n\n  /**\n   * Static canvas class\n   * @class fabric.StaticCanvas\n   * @mixes fabric.Collection\n   * @mixes fabric.Observable\n   * @see {@link http://fabricjs.com/static_canvas|StaticCanvas demo}\n   * @see {@link fabric.StaticCanvas#initialize} for constructor definition\n   * @fires before:render\n   * @fires after:render\n   * @fires canvas:cleared\n   * @fires object:added\n   * @fires object:removed\n   */\n  fabric.StaticCanvas = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Constructor\n     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(el, options) {\n      options || (options = { });\n      this.renderAndResetBound = this.renderAndReset.bind(this);\n      this.requestRenderAllBound = this.requestRenderAll.bind(this);\n      this._initStatic(el, options);\n    },\n\n    /**\n     * Background color of canvas instance.\n     * Should be set via {@link fabric.StaticCanvas#setBackgroundColor}.\n     * @type {(String|fabric.Pattern)}\n     * @default\n     */\n    backgroundColor: '',\n\n    /**\n     * Background image of canvas instance.\n     * since 2.4.0 image caching is active, please when putting an image as background, add to the\n     * canvas property a reference to the canvas it is on. Otherwise the image cannot detect the zoom\n     * vale. As an alternative you can disable image objectCaching\n     * @type fabric.Image\n     * @default\n     */\n    backgroundImage: null,\n\n    /**\n     * Overlay color of canvas instance.\n     * Should be set via {@link fabric.StaticCanvas#setOverlayColor}\n     * @since 1.3.9\n     * @type {(String|fabric.Pattern)}\n     * @default\n     */\n    overlayColor: '',\n\n    /**\n     * Overlay image of canvas instance.\n     * since 2.4.0 image caching is active, please when putting an image as overlay, add to the\n     * canvas property a reference to the canvas it is on. Otherwise the image cannot detect the zoom\n     * vale. As an alternative you can disable image objectCaching\n     * @type fabric.Image\n     * @default\n     */\n    overlayImage: null,\n\n    /**\n     * Indicates whether toObject/toDatalessObject should include default values\n     * if set to false, takes precedence over the object value.\n     * @type Boolean\n     * @default\n     */\n    includeDefaultValues: true,\n\n    /**\n     * Indicates whether objects' state should be saved\n     * @type Boolean\n     * @default\n     */\n    stateful: false,\n\n    /**\n     * Indicates whether {@link fabric.Collection.add}, {@link fabric.Collection.insertAt} and {@link fabric.Collection.remove},\n     * {@link fabric.StaticCanvas.moveTo}, {@link fabric.StaticCanvas.clear} and many more, should also re-render canvas.\n     * Disabling this option will not give a performance boost when adding/removing a lot of objects to/from canvas at once\n     * since the renders are quequed and executed one per frame.\n     * Disabling is suggested anyway and managing the renders of the app manually is not a big effort ( canvas.requestRenderAll() )\n     * Left default to true to do not break documentation and old app, fiddles.\n     * @type Boolean\n     * @default\n     */\n    renderOnAddRemove: true,\n\n    /**\n     * Indicates whether object controls (borders/controls) are rendered above overlay image\n     * @type Boolean\n     * @default\n     */\n    controlsAboveOverlay: false,\n\n    /**\n     * Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas\n     * @type Boolean\n     * @default\n     */\n    allowTouchScrolling: false,\n\n    /**\n     * Indicates whether this canvas will use image smoothing, this is on by default in browsers\n     * @type Boolean\n     * @default\n     */\n    imageSmoothingEnabled: true,\n\n    /**\n     * The transformation (a Canvas 2D API transform matrix) which focuses the viewport\n     * @type Array\n     * @example <caption>Default transform</caption>\n     * canvas.viewportTransform = [1, 0, 0, 1, 0, 0];\n     * @example <caption>Scale by 70% and translate toward bottom-right by 50, without skewing</caption>\n     * canvas.viewportTransform = [0.7, 0, 0, 0.7, 50, 50];\n     * @default\n     */\n    viewportTransform: fabric.iMatrix.concat(),\n\n    /**\n     * if set to false background image is not affected by viewport transform\n     * @since 1.6.3\n     * @type Boolean\n     * @default\n     */\n    backgroundVpt: true,\n\n    /**\n     * if set to false overlya image is not affected by viewport transform\n     * @since 1.6.3\n     * @type Boolean\n     * @default\n     */\n    overlayVpt: true,\n\n    /**\n     * When true, canvas is scaled by devicePixelRatio for better rendering on retina screens\n     * @type Boolean\n     * @default\n     */\n    enableRetinaScaling: true,\n\n    /**\n     * Describe canvas element extension over design\n     * properties are tl,tr,bl,br.\n     * if canvas is not zoomed/panned those points are the four corner of canvas\n     * if canvas is viewportTransformed you those points indicate the extension\n     * of canvas element in plain untrasformed coordinates\n     * The coordinates get updated with @method calcViewportBoundaries.\n     * @memberOf fabric.StaticCanvas.prototype\n     */\n    vptCoords: { },\n\n    /**\n     * Based on vptCoords and object.aCoords, skip rendering of objects that\n     * are not included in current viewport.\n     * May greatly help in applications with crowded canvas and use of zoom/pan\n     * If One of the corner of the bounding box of the object is on the canvas\n     * the objects get rendered.\n     * @memberOf fabric.StaticCanvas.prototype\n     * @type Boolean\n     * @default\n     */\n    skipOffscreen: true,\n\n    /**\n     * a fabricObject that, without stroke define a clipping area with their shape. filled in black\n     * the clipPath object gets used when the canvas has rendered, and the context is placed in the\n     * top left corner of the canvas.\n     * clipPath will clip away controls, if you do not want this to happen use controlsAboveOverlay = true\n     * @type fabric.Object\n     */\n    clipPath: undefined,\n\n    /**\n     * @private\n     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n     * @param {Object} [options] Options object\n     */\n    _initStatic: function(el, options) {\n      var cb = this.requestRenderAllBound;\n      this._objects = [];\n      this._createLowerCanvas(el);\n      this._initOptions(options);\n      // only initialize retina scaling once\n      if (!this.interactive) {\n        this._initRetinaScaling();\n      }\n\n      if (options.overlayImage) {\n        this.setOverlayImage(options.overlayImage, cb);\n      }\n      if (options.backgroundImage) {\n        this.setBackgroundImage(options.backgroundImage, cb);\n      }\n      if (options.backgroundColor) {\n        this.setBackgroundColor(options.backgroundColor, cb);\n      }\n      if (options.overlayColor) {\n        this.setOverlayColor(options.overlayColor, cb);\n      }\n      this.calcOffset();\n    },\n\n    /**\n     * @private\n     */\n    _isRetinaScaling: function() {\n      return (fabric.devicePixelRatio > 1 && this.enableRetinaScaling);\n    },\n\n    /**\n     * @private\n     * @return {Number} retinaScaling if applied, otherwise 1;\n     */\n    getRetinaScaling: function() {\n      return this._isRetinaScaling() ? Math.max(1, fabric.devicePixelRatio) : 1;\n    },\n\n    /**\n     * @private\n     */\n    _initRetinaScaling: function() {\n      if (!this._isRetinaScaling()) {\n        return;\n      }\n      var scaleRatio = fabric.devicePixelRatio;\n      this.__initRetinaScaling(scaleRatio, this.lowerCanvasEl, this.contextContainer);\n      if (this.upperCanvasEl) {\n        this.__initRetinaScaling(scaleRatio, this.upperCanvasEl, this.contextTop);\n      }\n    },\n\n    __initRetinaScaling: function(scaleRatio, canvas, context) {\n      canvas.setAttribute('width', this.width * scaleRatio);\n      canvas.setAttribute('height', this.height * scaleRatio);\n      context.scale(scaleRatio, scaleRatio);\n    },\n\n\n    /**\n     * Calculates canvas element offset relative to the document\n     * This method is also attached as \"resize\" event handler of window\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    calcOffset: function () {\n      this._offset = getElementOffset(this.lowerCanvasEl);\n      return this;\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas\n     * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to\n     * @param {Function} callback callback to invoke when image is loaded and set as an overlay\n     * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/MnzHT/|jsFiddle demo}\n     * @example <caption>Normal overlayImage with left/top = 0</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   // Needed to position overlayImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>overlayImage with different properties</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>Stretched overlayImage #1 - width/height correspond to canvas width/height</caption>\n     * fabric.Image.fromURL('http://fabricjs.com/assets/jail_cell_bars.png', function(img, isError) {\n     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n     *    canvas.setOverlayImage(img, canvas.renderAll.bind(canvas));\n     * });\n     * @example <caption>Stretched overlayImage #2 - width/height correspond to canvas width/height</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   width: canvas.width,\n     *   height: canvas.height,\n     *   // Needed to position overlayImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>overlayImage loaded from cross-origin</caption>\n     * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top',\n     *   crossOrigin: 'anonymous'\n     * });\n     */\n    setOverlayImage: function (image, callback, options) {\n      return this.__setBgOverlayImage('overlayImage', image, callback, options);\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas\n     * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to\n     * @param {Function} callback Callback to invoke when image is loaded and set as background\n     * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/djnr8o7a/28/|jsFiddle demo}\n     * @example <caption>Normal backgroundImage with left/top = 0</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   // Needed to position backgroundImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>backgroundImage with different properties</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>Stretched backgroundImage #1 - width/height correspond to canvas width/height</caption>\n     * fabric.Image.fromURL('http://fabricjs.com/assets/honey_im_subtle.png', function(img, isError) {\n     *    img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n     *    canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));\n     * });\n     * @example <caption>Stretched backgroundImage #2 - width/height correspond to canvas width/height</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   width: canvas.width,\n     *   height: canvas.height,\n     *   // Needed to position backgroundImage at 0/0\n     *   originX: 'left',\n     *   originY: 'top'\n     * });\n     * @example <caption>backgroundImage loaded from cross-origin</caption>\n     * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n     *   opacity: 0.5,\n     *   angle: 45,\n     *   left: 400,\n     *   top: 400,\n     *   originX: 'left',\n     *   originY: 'top',\n     *   crossOrigin: 'anonymous'\n     * });\n     */\n    // TODO: fix stretched examples\n    setBackgroundImage: function (image, callback, options) {\n      return this.__setBgOverlayImage('backgroundImage', image, callback, options);\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#overlayColor|foreground color} for this canvas\n     * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set foreground color to\n     * @param {Function} callback Callback to invoke when foreground color is set\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/pB55h/|jsFiddle demo}\n     * @example <caption>Normal overlayColor - color value</caption>\n     * canvas.setOverlayColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as overlayColor</caption>\n     * canvas.setOverlayColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'\n     * }, canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as overlayColor with repeat and offset</caption>\n     * canvas.setOverlayColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',\n     *   repeat: 'repeat',\n     *   offsetX: 200,\n     *   offsetY: 100\n     * }, canvas.renderAll.bind(canvas));\n     */\n    setOverlayColor: function(overlayColor, callback) {\n      return this.__setBgOverlayColor('overlayColor', overlayColor, callback);\n    },\n\n    /**\n     * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas\n     * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to\n     * @param {Function} callback Callback to invoke when background color is set\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     * @see {@link http://jsfiddle.net/fabricjs/hXzvk/|jsFiddle demo}\n     * @example <caption>Normal backgroundColor - color value</caption>\n     * canvas.setBackgroundColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as backgroundColor</caption>\n     * canvas.setBackgroundColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png'\n     * }, canvas.renderAll.bind(canvas));\n     * @example <caption>fabric.Pattern used as backgroundColor with repeat and offset</caption>\n     * canvas.setBackgroundColor({\n     *   source: 'http://fabricjs.com/assets/escheresque_ste.png',\n     *   repeat: 'repeat',\n     *   offsetX: 200,\n     *   offsetY: 100\n     * }, canvas.renderAll.bind(canvas));\n     */\n    setBackgroundColor: function(backgroundColor, callback) {\n      return this.__setBgOverlayColor('backgroundColor', backgroundColor, callback);\n    },\n\n    /**\n     * @private\n     * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage}\n     * or {@link fabric.StaticCanvas#overlayImage|overlayImage})\n     * @param {(fabric.Image|String|null)} image fabric.Image instance, URL of an image or null to set background or overlay to\n     * @param {Function} callback Callback to invoke when image is loaded and set as background or overlay. The first argument is the created image, the second argument is a flag indicating whether an error occurred or not.\n     * @param {Object} [options] Optional options to set for the {@link fabric.Image|image}.\n     */\n    __setBgOverlayImage: function(property, image, callback, options) {\n      if (typeof image === 'string') {\n        fabric.util.loadImage(image, function(img, isError) {\n          if (img) {\n            var instance = new fabric.Image(img, options);\n            this[property] = instance;\n            instance.canvas = this;\n          }\n          callback && callback(img, isError);\n        }, this, options && options.crossOrigin);\n      }\n      else {\n        options && image.setOptions(options);\n        this[property] = image;\n        image && (image.canvas = this);\n        callback && callback(image, false);\n      }\n\n      return this;\n    },\n\n    /**\n     * @private\n     * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor}\n     * or {@link fabric.StaticCanvas#overlayColor|overlayColor})\n     * @param {(Object|String|null)} color Object with pattern information, color value or null\n     * @param {Function} [callback] Callback is invoked when color is set\n     */\n    __setBgOverlayColor: function(property, color, callback) {\n      this[property] = color;\n      this._initGradient(color, property);\n      this._initPattern(color, property, callback);\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _createCanvasElement: function() {\n      var element = createCanvasElement();\n      if (!element) {\n        throw CANVAS_INIT_ERROR;\n      }\n      if (!element.style) {\n        element.style = { };\n      }\n      if (typeof element.getContext === 'undefined') {\n        throw CANVAS_INIT_ERROR;\n      }\n      return element;\n    },\n\n    /**\n     * @private\n     * @param {Object} [options] Options object\n     */\n    _initOptions: function (options) {\n      var lowerCanvasEl = this.lowerCanvasEl;\n      this._setOptions(options);\n\n      this.width = this.width || parseInt(lowerCanvasEl.width, 10) || 0;\n      this.height = this.height || parseInt(lowerCanvasEl.height, 10) || 0;\n\n      if (!this.lowerCanvasEl.style) {\n        return;\n      }\n\n      lowerCanvasEl.width = this.width;\n      lowerCanvasEl.height = this.height;\n\n      lowerCanvasEl.style.width = this.width + 'px';\n      lowerCanvasEl.style.height = this.height + 'px';\n\n      this.viewportTransform = this.viewportTransform.slice();\n    },\n\n    /**\n     * Creates a bottom canvas\n     * @private\n     * @param {HTMLElement} [canvasEl]\n     */\n    _createLowerCanvas: function (canvasEl) {\n      // canvasEl === 'HTMLCanvasElement' does not work on jsdom/node\n      if (canvasEl && canvasEl.getContext) {\n        this.lowerCanvasEl = canvasEl;\n      }\n      else {\n        this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement();\n      }\n\n      fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas');\n      this._originalCanvasStyle = this.lowerCanvasEl.style;\n      if (this.interactive) {\n        this._applyCanvasStyle(this.lowerCanvasEl);\n      }\n\n      this.contextContainer = this.lowerCanvasEl.getContext('2d');\n    },\n\n    /**\n     * Returns canvas width (in px)\n     * @return {Number}\n     */\n    getWidth: function () {\n      return this.width;\n    },\n\n    /**\n     * Returns canvas height (in px)\n     * @return {Number}\n     */\n    getHeight: function () {\n      return this.height;\n    },\n\n    /**\n     * Sets width of this canvas instance\n     * @param {Number|String} value                         Value to set width to\n     * @param {Object}        [options]                     Options object\n     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setWidth: function (value, options) {\n      return this.setDimensions({ width: value }, options);\n    },\n\n    /**\n     * Sets height of this canvas instance\n     * @param {Number|String} value                         Value to set height to\n     * @param {Object}        [options]                     Options object\n     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setHeight: function (value, options) {\n      return this.setDimensions({ height: value }, options);\n    },\n\n    /**\n     * Sets dimensions (width, height) of this canvas instance. when options.cssOnly flag active you should also supply the unit of measure (px/%/em)\n     * @param {Object}        dimensions                    Object with width/height properties\n     * @param {Number|String} [dimensions.width]            Width of canvas element\n     * @param {Number|String} [dimensions.height]           Height of canvas element\n     * @param {Object}        [options]                     Options object\n     * @param {Boolean}       [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n     * @param {Boolean}       [options.cssOnly=false]       Set the given dimensions only as css dimensions\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    setDimensions: function (dimensions, options) {\n      var cssValue;\n\n      options = options || {};\n\n      for (var prop in dimensions) {\n        cssValue = dimensions[prop];\n\n        if (!options.cssOnly) {\n          this._setBackstoreDimension(prop, dimensions[prop]);\n          cssValue += 'px';\n          this.hasLostContext = true;\n        }\n\n        if (!options.backstoreOnly) {\n          this._setCssDimension(prop, cssValue);\n        }\n      }\n      if (this._isCurrentlyDrawing) {\n        this.freeDrawingBrush && this.freeDrawingBrush._setBrushStyles(this.contextTop);\n      }\n      this._initRetinaScaling();\n      this.calcOffset();\n\n      if (!options.cssOnly) {\n        this.requestRenderAll();\n      }\n\n      return this;\n    },\n\n    /**\n     * Helper for setting width/height\n     * @private\n     * @param {String} prop property (width|height)\n     * @param {Number} value value to set property to\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    _setBackstoreDimension: function (prop, value) {\n      this.lowerCanvasEl[prop] = value;\n\n      if (this.upperCanvasEl) {\n        this.upperCanvasEl[prop] = value;\n      }\n\n      if (this.cacheCanvasEl) {\n        this.cacheCanvasEl[prop] = value;\n      }\n\n      this[prop] = value;\n\n      return this;\n    },\n\n    /**\n     * Helper for setting css width/height\n     * @private\n     * @param {String} prop property (width|height)\n     * @param {String} value value to set property to\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    _setCssDimension: function (prop, value) {\n      this.lowerCanvasEl.style[prop] = value;\n\n      if (this.upperCanvasEl) {\n        this.upperCanvasEl.style[prop] = value;\n      }\n\n      if (this.wrapperEl) {\n        this.wrapperEl.style[prop] = value;\n      }\n\n      return this;\n    },\n\n    /**\n     * Returns canvas zoom level\n     * @return {Number}\n     */\n    getZoom: function () {\n      return this.viewportTransform[0];\n    },\n\n    /**\n     * Sets viewport transformation of this canvas instance\n     * @param {Array} vpt a Canvas 2D API transform matrix\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setViewportTransform: function (vpt) {\n      var activeObject = this._activeObject,\n          backgroundObject = this.backgroundImage,\n          overlayObject = this.overlayImage,\n          object, i, len;\n      this.viewportTransform = vpt;\n      for (i = 0, len = this._objects.length; i < len; i++) {\n        object = this._objects[i];\n        object.group || object.setCoords(true);\n      }\n      if (activeObject) {\n        activeObject.setCoords();\n      }\n      if (backgroundObject) {\n        backgroundObject.setCoords(true);\n      }\n      if (overlayObject) {\n        overlayObject.setCoords(true);\n      }\n      this.calcViewportBoundaries();\n      this.renderOnAddRemove && this.requestRenderAll();\n      return this;\n    },\n\n    /**\n     * Sets zoom level of this canvas instance, the zoom centered around point\n     * meaning that following zoom to point with the same point will have the visual\n     * effect of the zoom originating from that point. The point won't move.\n     * It has nothing to do with canvas center or visual center of the viewport.\n     * @param {fabric.Point} point to zoom with respect to\n     * @param {Number} value to set zoom to, less than 1 zooms out\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    zoomToPoint: function (point, value) {\n      // TODO: just change the scale, preserve other transformations\n      var before = point, vpt = this.viewportTransform.slice(0);\n      point = transformPoint(point, invertTransform(this.viewportTransform));\n      vpt[0] = value;\n      vpt[3] = value;\n      var after = transformPoint(point, vpt);\n      vpt[4] += before.x - after.x;\n      vpt[5] += before.y - after.y;\n      return this.setViewportTransform(vpt);\n    },\n\n    /**\n     * Sets zoom level of this canvas instance\n     * @param {Number} value to set zoom to, less than 1 zooms out\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    setZoom: function (value) {\n      this.zoomToPoint(new fabric.Point(0, 0), value);\n      return this;\n    },\n\n    /**\n     * Pan viewport so as to place point at top left corner of canvas\n     * @param {fabric.Point} point to move to\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    absolutePan: function (point) {\n      var vpt = this.viewportTransform.slice(0);\n      vpt[4] = -point.x;\n      vpt[5] = -point.y;\n      return this.setViewportTransform(vpt);\n    },\n\n    /**\n     * Pans viewpoint relatively\n     * @param {fabric.Point} point (position vector) to move by\n     * @return {fabric.Canvas} instance\n     * @chainable true\n     */\n    relativePan: function (point) {\n      return this.absolutePan(new fabric.Point(\n        -point.x - this.viewportTransform[4],\n        -point.y - this.viewportTransform[5]\n      ));\n    },\n\n    /**\n     * Returns &lt;canvas> element corresponding to this instance\n     * @return {HTMLCanvasElement}\n     */\n    getElement: function () {\n      return this.lowerCanvasEl;\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} obj Object that was added\n     */\n    _onObjectAdded: function(obj) {\n      this.stateful && obj.setupState();\n      obj._set('canvas', this);\n      obj.setCoords();\n      this.fire('object:added', { target: obj });\n      obj.fire('added');\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} obj Object that was removed\n     */\n    _onObjectRemoved: function(obj) {\n      this.fire('object:removed', { target: obj });\n      obj.fire('removed');\n      delete obj.canvas;\n    },\n\n    /**\n     * Clears specified context of canvas element\n     * @param {CanvasRenderingContext2D} ctx Context to clear\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    clearContext: function(ctx) {\n      ctx.clearRect(0, 0, this.width, this.height);\n      return this;\n    },\n\n    /**\n     * Returns context of canvas where objects are drawn\n     * @return {CanvasRenderingContext2D}\n     */\n    getContext: function () {\n      return this.contextContainer;\n    },\n\n    /**\n     * Clears all contexts (background, main, top) of an instance\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    clear: function () {\n      this.remove.apply(this, this.getObjects());\n      this.backgroundImage = null;\n      this.overlayImage = null;\n      this.backgroundColor = '';\n      this.overlayColor = '';\n      if (this._hasITextHandlers) {\n        this.off('mouse:up', this._mouseUpITextHandler);\n        this._iTextInstances = null;\n        this._hasITextHandlers = false;\n      }\n      this.clearContext(this.contextContainer);\n      this.fire('canvas:cleared');\n      this.renderOnAddRemove && this.requestRenderAll();\n      return this;\n    },\n\n    /**\n     * Renders the canvas\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    renderAll: function () {\n      var canvasToDrawOn = this.contextContainer;\n      this.renderCanvas(canvasToDrawOn, this._objects);\n      return this;\n    },\n\n    /**\n     * Function created to be instance bound at initialization\n     * used in requestAnimationFrame rendering\n     * Let the fabricJS call it. If you call it manually you could have more\n     * animationFrame stacking on to of each other\n     * for an imperative rendering, use canvas.renderAll\n     * @private\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    renderAndReset: function() {\n      this.isRendering = 0;\n      this.renderAll();\n    },\n\n    /**\n     * Append a renderAll request to next animation frame.\n     * unless one is already in progress, in that case nothing is done\n     * a boolean flag will avoid appending more.\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    requestRenderAll: function () {\n      if (!this.isRendering) {\n        this.isRendering = fabric.util.requestAnimFrame(this.renderAndResetBound);\n      }\n      return this;\n    },\n\n    /**\n     * Calculate the position of the 4 corner of canvas with current viewportTransform.\n     * helps to determinate when an object is in the current rendering viewport using\n     * object absolute coordinates ( aCoords )\n     * @return {Object} points.tl\n     * @chainable\n     */\n    calcViewportBoundaries: function() {\n      var points = { }, width = this.width, height = this.height,\n          iVpt = invertTransform(this.viewportTransform);\n      points.tl = transformPoint({ x: 0, y: 0 }, iVpt);\n      points.br = transformPoint({ x: width, y: height }, iVpt);\n      points.tr = new fabric.Point(points.br.x, points.tl.y);\n      points.bl = new fabric.Point(points.tl.x, points.br.y);\n      this.vptCoords = points;\n      return points;\n    },\n\n    cancelRequestedRender: function() {\n      if (this.isRendering) {\n        fabric.util.cancelAnimFrame(this.isRendering);\n        this.isRendering = 0;\n      }\n    },\n\n    /**\n     * Renders background, objects, overlay and controls.\n     * @param {CanvasRenderingContext2D} ctx\n     * @param {Array} objects to render\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    renderCanvas: function(ctx, objects) {\n      var v = this.viewportTransform, path = this.clipPath;\n      this.cancelRequestedRender();\n      this.calcViewportBoundaries();\n      this.clearContext(ctx);\n      fabric.util.setImageSmoothing(ctx, this.imageSmoothingEnabled);\n      this.fire('before:render', { ctx: ctx, });\n      this._renderBackground(ctx);\n\n      ctx.save();\n      //apply viewport transform once for all rendering process\n      ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n      this._renderObjects(ctx, objects);\n      ctx.restore();\n      if (!this.controlsAboveOverlay && this.interactive) {\n        this.drawControls(ctx);\n      }\n      if (path) {\n        path.canvas = this;\n        // needed to setup a couple of variables\n        path.shouldCache();\n        path._transformDone = true;\n        path.renderCache({ forClipping: true });\n        this.drawClipPathOnCanvas(ctx);\n      }\n      this._renderOverlay(ctx);\n      if (this.controlsAboveOverlay && this.interactive) {\n        this.drawControls(ctx);\n      }\n      this.fire('after:render', { ctx: ctx, });\n    },\n\n    /**\n     * Paint the cached clipPath on the lowerCanvasEl\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    drawClipPathOnCanvas: function(ctx) {\n      var v = this.viewportTransform, path = this.clipPath;\n      ctx.save();\n      ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n      // DEBUG: uncomment this line, comment the following\n      // ctx.globalAlpha = 0.4;\n      ctx.globalCompositeOperation = 'destination-in';\n      path.transform(ctx);\n      ctx.scale(1 / path.zoomX, 1 / path.zoomY);\n      ctx.drawImage(path._cacheCanvas, -path.cacheTranslationX, -path.cacheTranslationY);\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Array} objects to render\n     */\n    _renderObjects: function(ctx, objects) {\n      var i, len;\n      for (i = 0, len = objects.length; i < len; ++i) {\n        objects[i] && objects[i].render(ctx);\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {string} property 'background' or 'overlay'\n     */\n    _renderBackgroundOrOverlay: function(ctx, property) {\n      var fill = this[property + 'Color'], object = this[property + 'Image'],\n          v = this.viewportTransform, needsVpt = this[property + 'Vpt'];\n      if (!fill && !object) {\n        return;\n      }\n      if (fill) {\n        ctx.save();\n        ctx.beginPath();\n        ctx.moveTo(0, 0);\n        ctx.lineTo(this.width, 0);\n        ctx.lineTo(this.width, this.height);\n        ctx.lineTo(0, this.height);\n        ctx.closePath();\n        ctx.fillStyle = fill.toLive\n          ? fill.toLive(ctx, this)\n          : fill;\n        if (needsVpt) {\n          ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n        }\n        ctx.transform(1, 0, 0, 1, fill.offsetX || 0, fill.offsetY || 0);\n        var m = fill.gradientTransform || fill.patternTransform;\n        m && ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n        ctx.fill();\n        ctx.restore();\n      }\n      if (object) {\n        ctx.save();\n        var skipOffscreen = this.skipOffscreen;\n        // if the object doesn't move with the viewport,\n        // the offscreen concept does not apply;\n        this.skipOffscreen = needsVpt;\n        if (needsVpt) {\n          ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n        }\n        object.render(ctx);\n        this.skipOffscreen = skipOffscreen;\n        ctx.restore();\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderBackground: function(ctx) {\n      this._renderBackgroundOrOverlay(ctx, 'background');\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderOverlay: function(ctx) {\n      this._renderBackgroundOrOverlay(ctx, 'overlay');\n    },\n\n    /**\n     * Returns coordinates of a center of canvas.\n     * Returned value is an object with top and left properties\n     * @return {Object} object with \"top\" and \"left\" number values\n     * @deprecated migrate to `getCenterPoint`\n     */\n    getCenter: function () {\n      return {\n        top: this.height / 2,\n        left: this.width / 2\n      };\n    },\n\n    /**\n     * Returns coordinates of a center of canvas.\n     * @return {fabric.Point} \n     */\n    getCenterPoint: function () {\n      return new fabric.Point(this.width / 2, this.height / 2);\n    },\n\n    /**\n     * Centers object horizontally in the canvas\n     * @param {fabric.Object} object Object to center horizontally\n     * @return {fabric.Canvas} thisArg\n     */\n    centerObjectH: function (object) {\n      return this._centerObject(object, new fabric.Point(this.getCenterPoint().x, object.getCenterPoint().y));\n    },\n\n    /**\n     * Centers object vertically in the canvas\n     * @param {fabric.Object} object Object to center vertically\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    centerObjectV: function (object) {\n      return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, this.getCenterPoint().y));\n    },\n\n    /**\n     * Centers object vertically and horizontally in the canvas\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    centerObject: function(object) {\n      var center = this.getCenterPoint();\n      return this._centerObject(object, center);\n    },\n\n    /**\n     * Centers object vertically and horizontally in the viewport\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    viewportCenterObject: function(object) {\n      var vpCenter = this.getVpCenter();\n      return this._centerObject(object, vpCenter);\n    },\n\n    /**\n     * Centers object horizontally in the viewport, object.top is unchanged\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    viewportCenterObjectH: function(object) {\n      var vpCenter = this.getVpCenter();\n      this._centerObject(object, new fabric.Point(vpCenter.x, object.getCenterPoint().y));\n      return this;\n    },\n\n    /**\n     * Centers object Vertically in the viewport, object.top is unchanged\n     * @param {fabric.Object} object Object to center vertically and horizontally\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    viewportCenterObjectV: function(object) {\n      var vpCenter = this.getVpCenter();\n\n      return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, vpCenter.y));\n    },\n\n    /**\n     * Calculate the point in canvas that correspond to the center of actual viewport.\n     * @return {fabric.Point} vpCenter, viewport center\n     * @chainable\n     */\n    getVpCenter: function() {\n      var center = this.getCenterPoint(),\n          iVpt = invertTransform(this.viewportTransform);\n      return transformPoint(center, iVpt);\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} object Object to center\n     * @param {fabric.Point} center Center point\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    _centerObject: function(object, center) {\n      object.setPositionByOrigin(center, 'center', 'center');\n      object.setCoords();\n      this.renderOnAddRemove && this.requestRenderAll();\n      return this;\n    },\n\n    /**\n     * Returns dataless JSON representation of canvas\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {String} json string\n     */\n    toDatalessJSON: function (propertiesToInclude) {\n      return this.toDatalessObject(propertiesToInclude);\n    },\n\n    /**\n     * Returns object representation of canvas\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function (propertiesToInclude) {\n      return this._toObjectMethod('toObject', propertiesToInclude);\n    },\n\n    /**\n     * Returns dataless object representation of canvas\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toDatalessObject: function (propertiesToInclude) {\n      return this._toObjectMethod('toDatalessObject', propertiesToInclude);\n    },\n\n    /**\n     * @private\n     */\n    _toObjectMethod: function (methodName, propertiesToInclude) {\n\n      var clipPath = this.clipPath, data = {\n        version: fabric.version,\n        objects: this._toObjects(methodName, propertiesToInclude),\n      };\n      if (clipPath && !clipPath.excludeFromExport) {\n        data.clipPath = this._toObject(this.clipPath, methodName, propertiesToInclude);\n      }\n      extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));\n\n      fabric.util.populateWithProperties(this, data, propertiesToInclude);\n\n      return data;\n    },\n\n    /**\n     * @private\n     */\n    _toObjects: function(methodName, propertiesToInclude) {\n      return this._objects.filter(function(object) {\n        return !object.excludeFromExport;\n      }).map(function(instance) {\n        return this._toObject(instance, methodName, propertiesToInclude);\n      }, this);\n    },\n\n    /**\n     * @private\n     */\n    _toObject: function(instance, methodName, propertiesToInclude) {\n      var originalValue;\n\n      if (!this.includeDefaultValues) {\n        originalValue = instance.includeDefaultValues;\n        instance.includeDefaultValues = false;\n      }\n\n      var object = instance[methodName](propertiesToInclude);\n      if (!this.includeDefaultValues) {\n        instance.includeDefaultValues = originalValue;\n      }\n      return object;\n    },\n\n    /**\n     * @private\n     */\n    __serializeBgOverlay: function(methodName, propertiesToInclude) {\n      var data = {}, bgImage = this.backgroundImage, overlayImage = this.overlayImage,\n          bgColor = this.backgroundColor, overlayColor = this.overlayColor;\n\n      if (bgColor && bgColor.toObject) {\n        if (!bgColor.excludeFromExport) {\n          data.background = bgColor.toObject(propertiesToInclude);\n        }\n      }\n      else if (bgColor) {\n        data.background = bgColor;\n      }\n\n      if (overlayColor && overlayColor.toObject) {\n        if (!overlayColor.excludeFromExport) {\n          data.overlay = overlayColor.toObject(propertiesToInclude);\n        }\n      }\n      else if (overlayColor) {\n        data.overlay = overlayColor;\n      }\n\n      if (bgImage && !bgImage.excludeFromExport) {\n        data.backgroundImage = this._toObject(bgImage, methodName, propertiesToInclude);\n      }\n      if (overlayImage && !overlayImage.excludeFromExport) {\n        data.overlayImage = this._toObject(overlayImage, methodName, propertiesToInclude);\n      }\n\n      return data;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * When true, getSvgTransform() will apply the StaticCanvas.viewportTransform to the SVG transformation. When true,\n     * a zoomed canvas will then produce zoomed SVG output.\n     * @type Boolean\n     * @default\n     */\n    svgViewportTransformation: true,\n\n    /**\n     * Returns SVG representation of canvas\n     * @function\n     * @param {Object} [options] Options object for SVG output\n     * @param {Boolean} [options.suppressPreamble=false] If true xml tag is not included\n     * @param {Object} [options.viewBox] SVG viewbox object\n     * @param {Number} [options.viewBox.x] x-coordinate of viewbox\n     * @param {Number} [options.viewBox.y] y-coordinate of viewbox\n     * @param {Number} [options.viewBox.width] Width of viewbox\n     * @param {Number} [options.viewBox.height] Height of viewbox\n     * @param {String} [options.encoding=UTF-8] Encoding of SVG output\n     * @param {String} [options.width] desired width of svg with or without units\n     * @param {String} [options.height] desired height of svg with or without units\n     * @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.\n     * @return {String} SVG string\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}\n     * @see {@link http://jsfiddle.net/fabricjs/jQ3ZZ/|jsFiddle demo}\n     * @example <caption>Normal SVG output</caption>\n     * var svg = canvas.toSVG();\n     * @example <caption>SVG output without preamble (without &lt;?xml ../>)</caption>\n     * var svg = canvas.toSVG({suppressPreamble: true});\n     * @example <caption>SVG output with viewBox attribute</caption>\n     * var svg = canvas.toSVG({\n     *   viewBox: {\n     *     x: 100,\n     *     y: 100,\n     *     width: 200,\n     *     height: 300\n     *   }\n     * });\n     * @example <caption>SVG output with different encoding (default: UTF-8)</caption>\n     * var svg = canvas.toSVG({encoding: 'ISO-8859-1'});\n     * @example <caption>Modify SVG output with reviver function</caption>\n     * var svg = canvas.toSVG(null, function(svg) {\n     *   return svg.replace('stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; ', '');\n     * });\n     */\n    toSVG: function(options, reviver) {\n      options || (options = { });\n      options.reviver = reviver;\n      var markup = [];\n\n      this._setSVGPreamble(markup, options);\n      this._setSVGHeader(markup, options);\n      if (this.clipPath) {\n        markup.push('<g clip-path=\"url(#' + this.clipPath.clipPathId + ')\" >\\n');\n      }\n      this._setSVGBgOverlayColor(markup, 'background');\n      this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);\n      this._setSVGObjects(markup, reviver);\n      if (this.clipPath) {\n        markup.push('</g>\\n');\n      }\n      this._setSVGBgOverlayColor(markup, 'overlay');\n      this._setSVGBgOverlayImage(markup, 'overlayImage', reviver);\n\n      markup.push('</svg>');\n\n      return markup.join('');\n    },\n\n    /**\n     * @private\n     */\n    _setSVGPreamble: function(markup, options) {\n      if (options.suppressPreamble) {\n        return;\n      }\n      markup.push(\n        '<?xml version=\"1.0\" encoding=\"', (options.encoding || 'UTF-8'), '\" standalone=\"no\" ?>\\n',\n        '<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ',\n        '\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\\n'\n      );\n    },\n\n    /**\n     * @private\n     */\n    _setSVGHeader: function(markup, options) {\n      var width = options.width || this.width,\n          height = options.height || this.height,\n          vpt, viewBox = 'viewBox=\"0 0 ' + this.width + ' ' + this.height + '\" ',\n          NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n\n      if (options.viewBox) {\n        viewBox = 'viewBox=\"' +\n                options.viewBox.x + ' ' +\n                options.viewBox.y + ' ' +\n                options.viewBox.width + ' ' +\n                options.viewBox.height + '\" ';\n      }\n      else {\n        if (this.svgViewportTransformation) {\n          vpt = this.viewportTransform;\n          viewBox = 'viewBox=\"' +\n                  toFixed(-vpt[4] / vpt[0], NUM_FRACTION_DIGITS) + ' ' +\n                  toFixed(-vpt[5] / vpt[3], NUM_FRACTION_DIGITS) + ' ' +\n                  toFixed(this.width / vpt[0], NUM_FRACTION_DIGITS) + ' ' +\n                  toFixed(this.height / vpt[3], NUM_FRACTION_DIGITS) + '\" ';\n        }\n      }\n\n      markup.push(\n        '<svg ',\n        'xmlns=\"http://www.w3.org/2000/svg\" ',\n        'xmlns:xlink=\"http://www.w3.org/1999/xlink\" ',\n        'version=\"1.1\" ',\n        'width=\"', width, '\" ',\n        'height=\"', height, '\" ',\n        viewBox,\n        'xml:space=\"preserve\">\\n',\n        '<desc>Created with Fabric.js ', fabric.version, '</desc>\\n',\n        '<defs>\\n',\n        this.createSVGFontFacesMarkup(),\n        this.createSVGRefElementsMarkup(),\n        this.createSVGClipPathMarkup(options),\n        '</defs>\\n'\n      );\n    },\n\n    createSVGClipPathMarkup: function(options) {\n      var clipPath = this.clipPath;\n      if (clipPath) {\n        clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;\n        return  '<clipPath id=\"' + clipPath.clipPathId + '\" >\\n' +\n          this.clipPath.toClipPathSVG(options.reviver) +\n          '</clipPath>\\n';\n      }\n      return '';\n    },\n\n    /**\n     * Creates markup containing SVG referenced elements like patterns, gradients etc.\n     * @return {String}\n     */\n    createSVGRefElementsMarkup: function() {\n      var _this = this,\n          markup = ['background', 'overlay'].map(function(prop) {\n            var fill = _this[prop + 'Color'];\n            if (fill && fill.toLive) {\n              var shouldTransform = _this[prop + 'Vpt'], vpt = _this.viewportTransform,\n                  object = {\n                    width: _this.width / (shouldTransform ? vpt[0] : 1),\n                    height: _this.height / (shouldTransform ? vpt[3] : 1)\n                  };\n              return fill.toSVG(\n                object,\n                { additionalTransform: shouldTransform ? fabric.util.matrixToSVG(vpt) : '' }\n              );\n            }\n          });\n      return markup.join('');\n    },\n\n    /**\n     * Creates markup containing SVG font faces,\n     * font URLs for font faces must be collected by developers\n     * and are not extracted from the DOM by fabricjs\n     * @param {Array} objects Array of fabric objects\n     * @return {String}\n     */\n    createSVGFontFacesMarkup: function() {\n      var markup = '', fontList = { }, obj, fontFamily,\n          style, row, rowIndex, _char, charIndex, i, len,\n          fontPaths = fabric.fontPaths, objects = [];\n\n      this._objects.forEach(function add(object) {\n        objects.push(object);\n        if (object._objects) {\n          object._objects.forEach(add);\n        }\n      });\n\n      for (i = 0, len = objects.length; i < len; i++) {\n        obj = objects[i];\n        fontFamily = obj.fontFamily;\n        if (obj.type.indexOf('text') === -1 || fontList[fontFamily] || !fontPaths[fontFamily]) {\n          continue;\n        }\n        fontList[fontFamily] = true;\n        if (!obj.styles) {\n          continue;\n        }\n        style = obj.styles;\n        for (rowIndex in style) {\n          row = style[rowIndex];\n          for (charIndex in row) {\n            _char = row[charIndex];\n            fontFamily = _char.fontFamily;\n            if (!fontList[fontFamily] && fontPaths[fontFamily]) {\n              fontList[fontFamily] = true;\n            }\n          }\n        }\n      }\n\n      for (var j in fontList) {\n        markup += [\n          '\\t\\t@font-face {\\n',\n          '\\t\\t\\tfont-family: \\'', j, '\\';\\n',\n          '\\t\\t\\tsrc: url(\\'', fontPaths[j], '\\');\\n',\n          '\\t\\t}\\n'\n        ].join('');\n      }\n\n      if (markup) {\n        markup = [\n          '\\t<style type=\"text/css\">',\n          '<![CDATA[\\n',\n          markup,\n          ']]>',\n          '</style>\\n'\n        ].join('');\n      }\n\n      return markup;\n    },\n\n    /**\n     * @private\n     */\n    _setSVGObjects: function(markup, reviver) {\n      var instance, i, len, objects = this._objects;\n      for (i = 0, len = objects.length; i < len; i++) {\n        instance = objects[i];\n        if (instance.excludeFromExport) {\n          continue;\n        }\n        this._setSVGObject(markup, instance, reviver);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setSVGObject: function(markup, instance, reviver) {\n      markup.push(instance.toSVG(reviver));\n    },\n\n    /**\n     * @private\n     */\n    _setSVGBgOverlayImage: function(markup, property, reviver) {\n      if (this[property] && !this[property].excludeFromExport && this[property].toSVG) {\n        markup.push(this[property].toSVG(reviver));\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setSVGBgOverlayColor: function(markup, property) {\n      var filler = this[property + 'Color'], vpt = this.viewportTransform, finalWidth = this.width,\n          finalHeight = this.height;\n      if (!filler) {\n        return;\n      }\n      if (filler.toLive) {\n        var repeat = filler.repeat, iVpt = fabric.util.invertTransform(vpt), shouldInvert = this[property + 'Vpt'],\n            additionalTransform = shouldInvert ? fabric.util.matrixToSVG(iVpt) : '';\n        markup.push(\n          '<rect transform=\"' + additionalTransform + ' translate(', finalWidth / 2, ',', finalHeight / 2, ')\"',\n          ' x=\"', filler.offsetX - finalWidth / 2,\n          '\" y=\"', filler.offsetY - finalHeight / 2, '\" ',\n          'width=\"',\n          (repeat === 'repeat-y' || repeat === 'no-repeat'\n            ? filler.source.width\n            : finalWidth ),\n          '\" height=\"',\n          (repeat === 'repeat-x' || repeat === 'no-repeat'\n            ? filler.source.height\n            : finalHeight),\n          '\" fill=\"url(#SVGID_' + filler.id + ')\"',\n          '></rect>\\n'\n        );\n      }\n      else {\n        markup.push(\n          '<rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" ',\n          'fill=\"', filler, '\"',\n          '></rect>\\n'\n        );\n      }\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Moves an object or the objects of a multiple selection\n     * to the bottom of the stack of drawn objects\n     * @param {fabric.Object} object Object to send to back\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    sendToBack: function (object) {\n      if (!object) {\n        return this;\n      }\n      var activeSelection = this._activeObject,\n          i, obj, objs;\n      if (object === activeSelection && object.type === 'activeSelection') {\n        objs = activeSelection._objects;\n        for (i = objs.length; i--;) {\n          obj = objs[i];\n          removeFromArray(this._objects, obj);\n          this._objects.unshift(obj);\n        }\n      }\n      else {\n        removeFromArray(this._objects, object);\n        this._objects.unshift(object);\n      }\n      this.renderOnAddRemove && this.requestRenderAll();\n      return this;\n    },\n\n    /**\n     * Moves an object or the objects of a multiple selection\n     * to the top of the stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    bringToFront: function (object) {\n      if (!object) {\n        return this;\n      }\n      var activeSelection = this._activeObject,\n          i, obj, objs;\n      if (object === activeSelection && object.type === 'activeSelection') {\n        objs = activeSelection._objects;\n        for (i = 0; i < objs.length; i++) {\n          obj = objs[i];\n          removeFromArray(this._objects, obj);\n          this._objects.push(obj);\n        }\n      }\n      else {\n        removeFromArray(this._objects, object);\n        this._objects.push(object);\n      }\n      this.renderOnAddRemove && this.requestRenderAll();\n      return this;\n    },\n\n    /**\n     * Moves an object or a selection down in stack of drawn objects\n     * An optional parameter, intersecting allows to move the object in behind\n     * the first intersecting object. Where intersection is calculated with\n     * bounding box. If no intersection is found, there will not be change in the\n     * stack.\n     * @param {fabric.Object} object Object to send\n     * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    sendBackwards: function (object, intersecting) {\n      if (!object) {\n        return this;\n      }\n      var activeSelection = this._activeObject,\n          i, obj, idx, newIdx, objs, objsMoved = 0;\n\n      if (object === activeSelection && object.type === 'activeSelection') {\n        objs = activeSelection._objects;\n        for (i = 0; i < objs.length; i++) {\n          obj = objs[i];\n          idx = this._objects.indexOf(obj);\n          if (idx > 0 + objsMoved) {\n            newIdx = idx - 1;\n            removeFromArray(this._objects, obj);\n            this._objects.splice(newIdx, 0, obj);\n          }\n          objsMoved++;\n        }\n      }\n      else {\n        idx = this._objects.indexOf(object);\n        if (idx !== 0) {\n          // if object is not on the bottom of stack\n          newIdx = this._findNewLowerIndex(object, idx, intersecting);\n          removeFromArray(this._objects, object);\n          this._objects.splice(newIdx, 0, object);\n        }\n      }\n      this.renderOnAddRemove && this.requestRenderAll();\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _findNewLowerIndex: function(object, idx, intersecting) {\n      var newIdx, i;\n\n      if (intersecting) {\n        newIdx = idx;\n\n        // traverse down the stack looking for the nearest intersecting object\n        for (i = idx - 1; i >= 0; --i) {\n\n          var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n                               object.isContainedWithinObject(this._objects[i]) ||\n                               this._objects[i].isContainedWithinObject(object);\n\n          if (isIntersecting) {\n            newIdx = i;\n            break;\n          }\n        }\n      }\n      else {\n        newIdx = idx - 1;\n      }\n\n      return newIdx;\n    },\n\n    /**\n     * Moves an object or a selection up in stack of drawn objects\n     * An optional parameter, intersecting allows to move the object in front\n     * of the first intersecting object. Where intersection is calculated with\n     * bounding box. If no intersection is found, there will not be change in the\n     * stack.\n     * @param {fabric.Object} object Object to send\n     * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    bringForward: function (object, intersecting) {\n      if (!object) {\n        return this;\n      }\n      var activeSelection = this._activeObject,\n          i, obj, idx, newIdx, objs, objsMoved = 0;\n\n      if (object === activeSelection && object.type === 'activeSelection') {\n        objs = activeSelection._objects;\n        for (i = objs.length; i--;) {\n          obj = objs[i];\n          idx = this._objects.indexOf(obj);\n          if (idx < this._objects.length - 1 - objsMoved) {\n            newIdx = idx + 1;\n            removeFromArray(this._objects, obj);\n            this._objects.splice(newIdx, 0, obj);\n          }\n          objsMoved++;\n        }\n      }\n      else {\n        idx = this._objects.indexOf(object);\n        if (idx !== this._objects.length - 1) {\n          // if object is not on top of stack (last item in an array)\n          newIdx = this._findNewUpperIndex(object, idx, intersecting);\n          removeFromArray(this._objects, object);\n          this._objects.splice(newIdx, 0, object);\n        }\n      }\n      this.renderOnAddRemove && this.requestRenderAll();\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _findNewUpperIndex: function(object, idx, intersecting) {\n      var newIdx, i, len;\n\n      if (intersecting) {\n        newIdx = idx;\n\n        // traverse up the stack looking for the nearest intersecting object\n        for (i = idx + 1, len = this._objects.length; i < len; ++i) {\n\n          var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n                               object.isContainedWithinObject(this._objects[i]) ||\n                               this._objects[i].isContainedWithinObject(object);\n\n          if (isIntersecting) {\n            newIdx = i;\n            break;\n          }\n        }\n      }\n      else {\n        newIdx = idx + 1;\n      }\n\n      return newIdx;\n    },\n\n    /**\n     * Moves an object to specified level in stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @param {Number} index Position to move to\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    moveTo: function (object, index) {\n      removeFromArray(this._objects, object);\n      this._objects.splice(index, 0, object);\n      return this.renderOnAddRemove && this.requestRenderAll();\n    },\n\n    /**\n     * Clears a canvas element and dispose objects\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    dispose: function () {\n      // cancel eventually ongoing renders\n      if (this.isRendering) {\n        fabric.util.cancelAnimFrame(this.isRendering);\n        this.isRendering = 0;\n      }\n      this.forEachObject(function(object) {\n        object.dispose && object.dispose();\n      });\n      this._objects = [];\n      if (this.backgroundImage && this.backgroundImage.dispose) {\n        this.backgroundImage.dispose();\n      }\n      this.backgroundImage = null;\n      if (this.overlayImage && this.overlayImage.dispose) {\n        this.overlayImage.dispose();\n      }\n      this.overlayImage = null;\n      this._iTextInstances = null;\n      this.contextContainer = null;\n      // restore canvas style\n      this.lowerCanvasEl.classList.remove('lower-canvas');\n      fabric.util.setStyle(this.lowerCanvasEl, this._originalCanvasStyle);\n      delete this._originalCanvasStyle;\n      // restore canvas size to original size in case retina scaling was applied\n      this.lowerCanvasEl.setAttribute('width', this.width);\n      this.lowerCanvasEl.setAttribute('height', this.height);\n      fabric.util.cleanUpJsdomNode(this.lowerCanvasEl);\n      this.lowerCanvasEl = undefined;\n      return this;\n    },\n\n    /**\n     * Returns a string representation of an instance\n     * @return {String} string representation of an instance\n     */\n    toString: function () {\n      return '#<fabric.Canvas (' + this.complexity() + '): ' +\n               '{ objects: ' + this._objects.length + ' }>';\n    }\n  });\n\n  extend(fabric.StaticCanvas.prototype, fabric.Observable);\n  extend(fabric.StaticCanvas.prototype, fabric.Collection);\n  extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);\n\n  extend(fabric.StaticCanvas, /** @lends fabric.StaticCanvas */ {\n\n    /**\n     * @static\n     * @type String\n     * @default\n     */\n    EMPTY_JSON: '{\"objects\": [], \"background\": \"white\"}',\n\n    /**\n     * Provides a way to check support of some of the canvas methods\n     * (either those of HTMLCanvasElement itself, or rendering context)\n     *\n     * @param {String} methodName Method to check support for;\n     *                            Could be one of \"setLineDash\"\n     * @return {Boolean | null} `true` if method is supported (or at least exists),\n     *                          `null` if canvas element or context can not be initialized\n     */\n    supports: function (methodName) {\n      var el = createCanvasElement();\n\n      if (!el || !el.getContext) {\n        return null;\n      }\n\n      var ctx = el.getContext('2d');\n      if (!ctx) {\n        return null;\n      }\n\n      switch (methodName) {\n\n        case 'setLineDash':\n          return typeof ctx.setLineDash !== 'undefined';\n\n        default:\n          return null;\n      }\n    }\n  });\n\n  /**\n   * Returns Object representation of canvas\n   * this alias is provided because if you call JSON.stringify on an instance,\n   * the toJSON object will be invoked if it exists.\n   * Having a toJSON method means you can do JSON.stringify(myCanvas)\n   * @function\n   * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n   * @return {Object} JSON compatible object\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}\n   * @see {@link http://jsfiddle.net/fabricjs/pec86/|jsFiddle demo}\n   * @example <caption>JSON without additional properties</caption>\n   * var json = canvas.toJSON();\n   * @example <caption>JSON with additional properties included</caption>\n   * var json = canvas.toJSON(['lockMovementX', 'lockMovementY', 'lockRotation', 'lockScalingX', 'lockScalingY']);\n   * @example <caption>JSON without default values</caption>\n   * canvas.includeDefaultValues = false;\n   * var json = canvas.toJSON();\n   */\n  fabric.StaticCanvas.prototype.toJSON = fabric.StaticCanvas.prototype.toObject;\n\n  if (fabric.isLikelyNode) {\n    fabric.StaticCanvas.prototype.createPNGStream = function() {\n      var impl = getNodeCanvas(this.lowerCanvasEl);\n      return impl && impl.createPNGStream();\n    };\n    fabric.StaticCanvas.prototype.createJPEGStream = function(opts) {\n      var impl = getNodeCanvas(this.lowerCanvasEl);\n      return impl && impl.createJPEGStream(opts);\n    };\n  }\n})();\n\n\n/**\n * BaseBrush class\n * @class fabric.BaseBrush\n * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo}\n */\nfabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ {\n\n  /**\n   * Color of a brush\n   * @type String\n   * @default\n   */\n  color: 'rgb(0, 0, 0)',\n\n  /**\n   * Width of a brush, has to be a Number, no string literals\n   * @type Number\n   * @default\n   */\n  width: 1,\n\n  /**\n   * Shadow object representing shadow of this shape.\n   * <b>Backwards incompatibility note:</b> This property replaces \"shadowColor\" (String), \"shadowOffsetX\" (Number),\n   * \"shadowOffsetY\" (Number) and \"shadowBlur\" (Number) since v1.2.12\n   * @type fabric.Shadow\n   * @default\n   */\n  shadow: null,\n\n  /**\n   * Line endings style of a brush (one of \"butt\", \"round\", \"square\")\n   * @type String\n   * @default\n   */\n  strokeLineCap: 'round',\n\n  /**\n   * Corner style of a brush (one of \"bevel\", \"round\", \"miter\")\n   * @type String\n   * @default\n   */\n  strokeLineJoin: 'round',\n\n  /**\n   * Maximum miter length (used for strokeLineJoin = \"miter\") of a brush's\n   * @type Number\n   * @default\n   */\n  strokeMiterLimit:         10,\n\n  /**\n   * Stroke Dash Array.\n   * @type Array\n   * @default\n   */\n  strokeDashArray: null,\n\n  /**\n   * When `true`, the free drawing is limited to the whiteboard size. Default to false.\n   * @type Boolean\n   * @default false\n  */\n\n  limitedToCanvasSize: false,\n\n\n  /**\n   * Sets brush styles\n   * @private\n   * @param {CanvasRenderingContext2D} ctx\n   */\n  _setBrushStyles: function (ctx) {\n    ctx.strokeStyle = this.color;\n    ctx.lineWidth = this.width;\n    ctx.lineCap = this.strokeLineCap;\n    ctx.miterLimit = this.strokeMiterLimit;\n    ctx.lineJoin = this.strokeLineJoin;\n    ctx.setLineDash(this.strokeDashArray || []);\n  },\n\n  /**\n   * Sets the transformation on given context\n   * @param {RenderingContext2d} ctx context to render on\n   * @private\n   */\n  _saveAndTransform: function(ctx) {\n    var v = this.canvas.viewportTransform;\n    ctx.save();\n    ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n  },\n\n  /**\n   * Sets brush shadow styles\n   * @private\n   */\n  _setShadow: function() {\n    if (!this.shadow) {\n      return;\n    }\n\n    var canvas = this.canvas,\n        shadow = this.shadow,\n        ctx = canvas.contextTop,\n        zoom = canvas.getZoom();\n    if (canvas && canvas._isRetinaScaling()) {\n      zoom *= fabric.devicePixelRatio;\n    }\n\n    ctx.shadowColor = shadow.color;\n    ctx.shadowBlur = shadow.blur * zoom;\n    ctx.shadowOffsetX = shadow.offsetX * zoom;\n    ctx.shadowOffsetY = shadow.offsetY * zoom;\n  },\n\n  needsFullRender: function() {\n    var color = new fabric.Color(this.color);\n    return color.getAlpha() < 1 || !!this.shadow;\n  },\n\n  /**\n   * Removes brush shadow styles\n   * @private\n   */\n  _resetShadow: function() {\n    var ctx = this.canvas.contextTop;\n\n    ctx.shadowColor = '';\n    ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n  },\n\n  /**\n   * Check is pointer is outside canvas boundaries\n   * @param {Object} pointer\n   * @private\n  */\n  _isOutSideCanvas: function(pointer) {\n    return pointer.x < 0 || pointer.x > this.canvas.getWidth() || pointer.y < 0 || pointer.y > this.canvas.getHeight();\n  }\n});\n\n\n(function() {\n  /**\n   * PencilBrush class\n   * @class fabric.PencilBrush\n   * @extends fabric.BaseBrush\n   */\n  fabric.PencilBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.PencilBrush.prototype */ {\n\n    /**\n     * Discard points that are less than `decimate` pixel distant from each other\n     * @type Number\n     * @default 0.4\n     */\n    decimate: 0.4,\n\n    /**\n     * Draws a straight line between last recorded point to current pointer\n     * Used for `shift` functionality\n     *\n     * @type boolean\n     * @default false\n     */\n    drawStraightLine: false,\n\n    /**\n     * The event modifier key that makes the brush draw a straight line.\n     * If `null` or 'none' or any other string that is not a modifier key the feature is disabled.\n     * @type {'altKey' | 'shiftKey' | 'ctrlKey' | 'none' | undefined | null}\n     */\n    straightLineKey: 'shiftKey',\n\n    /**\n     * Constructor\n     * @param {fabric.Canvas} canvas\n     * @return {fabric.PencilBrush} Instance of a pencil brush\n     */\n    initialize: function(canvas) {\n      this.canvas = canvas;\n      this._points = [];\n    },\n\n    needsFullRender: function () {\n      return this.callSuper('needsFullRender') || this._hasStraightLine;\n    },\n\n    /**\n     * Invoked inside on mouse down and mouse move\n     * @param {Object} pointer\n     */\n    _drawSegment: function (ctx, p1, p2) {\n      var midPoint = p1.midPointFrom(p2);\n      ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);\n      return midPoint;\n    },\n\n    /**\n     * Invoked on mouse down\n     * @param {Object} pointer\n     */\n    onMouseDown: function(pointer, options) {\n      if (!this.canvas._isMainEvent(options.e)) {\n        return;\n      }\n      this.drawStraightLine = options.e[this.straightLineKey];\n      this._prepareForDrawing(pointer);\n      // capture coordinates immediately\n      // this allows to draw dots (when movement never occurs)\n      this._captureDrawingPath(pointer);\n      this._render();\n    },\n\n    /**\n     * Invoked on mouse move\n     * @param {Object} pointer\n     */\n    onMouseMove: function(pointer, options) {\n      if (!this.canvas._isMainEvent(options.e)) {\n        return;\n      }\n      this.drawStraightLine = options.e[this.straightLineKey];\n      if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {\n        return;\n      }\n      if (this._captureDrawingPath(pointer) && this._points.length > 1) {\n        if (this.needsFullRender()) {\n          // redraw curve\n          // clear top canvas\n          this.canvas.clearContext(this.canvas.contextTop);\n          this._render();\n        }\n        else {\n          var points = this._points, length = points.length, ctx = this.canvas.contextTop;\n          // draw the curve update\n          this._saveAndTransform(ctx);\n          if (this.oldEnd) {\n            ctx.beginPath();\n            ctx.moveTo(this.oldEnd.x, this.oldEnd.y);\n          }\n          this.oldEnd = this._drawSegment(ctx, points[length - 2], points[length - 1], true);\n          ctx.stroke();\n          ctx.restore();\n        }\n      }\n    },\n\n    /**\n     * Invoked on mouse up\n     */\n    onMouseUp: function(options) {\n      if (!this.canvas._isMainEvent(options.e)) {\n        return true;\n      }\n      this.drawStraightLine = false;\n      this.oldEnd = undefined;\n      this._finalizeAndAddPath();\n      return false;\n    },\n\n    /**\n     * @private\n     * @param {Object} pointer Actual mouse position related to the canvas.\n     */\n    _prepareForDrawing: function(pointer) {\n\n      var p = new fabric.Point(pointer.x, pointer.y);\n\n      this._reset();\n      this._addPoint(p);\n      this.canvas.contextTop.moveTo(p.x, p.y);\n    },\n\n    /**\n     * @private\n     * @param {fabric.Point} point Point to be added to points array\n     */\n    _addPoint: function(point) {\n      if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) {\n        return false;\n      }\n      if (this.drawStraightLine && this._points.length > 1) {\n        this._hasStraightLine = true;\n        this._points.pop();\n      }\n      this._points.push(point);\n      return true;\n    },\n\n    /**\n     * Clear points array and set contextTop canvas style.\n     * @private\n     */\n    _reset: function() {\n      this._points = [];\n      this._setBrushStyles(this.canvas.contextTop);\n      this._setShadow();\n      this._hasStraightLine = false;\n    },\n\n    /**\n     * @private\n     * @param {Object} pointer Actual mouse position related to the canvas.\n     */\n    _captureDrawingPath: function(pointer) {\n      var pointerPoint = new fabric.Point(pointer.x, pointer.y);\n      return this._addPoint(pointerPoint);\n    },\n\n    /**\n     * Draw a smooth path on the topCanvas using quadraticCurveTo\n     * @private\n     * @param {CanvasRenderingContext2D} [ctx]\n     */\n    _render: function(ctx) {\n      var i, len,\n          p1 = this._points[0],\n          p2 = this._points[1];\n      ctx = ctx || this.canvas.contextTop;\n      this._saveAndTransform(ctx);\n      ctx.beginPath();\n      //if we only have 2 points in the path and they are the same\n      //it means that the user only clicked the canvas without moving the mouse\n      //then we should be drawing a dot. A path isn't drawn between two identical dots\n      //that's why we set them apart a bit\n      if (this._points.length === 2 && p1.x === p2.x && p1.y === p2.y) {\n        var width = this.width / 1000;\n        p1 = new fabric.Point(p1.x, p1.y);\n        p2 = new fabric.Point(p2.x, p2.y);\n        p1.x -= width;\n        p2.x += width;\n      }\n      ctx.moveTo(p1.x, p1.y);\n\n      for (i = 1, len = this._points.length; i < len; i++) {\n        // we pick the point between pi + 1 & pi + 2 as the\n        // end point and p1 as our control point.\n        this._drawSegment(ctx, p1, p2);\n        p1 = this._points[i];\n        p2 = this._points[i + 1];\n      }\n      // Draw last line as a straight line while\n      // we wait for the next point to be able to calculate\n      // the bezier control point\n      ctx.lineTo(p1.x, p1.y);\n      ctx.stroke();\n      ctx.restore();\n    },\n\n    /**\n     * Converts points to SVG path\n     * @param {Array} points Array of points\n     * @return {(string|number)[][]} SVG path commands\n     */\n    convertPointsToSVGPath: function (points) {\n      var correction = this.width / 1000;\n      return fabric.util.getSmoothPathFromPoints(points, correction);\n    },\n\n    /**\n     * @private\n     * @param {(string|number)[][]} pathData SVG path commands\n     * @returns {boolean}\n     */\n    _isEmptySVGPath: function (pathData) {\n      var pathString = fabric.util.joinPath(pathData);\n      return pathString === 'M 0 0 Q 0 0 0 0 L 0 0';\n    },\n\n    /**\n     * Creates fabric.Path object to add on canvas\n     * @param {(string|number)[][]} pathData Path data\n     * @return {fabric.Path} Path to add on canvas\n     */\n    createPath: function(pathData) {\n      var path = new fabric.Path(pathData, {\n        fill: null,\n        stroke: this.color,\n        strokeWidth: this.width,\n        strokeLineCap: this.strokeLineCap,\n        strokeMiterLimit: this.strokeMiterLimit,\n        strokeLineJoin: this.strokeLineJoin,\n        strokeDashArray: this.strokeDashArray,\n      });\n      if (this.shadow) {\n        this.shadow.affectStroke = true;\n        path.shadow = new fabric.Shadow(this.shadow);\n      }\n\n      return path;\n    },\n\n    /**\n     * Decimate points array with the decimate value\n     */\n    decimatePoints: function(points, distance) {\n      if (points.length <= 2) {\n        return points;\n      }\n      var zoom = this.canvas.getZoom(), adjustedDistance = Math.pow(distance / zoom, 2),\n          i, l = points.length - 1, lastPoint = points[0], newPoints = [lastPoint],\n          cDistance;\n      for (i = 1; i < l - 1; i++) {\n        cDistance = Math.pow(lastPoint.x - points[i].x, 2) + Math.pow(lastPoint.y - points[i].y, 2);\n        if (cDistance >= adjustedDistance) {\n          lastPoint = points[i];\n          newPoints.push(lastPoint);\n        }\n      }\n      /**\n       * Add the last point from the original line to the end of the array.\n       * This ensures decimate doesn't delete the last point on the line, and ensures the line is > 1 point.\n       */\n      newPoints.push(points[l]);\n      return newPoints;\n    },\n\n    /**\n     * On mouseup after drawing the path on contextTop canvas\n     * we use the points captured to create an new fabric path object\n     * and add it to the fabric canvas.\n     */\n    _finalizeAndAddPath: function() {\n      var ctx = this.canvas.contextTop;\n      ctx.closePath();\n      if (this.decimate) {\n        this._points = this.decimatePoints(this._points, this.decimate);\n      }\n      var pathData = this.convertPointsToSVGPath(this._points);\n      if (this._isEmptySVGPath(pathData)) {\n        // do not create 0 width/height paths, as they are\n        // rendered inconsistently across browsers\n        // Firefox 4, for example, renders a dot,\n        // whereas Chrome 10 renders nothing\n        this.canvas.requestRenderAll();\n        return;\n      }\n\n      var path = this.createPath(pathData);\n      this.canvas.clearContext(this.canvas.contextTop);\n      this.canvas.fire('before:path:created', { path: path });\n      this.canvas.add(path);\n      this.canvas.requestRenderAll();\n      path.setCoords();\n      this._resetShadow();\n\n\n      // fire event 'path' created\n      this.canvas.fire('path:created', { path: path });\n    }\n  });\n})();\n\n\n/**\n * CircleBrush class\n * @class fabric.CircleBrush\n */\nfabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.CircleBrush.prototype */ {\n\n  /**\n   * Width of a brush\n   * @type Number\n   * @default\n   */\n  width: 10,\n\n  /**\n   * Constructor\n   * @param {fabric.Canvas} canvas\n   * @return {fabric.CircleBrush} Instance of a circle brush\n   */\n  initialize: function(canvas) {\n    this.canvas = canvas;\n    this.points = [];\n  },\n\n  /**\n   * Invoked inside on mouse down and mouse move\n   * @param {Object} pointer\n   */\n  drawDot: function(pointer) {\n    var point = this.addPoint(pointer),\n        ctx = this.canvas.contextTop;\n    this._saveAndTransform(ctx);\n    this.dot(ctx, point);\n    ctx.restore();\n  },\n\n  dot: function(ctx, point) {\n    ctx.fillStyle = point.fill;\n    ctx.beginPath();\n    ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);\n    ctx.closePath();\n    ctx.fill();\n  },\n\n  /**\n   * Invoked on mouse down\n   */\n  onMouseDown: function(pointer) {\n    this.points.length = 0;\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._setShadow();\n    this.drawDot(pointer);\n  },\n\n  /**\n   * Render the full state of the brush\n   * @private\n   */\n  _render: function() {\n    var ctx  = this.canvas.contextTop, i, len,\n        points = this.points;\n    this._saveAndTransform(ctx);\n    for (i = 0, len = points.length; i < len; i++) {\n      this.dot(ctx, points[i]);\n    }\n    ctx.restore();\n  },\n\n  /**\n   * Invoked on mouse move\n   * @param {Object} pointer\n   */\n  onMouseMove: function(pointer) {\n    if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {\n      return;\n    }\n    if (this.needsFullRender()) {\n      this.canvas.clearContext(this.canvas.contextTop);\n      this.addPoint(pointer);\n      this._render();\n    }\n    else {\n      this.drawDot(pointer);\n    }\n  },\n\n  /**\n   * Invoked on mouse up\n   */\n  onMouseUp: function() {\n    var originalRenderOnAddRemove = this.canvas.renderOnAddRemove, i, len;\n    this.canvas.renderOnAddRemove = false;\n\n    var circles = [];\n\n    for (i = 0, len = this.points.length; i < len; i++) {\n      var point = this.points[i],\n          circle = new fabric.Circle({\n            radius: point.radius,\n            left: point.x,\n            top: point.y,\n            originX: 'center',\n            originY: 'center',\n            fill: point.fill\n          });\n\n      this.shadow && (circle.shadow = new fabric.Shadow(this.shadow));\n\n      circles.push(circle);\n    }\n    var group = new fabric.Group(circles);\n    group.canvas = this.canvas;\n\n    this.canvas.fire('before:path:created', { path: group });\n    this.canvas.add(group);\n    this.canvas.fire('path:created', { path: group });\n\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._resetShadow();\n    this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n    this.canvas.requestRenderAll();\n  },\n\n  /**\n   * @param {Object} pointer\n   * @return {fabric.Point} Just added pointer point\n   */\n  addPoint: function(pointer) {\n    var pointerPoint = new fabric.Point(pointer.x, pointer.y),\n\n        circleRadius = fabric.util.getRandomInt(\n          Math.max(0, this.width - 20), this.width + 20) / 2,\n\n        circleColor = new fabric.Color(this.color)\n          .setAlpha(fabric.util.getRandomInt(0, 100) / 100)\n          .toRgba();\n\n    pointerPoint.radius = circleRadius;\n    pointerPoint.fill = circleColor;\n\n    this.points.push(pointerPoint);\n\n    return pointerPoint;\n  }\n});\n\n\n/**\n * SprayBrush class\n * @class fabric.SprayBrush\n */\nfabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric.SprayBrush.prototype */ {\n\n  /**\n   * Width of a spray\n   * @type Number\n   * @default\n   */\n  width:              10,\n\n  /**\n   * Density of a spray (number of dots per chunk)\n   * @type Number\n   * @default\n   */\n  density:            20,\n\n  /**\n   * Width of spray dots\n   * @type Number\n   * @default\n   */\n  dotWidth:           1,\n\n  /**\n   * Width variance of spray dots\n   * @type Number\n   * @default\n   */\n  dotWidthVariance:   1,\n\n  /**\n   * Whether opacity of a dot should be random\n   * @type Boolean\n   * @default\n   */\n  randomOpacity:        false,\n\n  /**\n   * Whether overlapping dots (rectangles) should be removed (for performance reasons)\n   * @type Boolean\n   * @default\n   */\n  optimizeOverlapping:  true,\n\n  /**\n   * Constructor\n   * @param {fabric.Canvas} canvas\n   * @return {fabric.SprayBrush} Instance of a spray brush\n   */\n  initialize: function(canvas) {\n    this.canvas = canvas;\n    this.sprayChunks = [];\n  },\n\n  /**\n   * Invoked on mouse down\n   * @param {Object} pointer\n   */\n  onMouseDown: function(pointer) {\n    this.sprayChunks.length = 0;\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._setShadow();\n\n    this.addSprayChunk(pointer);\n    this.render(this.sprayChunkPoints);\n  },\n\n  /**\n   * Invoked on mouse move\n   * @param {Object} pointer\n   */\n  onMouseMove: function(pointer) {\n    if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {\n      return;\n    }\n    this.addSprayChunk(pointer);\n    this.render(this.sprayChunkPoints);\n  },\n\n  /**\n   * Invoked on mouse up\n   */\n  onMouseUp: function() {\n    var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;\n    this.canvas.renderOnAddRemove = false;\n\n    var rects = [];\n\n    for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {\n      var sprayChunk = this.sprayChunks[i];\n\n      for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) {\n\n        var rect = new fabric.Rect({\n          width: sprayChunk[j].width,\n          height: sprayChunk[j].width,\n          left: sprayChunk[j].x + 1,\n          top: sprayChunk[j].y + 1,\n          originX: 'center',\n          originY: 'center',\n          fill: this.color\n        });\n        rects.push(rect);\n      }\n    }\n\n    if (this.optimizeOverlapping) {\n      rects = this._getOptimizedRects(rects);\n    }\n\n    var group = new fabric.Group(rects);\n    this.shadow && group.set('shadow', new fabric.Shadow(this.shadow));\n    this.canvas.fire('before:path:created', { path: group });\n    this.canvas.add(group);\n    this.canvas.fire('path:created', { path: group });\n\n    this.canvas.clearContext(this.canvas.contextTop);\n    this._resetShadow();\n    this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n    this.canvas.requestRenderAll();\n  },\n\n  /**\n   * @private\n   * @param {Array} rects\n   */\n  _getOptimizedRects: function(rects) {\n\n    // avoid creating duplicate rects at the same coordinates\n    var uniqueRects = { }, key, i, len;\n\n    for (i = 0, len = rects.length; i < len; i++) {\n      key = rects[i].left + '' + rects[i].top;\n      if (!uniqueRects[key]) {\n        uniqueRects[key] = rects[i];\n      }\n    }\n    var uniqueRectsArray = [];\n    for (key in uniqueRects) {\n      uniqueRectsArray.push(uniqueRects[key]);\n    }\n\n    return uniqueRectsArray;\n  },\n\n  /**\n   * Render new chunk of spray brush\n   */\n  render: function(sprayChunk) {\n    var ctx = this.canvas.contextTop, i, len;\n    ctx.fillStyle = this.color;\n\n    this._saveAndTransform(ctx);\n\n    for (i = 0, len = sprayChunk.length; i < len; i++) {\n      var point = sprayChunk[i];\n      if (typeof point.opacity !== 'undefined') {\n        ctx.globalAlpha = point.opacity;\n      }\n      ctx.fillRect(point.x, point.y, point.width, point.width);\n    }\n    ctx.restore();\n  },\n\n  /**\n   * Render all spray chunks\n   */\n  _render: function() {\n    var ctx = this.canvas.contextTop, i, ilen;\n    ctx.fillStyle = this.color;\n\n    this._saveAndTransform(ctx);\n\n    for (i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {\n      this.render(this.sprayChunks[i]);\n    }\n    ctx.restore();\n  },\n\n  /**\n   * @param {Object} pointer\n   */\n  addSprayChunk: function(pointer) {\n    this.sprayChunkPoints = [];\n\n    var x, y, width, radius = this.width / 2, i;\n\n    for (i = 0; i < this.density; i++) {\n\n      x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius);\n      y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius);\n\n      if (this.dotWidthVariance) {\n        width = fabric.util.getRandomInt(\n          // bottom clamp width to 1\n          Math.max(1, this.dotWidth - this.dotWidthVariance),\n          this.dotWidth + this.dotWidthVariance);\n      }\n      else {\n        width = this.dotWidth;\n      }\n\n      var point = new fabric.Point(x, y);\n      point.width = width;\n\n      if (this.randomOpacity) {\n        point.opacity = fabric.util.getRandomInt(0, 100) / 100;\n      }\n\n      this.sprayChunkPoints.push(point);\n    }\n\n    this.sprayChunks.push(this.sprayChunkPoints);\n  }\n});\n\n\n/**\n * PatternBrush class\n * @class fabric.PatternBrush\n * @extends fabric.BaseBrush\n */\nfabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fabric.PatternBrush.prototype */ {\n\n  getPatternSrc: function() {\n\n    var dotWidth = 20,\n        dotDistance = 5,\n        patternCanvas = fabric.util.createCanvasElement(),\n        patternCtx = patternCanvas.getContext('2d');\n\n    patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;\n\n    patternCtx.fillStyle = this.color;\n    patternCtx.beginPath();\n    patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false);\n    patternCtx.closePath();\n    patternCtx.fill();\n\n    return patternCanvas;\n  },\n\n  getPatternSrcFunction: function() {\n    return String(this.getPatternSrc).replace('this.color', '\"' + this.color + '\"');\n  },\n\n  /**\n   * Creates \"pattern\" instance property\n   * @param {CanvasRenderingContext2D} ctx\n   */\n  getPattern: function(ctx) {\n    return ctx.createPattern(this.source || this.getPatternSrc(), 'repeat');\n  },\n\n  /**\n   * Sets brush styles\n   * @param {CanvasRenderingContext2D} ctx\n   */\n  _setBrushStyles: function(ctx) {\n    this.callSuper('_setBrushStyles', ctx);\n    ctx.strokeStyle = this.getPattern(ctx);\n  },\n\n  /**\n   * Creates path\n   */\n  createPath: function(pathData) {\n    var path = this.callSuper('createPath', pathData),\n        topLeft = path._getLeftTopCoords().scalarAdd(path.strokeWidth / 2);\n\n    path.stroke = new fabric.Pattern({\n      source: this.source || this.getPatternSrcFunction(),\n      offsetX: -topLeft.x,\n      offsetY: -topLeft.y\n    });\n    return path;\n  }\n});\n\n\n(function() {\n\n  var getPointer = fabric.util.getPointer,\n      degreesToRadians = fabric.util.degreesToRadians,\n      isTouchEvent = fabric.util.isTouchEvent;\n\n  /**\n   * Canvas class\n   * @class fabric.Canvas\n   * @extends fabric.StaticCanvas\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#canvas}\n   * @see {@link fabric.Canvas#initialize} for constructor definition\n   *\n   * @fires object:modified at the end of a transform or any change when statefull is true\n   * @fires object:rotating while an object is being rotated from the control\n   * @fires object:scaling while an object is being scaled by controls\n   * @fires object:moving while an object is being dragged\n   * @fires object:skewing while an object is being skewed from the controls\n   *\n   * @fires before:transform before a transform is is started\n   * @fires before:selection:cleared\n   * @fires selection:cleared\n   * @fires selection:updated\n   * @fires selection:created\n   *\n   * @fires path:created after a drawing operation ends and the path is added\n   * @fires mouse:down\n   * @fires mouse:move\n   * @fires mouse:up\n   * @fires mouse:down:before  on mouse down, before the inner fabric logic runs\n   * @fires mouse:move:before on mouse move, before the inner fabric logic runs\n   * @fires mouse:up:before on mouse up, before the inner fabric logic runs\n   * @fires mouse:over\n   * @fires mouse:out\n   * @fires mouse:dblclick whenever a native dbl click event fires on the canvas.\n   *\n   * @fires dragover\n   * @fires dragenter\n   * @fires dragleave\n   * @fires drop:before before drop event. same native event. This is added to handle edge cases\n   * @fires drop\n   * @fires after:render at the end of the render process, receives the context in the callback\n   * @fires before:render at start the render process, receives the context in the callback\n   *\n   */\n  fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {\n\n    /**\n     * Constructor\n     * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(el, options) {\n      options || (options = { });\n      this.renderAndResetBound = this.renderAndReset.bind(this);\n      this.requestRenderAllBound = this.requestRenderAll.bind(this);\n      this._initStatic(el, options);\n      this._initInteractive();\n      this._createCacheCanvas();\n    },\n\n    /**\n     * When true, objects can be transformed by one side (unproportionally)\n     * when dragged on the corners that normally would not do that.\n     * @type Boolean\n     * @default\n     * @since fabric 4.0 // changed name and default value\n     */\n    uniformScaling:      true,\n\n    /**\n     * Indicates which key switches uniform scaling.\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled.\n     * totally wrong named. this sounds like `uniform scaling`\n     * if Canvas.uniformScaling is true, pressing this will set it to false\n     * and viceversa.\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    uniScaleKey:           'shiftKey',\n\n    /**\n     * When true, objects use center point as the origin of scale transformation.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredScaling:        false,\n\n    /**\n     * When true, objects use center point as the origin of rotate transformation.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredRotation:       false,\n\n    /**\n     * Indicates which key enable centered Transform\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled feature disabled.\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    centeredKey:           'altKey',\n\n    /**\n     * Indicates which key enable alternate action on corner\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled feature disabled.\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    altActionKey:           'shiftKey',\n\n    /**\n     * Indicates that canvas is interactive. This property should not be changed.\n     * @type Boolean\n     * @default\n     */\n    interactive:            true,\n\n    /**\n     * Indicates whether group selection should be enabled\n     * @type Boolean\n     * @default\n     */\n    selection:              true,\n\n    /**\n     * Indicates which key or keys enable multiple click selection\n     * Pass value as a string or array of strings\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * If `null` or empty or containing any other string that is not a modifier key\n     * feature is disabled.\n     * @since 1.6.2\n     * @type String|Array\n     * @default\n     */\n    selectionKey:           'shiftKey',\n\n    /**\n     * Indicates which key enable alternative selection\n     * in case of target overlapping with active object\n     * values: 'altKey', 'shiftKey', 'ctrlKey'.\n     * For a series of reason that come from the general expectations on how\n     * things should work, this feature works only for preserveObjectStacking true.\n     * If `null` or 'none' or any other string that is not a modifier key\n     * feature is disabled.\n     * @since 1.6.5\n     * @type null|String\n     * @default\n     */\n    altSelectionKey:           null,\n\n    /**\n     * Color of selection\n     * @type String\n     * @default\n     */\n    selectionColor:         'rgba(100, 100, 255, 0.3)', // blue\n\n    /**\n     * Default dash array pattern\n     * If not empty the selection border is dashed\n     * @type Array\n     */\n    selectionDashArray:     [],\n\n    /**\n     * Color of the border of selection (usually slightly darker than color of selection itself)\n     * @type String\n     * @default\n     */\n    selectionBorderColor:   'rgba(255, 255, 255, 0.3)',\n\n    /**\n     * Width of a line used in object/group selection\n     * @type Number\n     * @default\n     */\n    selectionLineWidth:     1,\n\n    /**\n     * Select only shapes that are fully contained in the dragged selection rectangle.\n     * @type Boolean\n     * @default\n     */\n    selectionFullyContained: false,\n\n    /**\n     * Default cursor value used when hovering over an object on canvas\n     * @type String\n     * @default\n     */\n    hoverCursor:            'move',\n\n    /**\n     * Default cursor value used when moving an object on canvas\n     * @type String\n     * @default\n     */\n    moveCursor:             'move',\n\n    /**\n     * Default cursor value used for the entire canvas\n     * @type String\n     * @default\n     */\n    defaultCursor:          'default',\n\n    /**\n     * Cursor value used during free drawing\n     * @type String\n     * @default\n     */\n    freeDrawingCursor:      'crosshair',\n\n    /**\n     * Cursor value used for disabled elements ( corners with disabled action )\n     * @type String\n     * @since 2.0.0\n     * @default\n     */\n    notAllowedCursor:         'not-allowed',\n\n    /**\n     * Default element class that's given to wrapper (div) element of canvas\n     * @type String\n     * @default\n     */\n    containerClass:         'canvas-container',\n\n    /**\n     * When true, object detection happens on per-pixel basis rather than on per-bounding-box\n     * @type Boolean\n     * @default\n     */\n    perPixelTargetFind:     false,\n\n    /**\n     * Number of pixels around target pixel to tolerate (consider active) during object detection\n     * @type Number\n     * @default\n     */\n    targetFindTolerance:    0,\n\n    /**\n     * When true, target detection is skipped. Target detection will return always undefined.\n     * click selection won't work anymore, events will fire with no targets.\n     * if something is selected before setting it to true, it will be deselected at the first click.\n     * area selection will still work. check the `selection` property too.\n     * if you deactivate both, you should look into staticCanvas.\n     * @type Boolean\n     * @default\n     */\n    skipTargetFind:         false,\n\n    /**\n     * When true, mouse events on canvas (mousedown/mousemove/mouseup) result in free drawing.\n     * After mousedown, mousemove creates a shape,\n     * and then mouseup finalizes it and adds an instance of `fabric.Path` onto canvas.\n     * @tutorial {@link http://fabricjs.com/fabric-intro-part-4#free_drawing}\n     * @type Boolean\n     * @default\n     */\n    isDrawingMode:          false,\n\n    /**\n     * Indicates whether objects should remain in current stack position when selected.\n     * When false objects are brought to top and rendered as part of the selection group\n     * @type Boolean\n     * @default\n     */\n    preserveObjectStacking: false,\n\n    /**\n     * Indicates the angle that an object will lock to while rotating.\n     * @type Number\n     * @since 1.6.7\n     * @default\n     */\n    snapAngle: 0,\n\n    /**\n     * Indicates the distance from the snapAngle the rotation will lock to the snapAngle.\n     * When `null`, the snapThreshold will default to the snapAngle.\n     * @type null|Number\n     * @since 1.6.7\n     * @default\n     */\n    snapThreshold: null,\n\n    /**\n     * Indicates if the right click on canvas can output the context menu or not\n     * @type Boolean\n     * @since 1.6.5\n     * @default\n     */\n    stopContextMenu: false,\n\n    /**\n     * Indicates if the canvas can fire right click events\n     * @type Boolean\n     * @since 1.6.5\n     * @default\n     */\n    fireRightClick: false,\n\n    /**\n     * Indicates if the canvas can fire middle click events\n     * @type Boolean\n     * @since 1.7.8\n     * @default\n     */\n    fireMiddleClick: false,\n\n    /**\n     * Keep track of the subTargets for Mouse Events\n     * @type fabric.Object[]\n     */\n    targets: [],\n\n    /**\n     * When the option is enabled, PointerEvent is used instead of MouseEvent.\n     * @type Boolean\n     * @default\n     */\n    enablePointerEvents: false,\n\n    /**\n     * Keep track of the hovered target\n     * @type fabric.Object\n     * @private\n     */\n    _hoveredTarget: null,\n\n    /**\n     * hold the list of nested targets hovered\n     * @type fabric.Object[]\n     * @private\n     */\n    _hoveredTargets: [],\n\n    /**\n     * @private\n     */\n    _initInteractive: function() {\n      this._currentTransform = null;\n      this._groupSelector = null;\n      this._initWrapperElement();\n      this._createUpperCanvas();\n      this._initEventListeners();\n\n      this._initRetinaScaling();\n\n      this.freeDrawingBrush = fabric.PencilBrush && new fabric.PencilBrush(this);\n\n      this.calcOffset();\n    },\n\n    /**\n     * Divides objects in two groups, one to render immediately\n     * and one to render as activeGroup.\n     * @return {Array} objects to render immediately and pushes the other in the activeGroup.\n     */\n    _chooseObjectsToRender: function() {\n      var activeObjects = this.getActiveObjects(),\n          object, objsToRender, activeGroupObjects;\n\n      if (activeObjects.length > 0 && !this.preserveObjectStacking) {\n        objsToRender = [];\n        activeGroupObjects = [];\n        for (var i = 0, length = this._objects.length; i < length; i++) {\n          object = this._objects[i];\n          if (activeObjects.indexOf(object) === -1 ) {\n            objsToRender.push(object);\n          }\n          else {\n            activeGroupObjects.push(object);\n          }\n        }\n        if (activeObjects.length > 1) {\n          this._activeObject._objects = activeGroupObjects;\n        }\n        objsToRender.push.apply(objsToRender, activeGroupObjects);\n      }\n      else {\n        objsToRender = this._objects;\n      }\n      return objsToRender;\n    },\n\n    /**\n     * Renders both the top canvas and the secondary container canvas.\n     * @return {fabric.Canvas} instance\n     * @chainable\n     */\n    renderAll: function () {\n      if (this.contextTopDirty && !this._groupSelector && !this.isDrawingMode) {\n        this.clearContext(this.contextTop);\n        this.contextTopDirty = false;\n      }\n      if (this.hasLostContext) {\n        this.renderTopLayer(this.contextTop);\n        this.hasLostContext = false;\n      }\n      var canvasToDrawOn = this.contextContainer;\n      this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());\n      return this;\n    },\n\n    renderTopLayer: function(ctx) {\n      ctx.save();\n      if (this.isDrawingMode && this._isCurrentlyDrawing) {\n        this.freeDrawingBrush && this.freeDrawingBrush._render();\n        this.contextTopDirty = true;\n      }\n      // we render the top context - last object\n      if (this.selection && this._groupSelector) {\n        this._drawSelection(ctx);\n        this.contextTopDirty = true;\n      }\n      ctx.restore();\n    },\n\n    /**\n     * Method to render only the top canvas.\n     * Also used to render the group selection box.\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    renderTop: function () {\n      var ctx = this.contextTop;\n      this.clearContext(ctx);\n      this.renderTopLayer(ctx);\n      this.fire('after:render');\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _normalizePointer: function (object, pointer) {\n      var m = object.calcTransformMatrix(),\n          invertedM = fabric.util.invertTransform(m),\n          vptPointer = this.restorePointerVpt(pointer);\n      return fabric.util.transformPoint(vptPointer, invertedM);\n    },\n\n    /**\n     * Returns true if object is transparent at a certain location\n     * @param {fabric.Object} target Object to check\n     * @param {Number} x Left coordinate\n     * @param {Number} y Top coordinate\n     * @return {Boolean}\n     */\n    isTargetTransparent: function (target, x, y) {\n      // in case the target is the activeObject, we cannot execute this optimization\n      // because we need to draw controls too.\n      if (target.shouldCache() && target._cacheCanvas && target !== this._activeObject) {\n        var normalizedPointer = this._normalizePointer(target, {x: x, y: y}),\n            targetRelativeX = Math.max(target.cacheTranslationX + (normalizedPointer.x * target.zoomX), 0),\n            targetRelativeY = Math.max(target.cacheTranslationY + (normalizedPointer.y * target.zoomY), 0);\n\n        var isTransparent = fabric.util.isTransparent(\n          target._cacheContext, Math.round(targetRelativeX), Math.round(targetRelativeY), this.targetFindTolerance);\n\n        return isTransparent;\n      }\n\n      var ctx = this.contextCache,\n          originalColor = target.selectionBackgroundColor, v = this.viewportTransform;\n\n      target.selectionBackgroundColor = '';\n\n      this.clearContext(ctx);\n\n      ctx.save();\n      ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n      target.render(ctx);\n      ctx.restore();\n\n      target.selectionBackgroundColor = originalColor;\n\n      var isTransparent = fabric.util.isTransparent(\n        ctx, x, y, this.targetFindTolerance);\n\n      return isTransparent;\n    },\n\n    /**\n     * takes an event and determines if selection key has been pressed\n     * @private\n     * @param {Event} e Event object\n     */\n    _isSelectionKeyPressed: function(e) {\n      var selectionKeyPressed = false;\n\n      if (Array.isArray(this.selectionKey)) {\n        selectionKeyPressed = !!this.selectionKey.find(function(key) { return e[key] === true; });\n      }\n      else {\n        selectionKeyPressed = e[this.selectionKey];\n      }\n\n      return selectionKeyPressed;\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     */\n    _shouldClearSelection: function (e, target) {\n      var activeObjects = this.getActiveObjects(),\n          activeObject = this._activeObject;\n\n      return (\n        !target\n        ||\n        (target &&\n          activeObject &&\n          activeObjects.length > 1 &&\n          activeObjects.indexOf(target) === -1 &&\n          activeObject !== target &&\n          !this._isSelectionKeyPressed(e))\n        ||\n        (target && !target.evented)\n        ||\n        (target &&\n          !target.selectable &&\n          activeObject &&\n          activeObject !== target)\n      );\n    },\n\n    /**\n     * centeredScaling from object can't override centeredScaling from canvas.\n     * this should be fixed, since object setting should take precedence over canvas.\n     * also this should be something that will be migrated in the control properties.\n     * as ability to define the origin of the transformation that the control provide.\n     * @private\n     * @param {fabric.Object} target\n     * @param {String} action\n     * @param {Boolean} altKey\n     */\n    _shouldCenterTransform: function (target, action, altKey) {\n      if (!target) {\n        return;\n      }\n\n      var centerTransform;\n\n      if (action === 'scale' || action === 'scaleX' || action === 'scaleY' || action === 'resizing') {\n        centerTransform = this.centeredScaling || target.centeredScaling;\n      }\n      else if (action === 'rotate') {\n        centerTransform = this.centeredRotation || target.centeredRotation;\n      }\n\n      return centerTransform ? !altKey : altKey;\n    },\n\n    /**\n     * should disappear before release 4.0\n     * @private\n     */\n    _getOriginFromCorner: function(target, corner) {\n      var origin = {\n        x: target.originX,\n        y: target.originY\n      };\n\n      if (corner === 'ml' || corner === 'tl' || corner === 'bl') {\n        origin.x = 'right';\n      }\n      else if (corner === 'mr' || corner === 'tr' || corner === 'br') {\n        origin.x = 'left';\n      }\n\n      if (corner === 'tl' || corner === 'mt' || corner === 'tr') {\n        origin.y = 'bottom';\n      }\n      else if (corner === 'bl' || corner === 'mb' || corner === 'br') {\n        origin.y = 'top';\n      }\n      return origin;\n    },\n\n    /**\n     * @private\n     * @param {Boolean} alreadySelected true if target is already selected\n     * @param {String} corner a string representing the corner ml, mr, tl ...\n     * @param {Event} e Event object\n     * @param {fabric.Object} [target] inserted back to help overriding. Unused\n     */\n    _getActionFromCorner: function(alreadySelected, corner, e, target) {\n      if (!corner || !alreadySelected) {\n        return 'drag';\n      }\n      var control = target.controls[corner];\n      return control.getActionName(e, control, target);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     */\n    _setupCurrentTransform: function (e, target, alreadySelected) {\n      if (!target) {\n        return;\n      }\n\n      var pointer = this.getPointer(e), corner = target.__corner,\n          control = target.controls[corner],\n          actionHandler = (alreadySelected && corner) ?\n            control.getActionHandler(e, target, control) : fabric.controlsUtils.dragHandler,\n          action = this._getActionFromCorner(alreadySelected, corner, e, target),\n          origin = this._getOriginFromCorner(target, corner),\n          altKey = e[this.centeredKey],\n          transform = {\n            target: target,\n            action: action,\n            actionHandler: actionHandler,\n            corner: corner,\n            scaleX: target.scaleX,\n            scaleY: target.scaleY,\n            skewX: target.skewX,\n            skewY: target.skewY,\n            // used by transation\n            offsetX: pointer.x - target.left,\n            offsetY: pointer.y - target.top,\n            originX: origin.x,\n            originY: origin.y,\n            ex: pointer.x,\n            ey: pointer.y,\n            lastX: pointer.x,\n            lastY: pointer.y,\n            // unsure they are useful anymore.\n            // left: target.left,\n            // top: target.top,\n            theta: degreesToRadians(target.angle),\n            // end of unsure\n            width: target.width * target.scaleX,\n            shiftKey: e.shiftKey,\n            altKey: altKey,\n            original: fabric.util.saveObjectTransform(target),\n          };\n\n      if (this._shouldCenterTransform(target, action, altKey)) {\n        transform.originX = 'center';\n        transform.originY = 'center';\n      }\n      transform.original.originX = origin.x;\n      transform.original.originY = origin.y;\n      this._currentTransform = transform;\n      this._beforeTransform(e);\n    },\n\n    /**\n     * Set the cursor type of the canvas element\n     * @param {String} value Cursor type of the canvas element.\n     * @see http://www.w3.org/TR/css3-ui/#cursor\n     */\n    setCursor: function (value) {\n      this.upperCanvasEl.style.cursor = value;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx to draw the selection on\n     */\n    _drawSelection: function (ctx) {\n      var selector = this._groupSelector,\n          viewportStart = new fabric.Point(selector.ex, selector.ey),\n          start = fabric.util.transformPoint(viewportStart, this.viewportTransform),\n          viewportExtent = new fabric.Point(selector.ex + selector.left, selector.ey + selector.top),\n          extent = fabric.util.transformPoint(viewportExtent, this.viewportTransform),\n          minX = Math.min(start.x, extent.x),\n          minY = Math.min(start.y, extent.y),\n          maxX = Math.max(start.x, extent.x),\n          maxY = Math.max(start.y, extent.y),\n          strokeOffset = this.selectionLineWidth / 2;\n\n      if (this.selectionColor) {\n        ctx.fillStyle = this.selectionColor;\n        ctx.fillRect(minX, minY, maxX - minX, maxY - minY);\n      }\n\n      if (!this.selectionLineWidth || !this.selectionBorderColor) {\n        return;\n      }\n      ctx.lineWidth = this.selectionLineWidth;\n      ctx.strokeStyle = this.selectionBorderColor;\n\n      minX += strokeOffset;\n      minY += strokeOffset;\n      maxX -= strokeOffset;\n      maxY -= strokeOffset;\n      // selection border\n      fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);\n      ctx.strokeRect(minX, minY, maxX - minX, maxY - minY);\n    },\n\n    /**\n     * Method that determines what object we are clicking on\n     * the skipGroup parameter is for internal use, is needed for shift+click action\n     * 11/09/2018 TODO: would be cool if findTarget could discern between being a full target\n     * or the outside part of the corner.\n     * @param {Event} e mouse event\n     * @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through\n     * @return {fabric.Object} the target found\n     */\n    findTarget: function (e, skipGroup) {\n      if (this.skipTargetFind) {\n        return;\n      }\n\n      var ignoreZoom = true,\n          pointer = this.getPointer(e, ignoreZoom),\n          activeObject = this._activeObject,\n          aObjects = this.getActiveObjects(),\n          activeTarget, activeTargetSubs,\n          isTouch = isTouchEvent(e),\n          shouldLookForActive = (aObjects.length > 1 && !skipGroup) || aObjects.length === 1;\n\n      // first check current group (if one exists)\n      // active group does not check sub targets like normal groups.\n      // if active group just exits.\n      this.targets = [];\n\n      // if we hit the corner of an activeObject, let's return that.\n      if (shouldLookForActive && activeObject._findTargetCorner(pointer, isTouch)) {\n        return activeObject;\n      }\n      if (aObjects.length > 1 && !skipGroup && activeObject === this._searchPossibleTargets([activeObject], pointer)) {\n        return activeObject;\n      }\n      if (aObjects.length === 1 &&\n        activeObject === this._searchPossibleTargets([activeObject], pointer)) {\n        if (!this.preserveObjectStacking) {\n          return activeObject;\n        }\n        else {\n          activeTarget = activeObject;\n          activeTargetSubs = this.targets;\n          this.targets = [];\n        }\n      }\n      var target = this._searchPossibleTargets(this._objects, pointer);\n      if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) {\n        target = activeTarget;\n        this.targets = activeTargetSubs;\n      }\n      return target;\n    },\n\n    /**\n     * Checks point is inside the object.\n     * @param {Object} [pointer] x,y object of point coordinates we want to check.\n     * @param {fabric.Object} obj Object to test against\n     * @param {Object} [globalPointer] x,y object of point coordinates relative to canvas used to search per pixel target.\n     * @return {Boolean} true if point is contained within an area of given object\n     * @private\n     */\n    _checkTarget: function(pointer, obj, globalPointer) {\n      if (obj &&\n          obj.visible &&\n          obj.evented &&\n          // http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html\n          // http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html\n          obj.containsPoint(pointer)\n      ) {\n        if ((this.perPixelTargetFind || obj.perPixelTargetFind) && !obj.isEditing) {\n          var isTransparent = this.isTargetTransparent(obj, globalPointer.x, globalPointer.y);\n          if (!isTransparent) {\n            return true;\n          }\n        }\n        else {\n          return true;\n        }\n      }\n    },\n\n    /**\n     * Function used to search inside objects an object that contains pointer in bounding box or that contains pointerOnCanvas when painted\n     * @param {Array} [objects] objects array to look into\n     * @param {Object} [pointer] x,y object of point coordinates we want to check.\n     * @return {fabric.Object} object that contains pointer\n     * @private\n     */\n    _searchPossibleTargets: function(objects, pointer) {\n      // Cache all targets where their bounding box contains point.\n      var target, i = objects.length, subTarget;\n      // Do not check for currently grouped objects, since we check the parent group itself.\n      // until we call this function specifically to search inside the activeGroup\n      while (i--) {\n        var objToCheck = objects[i];\n        var pointerToUse = objToCheck.group ?\n          this._normalizePointer(objToCheck.group, pointer) : pointer;\n        if (this._checkTarget(pointerToUse, objToCheck, pointer)) {\n          target = objects[i];\n          if (target.subTargetCheck && target instanceof fabric.Group) {\n            subTarget = this._searchPossibleTargets(target._objects, pointer);\n            subTarget && this.targets.push(subTarget);\n          }\n          break;\n        }\n      }\n      return target;\n    },\n\n    /**\n     * Returns pointer coordinates without the effect of the viewport\n     * @param {Object} pointer with \"x\" and \"y\" number values\n     * @return {Object} object with \"x\" and \"y\" number values\n     */\n    restorePointerVpt: function(pointer) {\n      return fabric.util.transformPoint(\n        pointer,\n        fabric.util.invertTransform(this.viewportTransform)\n      );\n    },\n\n    /**\n     * Returns pointer coordinates relative to canvas.\n     * Can return coordinates with or without viewportTransform.\n     * ignoreZoom false gives back coordinates that represent\n     * the point clicked on canvas element.\n     * ignoreZoom true gives back coordinates after being processed\n     * by the viewportTransform ( sort of coordinates of what is displayed\n     * on the canvas where you are clicking.\n     * ignoreZoom true = HTMLElement coordinates relative to top,left\n     * ignoreZoom false, default = fabric space coordinates, the same used for shape position\n     * To interact with your shapes top and left you want to use ignoreZoom true\n     * most of the time, while ignoreZoom false will give you coordinates\n     * compatible with the object.oCoords system.\n     * of the time.\n     * @param {Event} e\n     * @param {Boolean} ignoreZoom\n     * @return {Object} object with \"x\" and \"y\" number values\n     */\n    getPointer: function (e, ignoreZoom) {\n      // return cached values if we are in the event processing chain\n      if (this._absolutePointer && !ignoreZoom) {\n        return this._absolutePointer;\n      }\n      if (this._pointer && ignoreZoom) {\n        return this._pointer;\n      }\n\n      var pointer = getPointer(e),\n          upperCanvasEl = this.upperCanvasEl,\n          bounds = upperCanvasEl.getBoundingClientRect(),\n          boundsWidth = bounds.width || 0,\n          boundsHeight = bounds.height || 0,\n          cssScale;\n\n      if (!boundsWidth || !boundsHeight ) {\n        if ('top' in bounds && 'bottom' in bounds) {\n          boundsHeight = Math.abs( bounds.top - bounds.bottom );\n        }\n        if ('right' in bounds && 'left' in bounds) {\n          boundsWidth = Math.abs( bounds.right - bounds.left );\n        }\n      }\n\n      this.calcOffset();\n      pointer.x = pointer.x - this._offset.left;\n      pointer.y = pointer.y - this._offset.top;\n      if (!ignoreZoom) {\n        pointer = this.restorePointerVpt(pointer);\n      }\n\n      var retinaScaling = this.getRetinaScaling();\n      if (retinaScaling !== 1) {\n        pointer.x /= retinaScaling;\n        pointer.y /= retinaScaling;\n      }\n\n      if (boundsWidth === 0 || boundsHeight === 0) {\n        // If bounds are not available (i.e. not visible), do not apply scale.\n        cssScale = { width: 1, height: 1 };\n      }\n      else {\n        cssScale = {\n          width: upperCanvasEl.width / boundsWidth,\n          height: upperCanvasEl.height / boundsHeight\n        };\n      }\n\n      return {\n        x: pointer.x * cssScale.width,\n        y: pointer.y * cssScale.height\n      };\n    },\n\n    /**\n     * @private\n     * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized\n     */\n    _createUpperCanvas: function () {\n      var lowerCanvasClass = this.lowerCanvasEl.className.replace(/\\s*lower-canvas\\s*/, ''),\n          lowerCanvasEl = this.lowerCanvasEl, upperCanvasEl = this.upperCanvasEl;\n\n      // there is no need to create a new upperCanvas element if we have already one.\n      if (upperCanvasEl) {\n        upperCanvasEl.className = '';\n      }\n      else {\n        upperCanvasEl = this._createCanvasElement();\n        this.upperCanvasEl = upperCanvasEl;\n      }\n      fabric.util.addClass(upperCanvasEl, 'upper-canvas ' + lowerCanvasClass);\n\n      this.wrapperEl.appendChild(upperCanvasEl);\n\n      this._copyCanvasStyle(lowerCanvasEl, upperCanvasEl);\n      this._applyCanvasStyle(upperCanvasEl);\n      this.contextTop = upperCanvasEl.getContext('2d');\n    },\n\n    /**\n     * Returns context of top canvas where interactions are drawn\n     * @returns {CanvasRenderingContext2D}\n     */\n    getTopContext: function () {\n      return this.contextTop;\n    },\n\n    /**\n     * @private\n     */\n    _createCacheCanvas: function () {\n      this.cacheCanvasEl = this._createCanvasElement();\n      this.cacheCanvasEl.setAttribute('width', this.width);\n      this.cacheCanvasEl.setAttribute('height', this.height);\n      this.contextCache = this.cacheCanvasEl.getContext('2d');\n    },\n\n    /**\n     * @private\n     */\n    _initWrapperElement: function () {\n      this.wrapperEl = fabric.util.wrapElement(this.lowerCanvasEl, 'div', {\n        'class': this.containerClass\n      });\n      fabric.util.setStyle(this.wrapperEl, {\n        width: this.width + 'px',\n        height: this.height + 'px',\n        position: 'relative'\n      });\n      fabric.util.makeElementUnselectable(this.wrapperEl);\n    },\n\n    /**\n     * @private\n     * @param {HTMLElement} element canvas element to apply styles on\n     */\n    _applyCanvasStyle: function (element) {\n      var width = this.width || element.width,\n          height = this.height || element.height;\n\n      fabric.util.setStyle(element, {\n        position: 'absolute',\n        width: width + 'px',\n        height: height + 'px',\n        left: 0,\n        top: 0,\n        'touch-action': this.allowTouchScrolling ? 'manipulation' : 'none',\n        '-ms-touch-action': this.allowTouchScrolling ? 'manipulation' : 'none'\n      });\n      element.width = width;\n      element.height = height;\n      fabric.util.makeElementUnselectable(element);\n    },\n\n    /**\n     * Copy the entire inline style from one element (fromEl) to another (toEl)\n     * @private\n     * @param {Element} fromEl Element style is copied from\n     * @param {Element} toEl Element copied style is applied to\n     */\n    _copyCanvasStyle: function (fromEl, toEl) {\n      toEl.style.cssText = fromEl.style.cssText;\n    },\n\n    /**\n     * Returns context of canvas where object selection is drawn\n     * @return {CanvasRenderingContext2D}\n     */\n    getSelectionContext: function() {\n      return this.contextTop;\n    },\n\n    /**\n     * Returns &lt;canvas> element on which object selection is drawn\n     * @return {HTMLCanvasElement}\n     */\n    getSelectionElement: function () {\n      return this.upperCanvasEl;\n    },\n\n    /**\n     * Returns currently active object\n     * @return {fabric.Object} active object\n     */\n    getActiveObject: function () {\n      return this._activeObject;\n    },\n\n    /**\n     * Returns an array with the current selected objects\n     * @return {fabric.Object} active object\n     */\n    getActiveObjects: function () {\n      var active = this._activeObject;\n      if (active) {\n        if (active.type === 'activeSelection' && active._objects) {\n          return active._objects.slice(0);\n        }\n        else {\n          return [active];\n        }\n      }\n      return [];\n    },\n\n    /**\n     * @private\n     * @param {fabric.Object} obj Object that was removed\n     */\n    _onObjectRemoved: function(obj) {\n      // removing active object should fire \"selection:cleared\" events\n      if (obj === this._activeObject) {\n        this.fire('before:selection:cleared', { target: obj });\n        this._discardActiveObject();\n        this.fire('selection:cleared', { target: obj });\n        obj.fire('deselected');\n      }\n      if (obj === this._hoveredTarget){\n        this._hoveredTarget = null;\n        this._hoveredTargets = [];\n      }\n      this.callSuper('_onObjectRemoved', obj);\n    },\n\n    /**\n     * @private\n     * Compares the old activeObject with the current one and fires correct events\n     * @param {fabric.Object} obj old activeObject\n     */\n    _fireSelectionEvents: function(oldObjects, e) {\n      var somethingChanged = false, objects = this.getActiveObjects(),\n          added = [], removed = [];\n      oldObjects.forEach(function(oldObject) {\n        if (objects.indexOf(oldObject) === -1) {\n          somethingChanged = true;\n          oldObject.fire('deselected', {\n            e: e,\n            target: oldObject\n          });\n          removed.push(oldObject);\n        }\n      });\n      objects.forEach(function(object) {\n        if (oldObjects.indexOf(object) === -1) {\n          somethingChanged = true;\n          object.fire('selected', {\n            e: e,\n            target: object\n          });\n          added.push(object);\n        }\n      });\n      if (oldObjects.length > 0 && objects.length > 0) {\n        somethingChanged && this.fire('selection:updated', {\n          e: e,\n          selected: added,\n          deselected: removed,\n        });\n      }\n      else if (objects.length > 0) {\n        this.fire('selection:created', {\n          e: e,\n          selected: added,\n        });\n      }\n      else if (oldObjects.length > 0) {\n        this.fire('selection:cleared', {\n          e: e,\n          deselected: removed,\n        });\n      }\n    },\n\n    /**\n     * Sets given object as the only active object on canvas\n     * @param {fabric.Object} object Object to set as an active one\n     * @param {Event} [e] Event (passed along when firing \"object:selected\")\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    setActiveObject: function (object, e) {\n      var currentActives = this.getActiveObjects();\n      this._setActiveObject(object, e);\n      this._fireSelectionEvents(currentActives, e);\n      return this;\n    },\n\n    /**\n     * This is a private method for now.\n     * This is supposed to be equivalent to setActiveObject but without firing\n     * any event. There is commitment to have this stay this way.\n     * This is the functional part of setActiveObject.\n     * @private\n     * @param {Object} object to set as active\n     * @param {Event} [e] Event (passed along when firing \"object:selected\")\n     * @return {Boolean} true if the selection happened\n     */\n    _setActiveObject: function(object, e) {\n      if (this._activeObject === object) {\n        return false;\n      }\n      if (!this._discardActiveObject(e, object)) {\n        return false;\n      }\n      if (object.onSelect({ e: e })) {\n        return false;\n      }\n      this._activeObject = object;\n      return true;\n    },\n\n    /**\n     * This is a private method for now.\n     * This is supposed to be equivalent to discardActiveObject but without firing\n     * any events. There is commitment to have this stay this way.\n     * This is the functional part of discardActiveObject.\n     * @param {Event} [e] Event (passed along when firing \"object:deselected\")\n     * @param {Object} object to set as active\n     * @return {Boolean} true if the selection happened\n     * @private\n     */\n    _discardActiveObject: function(e, object) {\n      var obj = this._activeObject;\n      if (obj) {\n        // onDeselect return TRUE to cancel selection;\n        if (obj.onDeselect({ e: e, object: object })) {\n          return false;\n        }\n        this._activeObject = null;\n      }\n      return true;\n    },\n\n    /**\n     * Discards currently active object and fire events. If the function is called by fabric\n     * as a consequence of a mouse event, the event is passed as a parameter and\n     * sent to the fire function for the custom events. When used as a method the\n     * e param does not have any application.\n     * @param {event} e\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    discardActiveObject: function (e) {\n      var currentActives = this.getActiveObjects(), activeObject = this.getActiveObject();\n      if (currentActives.length) {\n        this.fire('before:selection:cleared', { target: activeObject, e: e });\n      }\n      this._discardActiveObject(e);\n      this._fireSelectionEvents(currentActives, e);\n      return this;\n    },\n\n    /**\n     * Clears a canvas element and removes all event listeners\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    dispose: function () {\n      var wrapper = this.wrapperEl;\n      this.removeListeners();\n      wrapper.removeChild(this.upperCanvasEl);\n      wrapper.removeChild(this.lowerCanvasEl);\n      this.contextCache = null;\n      this.contextTop = null;\n      ['upperCanvasEl', 'cacheCanvasEl'].forEach((function(element) {\n        fabric.util.cleanUpJsdomNode(this[element]);\n        this[element] = undefined;\n      }).bind(this));\n      if (wrapper.parentNode) {\n        wrapper.parentNode.replaceChild(this.lowerCanvasEl, this.wrapperEl);\n      }\n      delete this.wrapperEl;\n      fabric.StaticCanvas.prototype.dispose.call(this);\n      return this;\n    },\n\n    /**\n     * Clears all contexts (background, main, top) of an instance\n     * @return {fabric.Canvas} thisArg\n     * @chainable\n     */\n    clear: function () {\n      // this.discardActiveGroup();\n      this.discardActiveObject();\n      this.clearContext(this.contextTop);\n      return this.callSuper('clear');\n    },\n\n    /**\n     * Draws objects' controls (borders/controls)\n     * @param {CanvasRenderingContext2D} ctx Context to render controls on\n     */\n    drawControls: function(ctx) {\n      var activeObject = this._activeObject;\n\n      if (activeObject) {\n        activeObject._renderControls(ctx);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _toObject: function(instance, methodName, propertiesToInclude) {\n      //If the object is part of the current selection group, it should\n      //be transformed appropriately\n      //i.e. it should be serialised as it would appear if the selection group\n      //were to be destroyed.\n      var originalProperties = this._realizeGroupTransformOnObject(instance),\n          object = this.callSuper('_toObject', instance, methodName, propertiesToInclude);\n      //Undo the damage we did by changing all of its properties\n      this._unwindGroupTransformOnObject(instance, originalProperties);\n      return object;\n    },\n\n    /**\n     * Realises an object's group transformation on it\n     * @private\n     * @param {fabric.Object} [instance] the object to transform (gets mutated)\n     * @returns the original values of instance which were changed\n     */\n    _realizeGroupTransformOnObject: function(instance) {\n      if (instance.group && instance.group.type === 'activeSelection' && this._activeObject === instance.group) {\n        var layoutProps = ['angle', 'flipX', 'flipY', 'left', 'scaleX', 'scaleY', 'skewX', 'skewY', 'top'];\n        //Copy all the positionally relevant properties across now\n        var originalValues = {};\n        layoutProps.forEach(function(prop) {\n          originalValues[prop] = instance[prop];\n        });\n        fabric.util.addTransformToObject(instance, this._activeObject.calcOwnMatrix());\n        return originalValues;\n      }\n      else {\n        return null;\n      }\n    },\n\n    /**\n     * Restores the changed properties of instance\n     * @private\n     * @param {fabric.Object} [instance] the object to un-transform (gets mutated)\n     * @param {Object} [originalValues] the original values of instance, as returned by _realizeGroupTransformOnObject\n     */\n    _unwindGroupTransformOnObject: function(instance, originalValues) {\n      if (originalValues) {\n        instance.set(originalValues);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setSVGObject: function(markup, instance, reviver) {\n      //If the object is in a selection group, simulate what would happen to that\n      //object when the group is deselected\n      var originalProperties = this._realizeGroupTransformOnObject(instance);\n      this.callSuper('_setSVGObject', markup, instance, reviver);\n      this._unwindGroupTransformOnObject(instance, originalProperties);\n    },\n\n    setViewportTransform: function (vpt) {\n      if (this.renderOnAddRemove && this._activeObject && this._activeObject.isEditing) {\n        this._activeObject.clearContextTop();\n      }\n      fabric.StaticCanvas.prototype.setViewportTransform.call(this, vpt);\n    }\n  });\n\n  // copying static properties manually to work around Opera's bug,\n  // where \"prototype\" property is enumerable and overrides existing prototype\n  for (var prop in fabric.StaticCanvas) {\n    if (prop !== 'prototype') {\n      fabric.Canvas[prop] = fabric.StaticCanvas[prop];\n    }\n  }\n})();\n\n\n(function() {\n\n  var addListener = fabric.util.addListener,\n      removeListener = fabric.util.removeListener,\n      RIGHT_CLICK = 3, MIDDLE_CLICK = 2, LEFT_CLICK = 1,\n      addEventOptions = { passive: false };\n\n  function checkClick(e, value) {\n    return e.button && (e.button === value - 1);\n  }\n\n  fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n    /**\n     * Contains the id of the touch event that owns the fabric transform\n     * @type Number\n     * @private\n     */\n    mainTouchId: null,\n\n    /**\n     * Adds mouse listeners to canvas\n     * @private\n     */\n    _initEventListeners: function () {\n      // in case we initialized the class twice. This should not happen normally\n      // but in some kind of applications where the canvas element may be changed\n      // this is a workaround to having double listeners.\n      this.removeListeners();\n      this._bindEvents();\n      this.addOrRemove(addListener, 'add');\n    },\n\n    /**\n     * return an event prefix pointer or mouse.\n     * @private\n     */\n    _getEventPrefix: function () {\n      return this.enablePointerEvents ? 'pointer' : 'mouse';\n    },\n\n    addOrRemove: function(functor, eventjsFunctor) {\n      var canvasElement = this.upperCanvasEl,\n          eventTypePrefix = this._getEventPrefix();\n      functor(fabric.window, 'resize', this._onResize);\n      functor(canvasElement, eventTypePrefix + 'down', this._onMouseDown);\n      functor(canvasElement, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n      functor(canvasElement, eventTypePrefix + 'out', this._onMouseOut);\n      functor(canvasElement, eventTypePrefix + 'enter', this._onMouseEnter);\n      functor(canvasElement, 'wheel', this._onMouseWheel);\n      functor(canvasElement, 'contextmenu', this._onContextMenu);\n      functor(canvasElement, 'dblclick', this._onDoubleClick);\n      functor(canvasElement, 'dragover', this._onDragOver);\n      functor(canvasElement, 'dragenter', this._onDragEnter);\n      functor(canvasElement, 'dragleave', this._onDragLeave);\n      functor(canvasElement, 'drop', this._onDrop);\n      if (!this.enablePointerEvents) {\n        functor(canvasElement, 'touchstart', this._onTouchStart, addEventOptions);\n      }\n      if (typeof eventjs !== 'undefined' && eventjsFunctor in eventjs) {\n        eventjs[eventjsFunctor](canvasElement, 'gesture', this._onGesture);\n        eventjs[eventjsFunctor](canvasElement, 'drag', this._onDrag);\n        eventjs[eventjsFunctor](canvasElement, 'orientation', this._onOrientationChange);\n        eventjs[eventjsFunctor](canvasElement, 'shake', this._onShake);\n        eventjs[eventjsFunctor](canvasElement, 'longpress', this._onLongPress);\n      }\n    },\n\n    /**\n     * Removes all event listeners\n     */\n    removeListeners: function() {\n      this.addOrRemove(removeListener, 'remove');\n      // if you dispose on a mouseDown, before mouse up, you need to clean document to...\n      var eventTypePrefix = this._getEventPrefix();\n      removeListener(fabric.document, eventTypePrefix + 'up', this._onMouseUp);\n      removeListener(fabric.document, 'touchend', this._onTouchEnd, addEventOptions);\n      removeListener(fabric.document, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n      removeListener(fabric.document, 'touchmove', this._onMouseMove, addEventOptions);\n    },\n\n    /**\n     * @private\n     */\n    _bindEvents: function() {\n      if (this.eventsBound) {\n        // for any reason we pass here twice we do not want to bind events twice.\n        return;\n      }\n      this._onMouseDown = this._onMouseDown.bind(this);\n      this._onTouchStart = this._onTouchStart.bind(this);\n      this._onMouseMove = this._onMouseMove.bind(this);\n      this._onMouseUp = this._onMouseUp.bind(this);\n      this._onTouchEnd = this._onTouchEnd.bind(this);\n      this._onResize = this._onResize.bind(this);\n      this._onGesture = this._onGesture.bind(this);\n      this._onDrag = this._onDrag.bind(this);\n      this._onShake = this._onShake.bind(this);\n      this._onLongPress = this._onLongPress.bind(this);\n      this._onOrientationChange = this._onOrientationChange.bind(this);\n      this._onMouseWheel = this._onMouseWheel.bind(this);\n      this._onMouseOut = this._onMouseOut.bind(this);\n      this._onMouseEnter = this._onMouseEnter.bind(this);\n      this._onContextMenu = this._onContextMenu.bind(this);\n      this._onDoubleClick = this._onDoubleClick.bind(this);\n      this._onDragOver = this._onDragOver.bind(this);\n      this._onDragEnter = this._simpleEventHandler.bind(this, 'dragenter');\n      this._onDragLeave = this._simpleEventHandler.bind(this, 'dragleave');\n      this._onDrop = this._onDrop.bind(this);\n      this.eventsBound = true;\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js gesture\n     * @param {Event} [self] Inner Event object\n     */\n    _onGesture: function(e, self) {\n      this.__onTransformGesture && this.__onTransformGesture(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js drag\n     * @param {Event} [self] Inner Event object\n     */\n    _onDrag: function(e, self) {\n      this.__onDrag && this.__onDrag(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on wheel event\n     */\n    _onMouseWheel: function(e) {\n      this.__onMouseWheel(e);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onMouseOut: function(e) {\n      var target = this._hoveredTarget;\n      this.fire('mouse:out', { target: target, e: e });\n      this._hoveredTarget = null;\n      target && target.fire('mouseout', { e: e });\n\n      var _this = this;\n      this._hoveredTargets.forEach(function(_target){\n        _this.fire('mouse:out', { target: _target, e: e });\n        _target && _target.fire('mouseout', { e: e });\n      });\n      this._hoveredTargets = [];\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mouseenter\n     */\n    _onMouseEnter: function(e) {\n      // This find target and consequent 'mouse:over' is used to\n      // clear old instances on hovered target.\n      // calling findTarget has the side effect of killing target.__corner.\n      // as a short term fix we are not firing this if we are currently transforming.\n      // as a long term fix we need to separate the action of finding a target with the\n      // side effects we added to it.\n      if (!this._currentTransform && !this.findTarget(e)) {\n        this.fire('mouse:over', { target: null, e: e });\n        this._hoveredTarget = null;\n        this._hoveredTargets = [];\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js orientation change\n     * @param {Event} [self] Inner Event object\n     */\n    _onOrientationChange: function(e, self) {\n      this.__onOrientationChange && this.__onOrientationChange(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js shake\n     * @param {Event} [self] Inner Event object\n     */\n    _onShake: function(e, self) {\n      this.__onShake && this.__onShake(e, self);\n    },\n\n    /**\n     * @private\n     * @param {Event} [e] Event object fired on Event.js shake\n     * @param {Event} [self] Inner Event object\n     */\n    _onLongPress: function(e, self) {\n      this.__onLongPress && this.__onLongPress(e, self);\n    },\n\n    /**\n     * prevent default to allow drop event to be fired\n     * @private\n     * @param {Event} [e] Event object fired on Event.js shake\n     */\n    _onDragOver: function(e) {\n      e.preventDefault();\n      var target = this._simpleEventHandler('dragover', e);\n      this._fireEnterLeaveEvents(target, e);\n    },\n\n    /**\n     * `drop:before` is a an event that allow you to schedule logic\n     * before the `drop` event. Prefer `drop` event always, but if you need\n     * to run some drop-disabling logic on an event, since there is no way\n     * to handle event handlers ordering, use `drop:before`\n     * @param {Event} e\n     */\n    _onDrop: function (e) {\n      this._simpleEventHandler('drop:before', e);\n      return this._simpleEventHandler('drop', e);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onContextMenu: function (e) {\n      if (this.stopContextMenu) {\n        e.stopPropagation();\n        e.preventDefault();\n      }\n      return false;\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onDoubleClick: function (e) {\n      this._cacheTransformEventData(e);\n      this._handleEvent(e, 'dblclick');\n      this._resetTransformEventData(e);\n    },\n\n    /**\n     * Return a the id of an event.\n     * returns either the pointerId or the identifier or 0 for the mouse event\n     * @private\n     * @param {Event} evt Event object\n     */\n    getPointerId: function(evt) {\n      var changedTouches = evt.changedTouches;\n\n      if (changedTouches) {\n        return changedTouches[0] && changedTouches[0].identifier;\n      }\n\n      if (this.enablePointerEvents) {\n        return evt.pointerId;\n      }\n\n      return -1;\n    },\n\n    /**\n     * Determines if an event has the id of the event that is considered main\n     * @private\n     * @param {evt} event Event object\n     */\n    _isMainEvent: function(evt) {\n      if (evt.isPrimary === true) {\n        return true;\n      }\n      if (evt.isPrimary === false) {\n        return false;\n      }\n      if (evt.type === 'touchend' && evt.touches.length === 0) {\n        return true;\n      }\n      if (evt.changedTouches) {\n        return evt.changedTouches[0].identifier === this.mainTouchId;\n      }\n      return true;\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onTouchStart: function(e) {\n      e.preventDefault();\n      if (this.mainTouchId === null) {\n        this.mainTouchId = this.getPointerId(e);\n      }\n      this.__onMouseDown(e);\n      this._resetTransformEventData();\n      var canvasElement = this.upperCanvasEl,\n          eventTypePrefix = this._getEventPrefix();\n      addListener(fabric.document, 'touchend', this._onTouchEnd, addEventOptions);\n      addListener(fabric.document, 'touchmove', this._onMouseMove, addEventOptions);\n      // Unbind mousedown to prevent double triggers from touch devices\n      removeListener(canvasElement, eventTypePrefix + 'down', this._onMouseDown);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onMouseDown: function (e) {\n      this.__onMouseDown(e);\n      this._resetTransformEventData();\n      var canvasElement = this.upperCanvasEl,\n          eventTypePrefix = this._getEventPrefix();\n      removeListener(canvasElement, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n      addListener(fabric.document, eventTypePrefix + 'up', this._onMouseUp);\n      addListener(fabric.document, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onTouchEnd: function(e) {\n      if (e.touches.length > 0) {\n        // if there are still touches stop here\n        return;\n      }\n      this.__onMouseUp(e);\n      this._resetTransformEventData();\n      this.mainTouchId = null;\n      var eventTypePrefix = this._getEventPrefix();\n      removeListener(fabric.document, 'touchend', this._onTouchEnd, addEventOptions);\n      removeListener(fabric.document, 'touchmove', this._onMouseMove, addEventOptions);\n      var _this = this;\n      if (this._willAddMouseDown) {\n        clearTimeout(this._willAddMouseDown);\n      }\n      this._willAddMouseDown = setTimeout(function() {\n        // Wait 400ms before rebinding mousedown to prevent double triggers\n        // from touch devices\n        addListener(_this.upperCanvasEl, eventTypePrefix + 'down', _this._onMouseDown);\n        _this._willAddMouseDown = 0;\n      }, 400);\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mouseup\n     */\n    _onMouseUp: function (e) {\n      this.__onMouseUp(e);\n      this._resetTransformEventData();\n      var canvasElement = this.upperCanvasEl,\n          eventTypePrefix = this._getEventPrefix();\n      if (this._isMainEvent(e)) {\n        removeListener(fabric.document, eventTypePrefix + 'up', this._onMouseUp);\n        removeListener(fabric.document, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n        addListener(canvasElement, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousemove\n     */\n    _onMouseMove: function (e) {\n      !this.allowTouchScrolling && e.preventDefault && e.preventDefault();\n      this.__onMouseMove(e);\n    },\n\n    /**\n     * @private\n     */\n    _onResize: function () {\n      this.calcOffset();\n    },\n\n    /**\n     * Decides whether the canvas should be redrawn in mouseup and mousedown events.\n     * @private\n     * @param {Object} target\n     */\n    _shouldRender: function(target) {\n      var activeObject = this._activeObject;\n\n      if (\n        !!activeObject !== !!target ||\n        (activeObject && target && (activeObject !== target))\n      ) {\n        // this covers: switch of target, from target to no target, selection of target\n        // multiSelection with key and mouse\n        return true;\n      }\n      else if (activeObject && activeObject.isEditing) {\n        // if we mouse up/down over a editing textbox a cursor change,\n        // there is no need to re render\n        return false;\n      }\n      return false;\n    },\n\n    /**\n     * Method that defines the actions when mouse is released on canvas.\n     * The method resets the currentTransform parameters, store the image corner\n     * position in the image object and render the canvas on top.\n     * @private\n     * @param {Event} e Event object fired on mouseup\n     */\n    __onMouseUp: function (e) {\n      var target, transform = this._currentTransform,\n          groupSelector = this._groupSelector, shouldRender = false,\n          isClick = (!groupSelector || (groupSelector.left === 0 && groupSelector.top === 0));\n      this._cacheTransformEventData(e);\n      target = this._target;\n      this._handleEvent(e, 'up:before');\n      // if right/middle click just fire events and return\n      // target undefined will make the _handleEvent search the target\n      if (checkClick(e, RIGHT_CLICK)) {\n        if (this.fireRightClick) {\n          this._handleEvent(e, 'up', RIGHT_CLICK, isClick);\n        }\n        return;\n      }\n\n      if (checkClick(e, MIDDLE_CLICK)) {\n        if (this.fireMiddleClick) {\n          this._handleEvent(e, 'up', MIDDLE_CLICK, isClick);\n        }\n        this._resetTransformEventData();\n        return;\n      }\n\n      if (this.isDrawingMode && this._isCurrentlyDrawing) {\n        this._onMouseUpInDrawingMode(e);\n        return;\n      }\n\n      if (!this._isMainEvent(e)) {\n        return;\n      }\n      if (transform) {\n        this._finalizeCurrentTransform(e);\n        shouldRender = transform.actionPerformed;\n      }\n      if (!isClick) {\n        var targetWasActive = target === this._activeObject;\n        this._maybeGroupObjects(e);\n        if (!shouldRender) {\n          shouldRender = (\n            this._shouldRender(target) ||\n            (!targetWasActive && target === this._activeObject)\n          );\n        }\n      }\n      var corner, pointer;\n      if (target) {\n        corner = target._findTargetCorner(\n          this.getPointer(e, true),\n          fabric.util.isTouchEvent(e)\n        );\n        if (target.selectable && target !== this._activeObject && target.activeOn === 'up') {\n          this.setActiveObject(target, e);\n          shouldRender = true;\n        }\n        else {\n          var control = target.controls[corner],\n              mouseUpHandler = control && control.getMouseUpHandler(e, target, control);\n          if (mouseUpHandler) {\n            pointer = this.getPointer(e);\n            mouseUpHandler(e, transform, pointer.x, pointer.y);\n          }\n        }\n        target.isMoving = false;\n      }\n      // if we are ending up a transform on a different control or a new object\n      // fire the original mouse up from the corner that started the transform\n      if (transform && (transform.target !== target || transform.corner !== corner)) {\n        var originalControl = transform.target && transform.target.controls[transform.corner],\n            originalMouseUpHandler = originalControl && originalControl.getMouseUpHandler(e, target, control);\n        pointer = pointer || this.getPointer(e);\n        originalMouseUpHandler && originalMouseUpHandler(e, transform, pointer.x, pointer.y);\n      }\n      this._setCursorFromEvent(e, target);\n      this._handleEvent(e, 'up', LEFT_CLICK, isClick);\n      this._groupSelector = null;\n      this._currentTransform = null;\n      // reset the target information about which corner is selected\n      target && (target.__corner = 0);\n      if (shouldRender) {\n        this.requestRenderAll();\n      }\n      else if (!isClick) {\n        this.renderTop();\n      }\n    },\n\n    /**\n     * @private\n     * Handle event firing for target and subtargets\n     * @param {Event} e event from mouse\n     * @param {String} eventType event to fire (up, down or move)\n     * @return {Fabric.Object} target return the the target found, for internal reasons.\n     */\n    _simpleEventHandler: function(eventType, e) {\n      var target = this.findTarget(e),\n          targets = this.targets,\n          options = {\n            e: e,\n            target: target,\n            subTargets: targets,\n          };\n      this.fire(eventType, options);\n      target && target.fire(eventType, options);\n      if (!targets) {\n        return target;\n      }\n      for (var i = 0; i < targets.length; i++) {\n        targets[i].fire(eventType, options);\n      }\n      return target;\n    },\n\n    /**\n     * @private\n     * Handle event firing for target and subtargets\n     * @param {Event} e event from mouse\n     * @param {String} eventType event to fire (up, down or move)\n     * @param {fabric.Object} targetObj receiving event\n     * @param {Number} [button] button used in the event 1 = left, 2 = middle, 3 = right\n     * @param {Boolean} isClick for left button only, indicates that the mouse up happened without move.\n     */\n    _handleEvent: function(e, eventType, button, isClick) {\n      var target = this._target,\n          targets = this.targets || [],\n          options = {\n            e: e,\n            target: target,\n            subTargets: targets,\n            button: button || LEFT_CLICK,\n            isClick: isClick || false,\n            pointer: this._pointer,\n            absolutePointer: this._absolutePointer,\n            transform: this._currentTransform\n          };\n      if (eventType === 'up') {\n        options.currentTarget = this.findTarget(e);\n        options.currentSubTargets = this.targets;\n      }\n      this.fire('mouse:' + eventType, options);\n      target && target.fire('mouse' + eventType, options);\n      for (var i = 0; i < targets.length; i++) {\n        targets[i].fire('mouse' + eventType, options);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e send the mouse event that generate the finalize down, so it can be used in the event\n     */\n    _finalizeCurrentTransform: function(e) {\n\n      var transform = this._currentTransform,\n          target = transform.target,\n          options = {\n            e: e,\n            target: target,\n            transform: transform,\n            action: transform.action,\n          };\n\n      if (target._scaling) {\n        target._scaling = false;\n      }\n\n      target.setCoords();\n\n      if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) {\n        this._fire('modified', options);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    _onMouseDownInDrawingMode: function(e) {\n      this._isCurrentlyDrawing = true;\n      if (this.getActiveObject()) {\n        this.discardActiveObject(e).requestRenderAll();\n      }\n      var pointer = this.getPointer(e);\n      this.freeDrawingBrush.onMouseDown(pointer, { e: e, pointer: pointer });\n      this._handleEvent(e, 'down');\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mousemove\n     */\n    _onMouseMoveInDrawingMode: function(e) {\n      if (this._isCurrentlyDrawing) {\n        var pointer = this.getPointer(e);\n        this.freeDrawingBrush.onMouseMove(pointer, { e: e, pointer: pointer });\n      }\n      this.setCursor(this.freeDrawingCursor);\n      this._handleEvent(e, 'move');\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object fired on mouseup\n     */\n    _onMouseUpInDrawingMode: function(e) {\n      var pointer = this.getPointer(e);\n      this._isCurrentlyDrawing = this.freeDrawingBrush.onMouseUp({ e: e, pointer: pointer });\n      this._handleEvent(e, 'up');\n    },\n\n    /**\n     * Method that defines the actions when mouse is clicked on canvas.\n     * The method inits the currentTransform parameters and renders all the\n     * canvas so the current image can be placed on the top canvas and the rest\n     * in on the container one.\n     * @private\n     * @param {Event} e Event object fired on mousedown\n     */\n    __onMouseDown: function (e) {\n      this._cacheTransformEventData(e);\n      this._handleEvent(e, 'down:before');\n      var target = this._target;\n      // if right click just fire events\n      if (checkClick(e, RIGHT_CLICK)) {\n        if (this.fireRightClick) {\n          this._handleEvent(e, 'down', RIGHT_CLICK);\n        }\n        return;\n      }\n\n      if (checkClick(e, MIDDLE_CLICK)) {\n        if (this.fireMiddleClick) {\n          this._handleEvent(e, 'down', MIDDLE_CLICK);\n        }\n        return;\n      }\n\n      if (this.isDrawingMode) {\n        this._onMouseDownInDrawingMode(e);\n        return;\n      }\n\n      if (!this._isMainEvent(e)) {\n        return;\n      }\n\n      // ignore if some object is being transformed at this moment\n      if (this._currentTransform) {\n        return;\n      }\n\n      var pointer = this._pointer;\n      // save pointer for check in __onMouseUp event\n      this._previousPointer = pointer;\n      var shouldRender = this._shouldRender(target),\n          shouldGroup = this._shouldGroup(e, target);\n      if (this._shouldClearSelection(e, target)) {\n        this.discardActiveObject(e);\n      }\n      else if (shouldGroup) {\n        this._handleGrouping(e, target);\n        target = this._activeObject;\n      }\n\n      if (this.selection && (!target ||\n        (!target.selectable && !target.isEditing && target !== this._activeObject))) {\n        this._groupSelector = {\n          ex: this._absolutePointer.x,\n          ey: this._absolutePointer.y,\n          top: 0,\n          left: 0\n        };\n      }\n\n      if (target) {\n        var alreadySelected = target === this._activeObject;\n        if (target.selectable && target.activeOn === 'down') {\n          this.setActiveObject(target, e);\n        }\n        var corner = target._findTargetCorner(\n          this.getPointer(e, true),\n          fabric.util.isTouchEvent(e)\n        );\n        target.__corner = corner;\n        if (target === this._activeObject && (corner || !shouldGroup)) {\n          this._setupCurrentTransform(e, target, alreadySelected);\n          var control = target.controls[corner],\n              pointer = this.getPointer(e),\n              mouseDownHandler = control && control.getMouseDownHandler(e, target, control);\n          if (mouseDownHandler) {\n            mouseDownHandler(e, this._currentTransform, pointer.x, pointer.y);\n          }\n        }\n      }\n      this._handleEvent(e, 'down');\n      // we must renderAll so that we update the visuals\n      (shouldRender || shouldGroup) && this.requestRenderAll();\n    },\n\n    /**\n     * reset cache form common information needed during event processing\n     * @private\n     */\n    _resetTransformEventData: function() {\n      this._target = null;\n      this._pointer = null;\n      this._absolutePointer = null;\n    },\n\n    /**\n     * Cache common information needed during event processing\n     * @private\n     * @param {Event} e Event object fired on event\n     */\n    _cacheTransformEventData: function(e) {\n      // reset in order to avoid stale caching\n      this._resetTransformEventData();\n      this._pointer = this.getPointer(e, true);\n      this._absolutePointer = this.restorePointerVpt(this._pointer);\n      this._target = this._currentTransform ? this._currentTransform.target : this.findTarget(e) || null;\n    },\n\n    /**\n     * @private\n     */\n    _beforeTransform: function(e) {\n      var t = this._currentTransform;\n      this.stateful && t.target.saveState();\n      this.fire('before:transform', {\n        e: e,\n        transform: t,\n      });\n    },\n\n    /**\n     * Method that defines the actions when mouse is hovering the canvas.\n     * The currentTransform parameter will define whether the user is rotating/scaling/translating\n     * an image or neither of them (only hovering). A group selection is also possible and would cancel\n     * all any other type of action.\n     * In case of an image transformation only the top canvas will be rendered.\n     * @private\n     * @param {Event} e Event object fired on mousemove\n     */\n    __onMouseMove: function (e) {\n      this._handleEvent(e, 'move:before');\n      this._cacheTransformEventData(e);\n      var target, pointer;\n\n      if (this.isDrawingMode) {\n        this._onMouseMoveInDrawingMode(e);\n        return;\n      }\n\n      if (!this._isMainEvent(e)) {\n        return;\n      }\n\n      var groupSelector = this._groupSelector;\n\n      // We initially clicked in an empty area, so we draw a box for multiple selection\n      if (groupSelector) {\n        pointer = this._absolutePointer;\n\n        groupSelector.left = pointer.x - groupSelector.ex;\n        groupSelector.top = pointer.y - groupSelector.ey;\n\n        this.renderTop();\n      }\n      else if (!this._currentTransform) {\n        target = this.findTarget(e) || null;\n        this._setCursorFromEvent(e, target);\n        this._fireOverOutEvents(target, e);\n      }\n      else {\n        this._transformObject(e);\n      }\n      this._handleEvent(e, 'move');\n      this._resetTransformEventData();\n    },\n\n    /**\n     * Manage the mouseout, mouseover events for the fabric object on the canvas\n     * @param {Fabric.Object} target the target where the target from the mousemove event\n     * @param {Event} e Event object fired on mousemove\n     * @private\n     */\n    _fireOverOutEvents: function(target, e) {\n      var _hoveredTarget = this._hoveredTarget,\n          _hoveredTargets = this._hoveredTargets, targets = this.targets,\n          length = Math.max(_hoveredTargets.length, targets.length);\n\n      this.fireSyntheticInOutEvents(target, e, {\n        oldTarget: _hoveredTarget,\n        evtOut: 'mouseout',\n        canvasEvtOut: 'mouse:out',\n        evtIn: 'mouseover',\n        canvasEvtIn: 'mouse:over',\n      });\n      for (var i = 0; i < length; i++){\n        this.fireSyntheticInOutEvents(targets[i], e, {\n          oldTarget: _hoveredTargets[i],\n          evtOut: 'mouseout',\n          evtIn: 'mouseover',\n        });\n      }\n      this._hoveredTarget = target;\n      this._hoveredTargets = this.targets.concat();\n    },\n\n    /**\n     * Manage the dragEnter, dragLeave events for the fabric objects on the canvas\n     * @param {Fabric.Object} target the target where the target from the onDrag event\n     * @param {Event} e Event object fired on ondrag\n     * @private\n     */\n    _fireEnterLeaveEvents: function(target, e) {\n      var _draggedoverTarget = this._draggedoverTarget,\n          _hoveredTargets = this._hoveredTargets, targets = this.targets,\n          length = Math.max(_hoveredTargets.length, targets.length);\n\n      this.fireSyntheticInOutEvents(target, e, {\n        oldTarget: _draggedoverTarget,\n        evtOut: 'dragleave',\n        evtIn: 'dragenter',\n      });\n      for (var i = 0; i < length; i++) {\n        this.fireSyntheticInOutEvents(targets[i], e, {\n          oldTarget: _hoveredTargets[i],\n          evtOut: 'dragleave',\n          evtIn: 'dragenter',\n        });\n      }\n      this._draggedoverTarget = target;\n    },\n\n    /**\n     * Manage the synthetic in/out events for the fabric objects on the canvas\n     * @param {Fabric.Object} target the target where the target from the supported events\n     * @param {Event} e Event object fired\n     * @param {Object} config configuration for the function to work\n     * @param {String} config.targetName property on the canvas where the old target is stored\n     * @param {String} [config.canvasEvtOut] name of the event to fire at canvas level for out\n     * @param {String} config.evtOut name of the event to fire for out\n     * @param {String} [config.canvasEvtIn] name of the event to fire at canvas level for in\n     * @param {String} config.evtIn name of the event to fire for in\n     * @private\n     */\n    fireSyntheticInOutEvents: function(target, e, config) {\n      var inOpt, outOpt, oldTarget = config.oldTarget, outFires, inFires,\n          targetChanged = oldTarget !== target, canvasEvtIn = config.canvasEvtIn, canvasEvtOut = config.canvasEvtOut;\n      if (targetChanged) {\n        inOpt = { e: e, target: target, previousTarget: oldTarget };\n        outOpt = { e: e, target: oldTarget, nextTarget: target };\n      }\n      inFires = target && targetChanged;\n      outFires = oldTarget && targetChanged;\n      if (outFires) {\n        canvasEvtOut && this.fire(canvasEvtOut, outOpt);\n        oldTarget.fire(config.evtOut, outOpt);\n      }\n      if (inFires) {\n        canvasEvtIn && this.fire(canvasEvtIn, inOpt);\n        target.fire(config.evtIn, inOpt);\n      }\n    },\n\n    /**\n     * Method that defines actions when an Event Mouse Wheel\n     * @param {Event} e Event object fired on mouseup\n     */\n    __onMouseWheel: function(e) {\n      this._cacheTransformEventData(e);\n      this._handleEvent(e, 'wheel');\n      this._resetTransformEventData();\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event fired on mousemove\n     */\n    _transformObject: function(e) {\n      var pointer = this.getPointer(e),\n          transform = this._currentTransform;\n\n      transform.reset = false;\n      transform.shiftKey = e.shiftKey;\n      transform.altKey = e[this.centeredKey];\n\n      this._performTransformAction(e, transform, pointer);\n      transform.actionPerformed && this.requestRenderAll();\n    },\n\n    /**\n     * @private\n     */\n    _performTransformAction: function(e, transform, pointer) {\n      var x = pointer.x,\n          y = pointer.y,\n          action = transform.action,\n          actionPerformed = false,\n          actionHandler = transform.actionHandler;\n          // this object could be created from the function in the control handlers\n\n\n      if (actionHandler) {\n        actionPerformed = actionHandler(e, transform, x, y);\n      }\n      if (action === 'drag' && actionPerformed) {\n        transform.target.isMoving = true;\n        this.setCursor(transform.target.moveCursor || this.moveCursor);\n      }\n      transform.actionPerformed = transform.actionPerformed || actionPerformed;\n    },\n\n    /**\n     * @private\n     */\n    _fire: fabric.controlsUtils.fireEvent,\n\n    /**\n     * Sets the cursor depending on where the canvas is being hovered.\n     * Note: very buggy in Opera\n     * @param {Event} e Event object\n     * @param {Object} target Object that the mouse is hovering, if so.\n     */\n    _setCursorFromEvent: function (e, target) {\n      if (!target) {\n        this.setCursor(this.defaultCursor);\n        return false;\n      }\n      var hoverCursor = target.hoverCursor || this.hoverCursor,\n          activeSelection = this._activeObject && this._activeObject.type === 'activeSelection' ?\n            this._activeObject : null,\n          // only show proper corner when group selection is not active\n          corner = (!activeSelection || !activeSelection.contains(target))\n          // here we call findTargetCorner always with undefined for the touch parameter.\n          // we assume that if you are using a cursor you do not need to interact with\n          // the bigger touch area.\n                    && target._findTargetCorner(this.getPointer(e, true));\n\n      if (!corner) {\n        if (target.subTargetCheck){\n          // hoverCursor should come from top-most subTarget,\n          // so we walk the array backwards\n          this.targets.concat().reverse().map(function(_target){\n            hoverCursor = _target.hoverCursor || hoverCursor;\n          });\n        }\n        this.setCursor(hoverCursor);\n      }\n      else {\n        this.setCursor(this.getCornerCursor(corner, target, e));\n      }\n    },\n\n    /**\n     * @private\n     */\n    getCornerCursor: function(corner, target, e) {\n      var control = target.controls[corner];\n      return control.cursorStyleHandler(e, control, target);\n    }\n  });\n})();\n\n\n(function() {\n\n  var min = Math.min,\n      max = Math.max;\n\n  fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     * @return {Boolean}\n     */\n    _shouldGroup: function(e, target) {\n      var activeObject = this._activeObject;\n      return activeObject && this._isSelectionKeyPressed(e) && target && target.selectable && this.selection &&\n            (activeObject !== target || activeObject.type === 'activeSelection') && !target.onSelect({ e: e });\n    },\n\n    /**\n     * @private\n     * @param {Event} e Event object\n     * @param {fabric.Object} target\n     */\n    _handleGrouping: function (e, target) {\n      var activeObject = this._activeObject;\n      // avoid multi select when shift click on a corner\n      if (activeObject.__corner) {\n        return;\n      }\n      if (target === activeObject) {\n        // if it's a group, find target again, using activeGroup objects\n        target = this.findTarget(e, true);\n        // if even object is not found or we are on activeObjectCorner, bail out\n        if (!target || !target.selectable) {\n          return;\n        }\n      }\n      if (activeObject && activeObject.type === 'activeSelection') {\n        this._updateActiveSelection(target, e);\n      }\n      else {\n        this._createActiveSelection(target, e);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _updateActiveSelection: function(target, e) {\n      var activeSelection = this._activeObject,\n          currentActiveObjects = activeSelection._objects.slice(0);\n      if (activeSelection.contains(target)) {\n        activeSelection.removeWithUpdate(target);\n        this._hoveredTarget = target;\n        this._hoveredTargets = this.targets.concat();\n        if (activeSelection.size() === 1) {\n          // activate last remaining object\n          this._setActiveObject(activeSelection.item(0), e);\n        }\n      }\n      else {\n        activeSelection.addWithUpdate(target);\n        this._hoveredTarget = activeSelection;\n        this._hoveredTargets = this.targets.concat();\n      }\n      this._fireSelectionEvents(currentActiveObjects, e);\n    },\n\n    /**\n     * @private\n     */\n    _createActiveSelection: function(target, e) {\n      var currentActives = this.getActiveObjects(), group = this._createGroup(target);\n      this._hoveredTarget = group;\n      // ISSUE 4115: should we consider subTargets here?\n      // this._hoveredTargets = [];\n      // this._hoveredTargets = this.targets.concat();\n      this._setActiveObject(group, e);\n      this._fireSelectionEvents(currentActives, e);\n    },\n\n    /**\n     * @private\n     * @param {Object} target\n     */\n    _createGroup: function(target) {\n      var objects = this._objects,\n          isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target),\n          groupObjects = isActiveLower\n            ? [this._activeObject, target]\n            : [target, this._activeObject];\n      this._activeObject.isEditing && this._activeObject.exitEditing();\n      return new fabric.ActiveSelection(groupObjects, {\n        canvas: this\n      });\n    },\n\n    /**\n     * @private\n     * @param {Event} e mouse event\n     */\n    _groupSelectedObjects: function (e) {\n\n      var group = this._collectObjects(e),\n          aGroup;\n\n      // do not create group for 1 element only\n      if (group.length === 1) {\n        this.setActiveObject(group[0], e);\n      }\n      else if (group.length > 1) {\n        aGroup = new fabric.ActiveSelection(group.reverse(), {\n          canvas: this\n        });\n        this.setActiveObject(aGroup, e);\n      }\n    },\n\n    /**\n     * @private\n     */\n    _collectObjects: function(e) {\n      var group = [],\n          currentObject,\n          x1 = this._groupSelector.ex,\n          y1 = this._groupSelector.ey,\n          x2 = x1 + this._groupSelector.left,\n          y2 = y1 + this._groupSelector.top,\n          selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),\n          selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)),\n          allowIntersect = !this.selectionFullyContained,\n          isClick = x1 === x2 && y1 === y2;\n      // we iterate reverse order to collect top first in case of click.\n      for (var i = this._objects.length; i--; ) {\n        currentObject = this._objects[i];\n\n        if (!currentObject || !currentObject.selectable || !currentObject.visible) {\n          continue;\n        }\n\n        if ((allowIntersect && currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2, true)) ||\n            currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2, true) ||\n            (allowIntersect && currentObject.containsPoint(selectionX1Y1, null, true)) ||\n            (allowIntersect && currentObject.containsPoint(selectionX2Y2, null, true))\n        ) {\n          group.push(currentObject);\n          // only add one object if it's a click\n          if (isClick) {\n            break;\n          }\n        }\n      }\n\n      if (group.length > 1) {\n        group = group.filter(function(object) {\n          return !object.onSelect({ e: e });\n        });\n      }\n\n      return group;\n    },\n\n    /**\n     * @private\n     */\n    _maybeGroupObjects: function(e) {\n      if (this.selection && this._groupSelector) {\n        this._groupSelectedObjects(e);\n      }\n      this.setCursor(this.defaultCursor);\n      // clear selection and current transformation\n      this._groupSelector = null;\n    }\n  });\n\n})();\n\n\n(function () {\n  fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n    /**\n     * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately\n     * @param {Object} [options] Options object\n     * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n     * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n     * @param {Number} [options.multiplier=1] Multiplier to scale by, to have consistent\n     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n     * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 2.0.0\n     * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n     * @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}\n     * @example <caption>Generate jpeg dataURL with lower quality</caption>\n     * var dataURL = canvas.toDataURL({\n     *   format: 'jpeg',\n     *   quality: 0.8\n     * });\n     * @example <caption>Generate cropped png dataURL (clipping of canvas)</caption>\n     * var dataURL = canvas.toDataURL({\n     *   format: 'png',\n     *   left: 100,\n     *   top: 100,\n     *   width: 200,\n     *   height: 200\n     * });\n     * @example <caption>Generate double scaled png dataURL</caption>\n     * var dataURL = canvas.toDataURL({\n     *   format: 'png',\n     *   multiplier: 2\n     * });\n     */\n    toDataURL: function (options) {\n      options || (options = { });\n\n      var format = options.format || 'png',\n          quality = options.quality || 1,\n          multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? this.getRetinaScaling() : 1),\n          canvasEl = this.toCanvasElement(multiplier, options);\n      return fabric.util.toDataURL(canvasEl, format, quality);\n    },\n\n    /**\n     * Create a new HTMLCanvas element painted with the current canvas content.\n     * No need to resize the actual one or repaint it.\n     * Will transfer object ownership to a new canvas, paint it, and set everything back.\n     * This is an intermediary step used to get to a dataUrl but also it is useful to\n     * create quick image copies of a canvas without passing for the dataUrl string\n     * @param {Number} [multiplier] a zoom factor.\n     * @param {Object} [cropping] Cropping informations\n     * @param {Number} [cropping.left] Cropping left offset.\n     * @param {Number} [cropping.top] Cropping top offset.\n     * @param {Number} [cropping.width] Cropping width.\n     * @param {Number} [cropping.height] Cropping height.\n     */\n    toCanvasElement: function(multiplier, cropping) {\n      multiplier = multiplier || 1;\n      cropping = cropping || { };\n      var scaledWidth = (cropping.width || this.width) * multiplier,\n          scaledHeight = (cropping.height || this.height) * multiplier,\n          zoom = this.getZoom(),\n          originalWidth = this.width,\n          originalHeight = this.height,\n          newZoom = zoom * multiplier,\n          vp = this.viewportTransform,\n          translateX = (vp[4] - (cropping.left || 0)) * multiplier,\n          translateY = (vp[5] - (cropping.top || 0)) * multiplier,\n          originalInteractive = this.interactive,\n          newVp = [newZoom, 0, 0, newZoom, translateX, translateY],\n          originalRetina = this.enableRetinaScaling,\n          canvasEl = fabric.util.createCanvasElement(),\n          originalContextTop = this.contextTop;\n      canvasEl.width = scaledWidth;\n      canvasEl.height = scaledHeight;\n      this.contextTop = null;\n      this.enableRetinaScaling = false;\n      this.interactive = false;\n      this.viewportTransform = newVp;\n      this.width = scaledWidth;\n      this.height = scaledHeight;\n      this.calcViewportBoundaries();\n      this.renderCanvas(canvasEl.getContext('2d'), this._objects);\n      this.viewportTransform = vp;\n      this.width = originalWidth;\n      this.height = originalHeight;\n      this.calcViewportBoundaries();\n      this.interactive = originalInteractive;\n      this.enableRetinaScaling = originalRetina;\n      this.contextTop = originalContextTop;\n      return canvasEl;\n    },\n  });\n\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n  /**\n   * Populates canvas with data from the specified JSON.\n   * JSON format must conform to the one of {@link fabric.Canvas#toJSON}\n   * @param {String|Object} json JSON string or object\n   * @param {Function} callback Callback, invoked when json is parsed\n   *                            and corresponding objects (e.g: {@link fabric.Image})\n   *                            are initialized\n   * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.\n   * @return {fabric.Canvas} instance\n   * @chainable\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization}\n   * @see {@link http://jsfiddle.net/fabricjs/fmgXt/|jsFiddle demo}\n   * @example <caption>loadFromJSON</caption>\n   * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));\n   * @example <caption>loadFromJSON with reviver</caption>\n   * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) {\n   *   // `o` = json object\n   *   // `object` = fabric.Object instance\n   *   // ... do some stuff ...\n   * });\n   */\n  loadFromJSON: function (json, callback, reviver) {\n    if (!json) {\n      return;\n    }\n\n    // serialize if it wasn't already\n    var serialized = (typeof json === 'string')\n      ? JSON.parse(json)\n      : fabric.util.object.clone(json);\n\n    var _this = this,\n        clipPath = serialized.clipPath,\n        renderOnAddRemove = this.renderOnAddRemove;\n\n    this.renderOnAddRemove = false;\n\n    delete serialized.clipPath;\n\n    this._enlivenObjects(serialized.objects, function (enlivenedObjects) {\n      _this.clear();\n      _this._setBgOverlay(serialized, function () {\n        if (clipPath) {\n          _this._enlivenObjects([clipPath], function (enlivenedCanvasClip) {\n            _this.clipPath = enlivenedCanvasClip[0];\n            _this.__setupCanvas.call(_this, serialized, enlivenedObjects, renderOnAddRemove, callback);\n          });\n        }\n        else {\n          _this.__setupCanvas.call(_this, serialized, enlivenedObjects, renderOnAddRemove, callback);\n        }\n      });\n    }, reviver);\n    return this;\n  },\n\n  /**\n   * @private\n   * @param {Object} serialized Object with background and overlay information\n   * @param {Array} restored canvas objects\n   * @param {Function} cached renderOnAddRemove callback\n   * @param {Function} callback Invoked after all background and overlay images/patterns loaded\n   */\n  __setupCanvas: function(serialized, enlivenedObjects, renderOnAddRemove, callback) {\n    var _this = this;\n    enlivenedObjects.forEach(function(obj, index) {\n      // we splice the array just in case some custom classes restored from JSON\n      // will add more object to canvas at canvas init.\n      _this.insertAt(obj, index);\n    });\n    this.renderOnAddRemove = renderOnAddRemove;\n    // remove parts i cannot set as options\n    delete serialized.objects;\n    delete serialized.backgroundImage;\n    delete serialized.overlayImage;\n    delete serialized.background;\n    delete serialized.overlay;\n    // this._initOptions does too many things to just\n    // call it. Normally loading an Object from JSON\n    // create the Object instance. Here the Canvas is\n    // already an instance and we are just loading things over it\n    this._setOptions(serialized);\n    this.renderAll();\n    callback && callback();\n  },\n\n  /**\n   * @private\n   * @param {Object} serialized Object with background and overlay information\n   * @param {Function} callback Invoked after all background and overlay images/patterns loaded\n   */\n  _setBgOverlay: function(serialized, callback) {\n    var loaded = {\n      backgroundColor: false,\n      overlayColor: false,\n      backgroundImage: false,\n      overlayImage: false\n    };\n\n    if (!serialized.backgroundImage && !serialized.overlayImage && !serialized.background && !serialized.overlay) {\n      callback && callback();\n      return;\n    }\n\n    var cbIfLoaded = function () {\n      if (loaded.backgroundImage && loaded.overlayImage && loaded.backgroundColor && loaded.overlayColor) {\n        callback && callback();\n      }\n    };\n\n    this.__setBgOverlay('backgroundImage', serialized.backgroundImage, loaded, cbIfLoaded);\n    this.__setBgOverlay('overlayImage', serialized.overlayImage, loaded, cbIfLoaded);\n    this.__setBgOverlay('backgroundColor', serialized.background, loaded, cbIfLoaded);\n    this.__setBgOverlay('overlayColor', serialized.overlay, loaded, cbIfLoaded);\n  },\n\n  /**\n   * @private\n   * @param {String} property Property to set (backgroundImage, overlayImage, backgroundColor, overlayColor)\n   * @param {(Object|String)} value Value to set\n   * @param {Object} loaded Set loaded property to true if property is set\n   * @param {Object} callback Callback function to invoke after property is set\n   */\n  __setBgOverlay: function(property, value, loaded, callback) {\n    var _this = this;\n\n    if (!value) {\n      loaded[property] = true;\n      callback && callback();\n      return;\n    }\n\n    if (property === 'backgroundImage' || property === 'overlayImage') {\n      fabric.util.enlivenObjects([value], function(enlivedObject){\n        _this[property] = enlivedObject[0];\n        loaded[property] = true;\n        callback && callback();\n      });\n    }\n    else {\n      this['set' + fabric.util.string.capitalize(property, true)](value, function() {\n        loaded[property] = true;\n        callback && callback();\n      });\n    }\n  },\n\n  /**\n   * @private\n   * @param {Array} objects\n   * @param {Function} callback\n   * @param {Function} [reviver]\n   */\n  _enlivenObjects: function (objects, callback, reviver) {\n    if (!objects || objects.length === 0) {\n      callback && callback([]);\n      return;\n    }\n\n    fabric.util.enlivenObjects(objects, function(enlivenedObjects) {\n      callback && callback(enlivenedObjects);\n    }, null, reviver);\n  },\n\n  /**\n   * @private\n   * @param {String} format\n   * @param {Function} callback\n   */\n  _toDataURL: function (format, callback) {\n    this.clone(function (clone) {\n      callback(clone.toDataURL(format));\n    });\n  },\n\n  /**\n   * @private\n   * @param {String} format\n   * @param {Number} multiplier\n   * @param {Function} callback\n   */\n  _toDataURLWithMultiplier: function (format, multiplier, callback) {\n    this.clone(function (clone) {\n      callback(clone.toDataURLWithMultiplier(format, multiplier));\n    });\n  },\n\n  /**\n   * Clones canvas instance\n   * @param {Object} [callback] Receives cloned instance as a first argument\n   * @param {Array} [properties] Array of properties to include in the cloned canvas and children\n   */\n  clone: function (callback, properties) {\n    var data = JSON.stringify(this.toJSON(properties));\n    this.cloneWithoutData(function(clone) {\n      clone.loadFromJSON(data, function() {\n        callback && callback(clone);\n      });\n    });\n  },\n\n  /**\n   * Clones canvas instance without cloning existing data.\n   * This essentially copies canvas dimensions, clipping properties, etc.\n   * but leaves data empty (so that you can populate it with your own)\n   * @param {Object} [callback] Receives cloned instance as a first argument\n   */\n  cloneWithoutData: function(callback) {\n    var el = fabric.util.createCanvasElement();\n\n    el.width = this.width;\n    el.height = this.height;\n\n    var clone = new fabric.Canvas(el);\n    if (this.backgroundImage) {\n      clone.setBackgroundImage(this.backgroundImage.src, function() {\n        clone.renderAll();\n        callback && callback(clone);\n      });\n      clone.backgroundImageOpacity = this.backgroundImageOpacity;\n      clone.backgroundImageStretch = this.backgroundImageStretch;\n    }\n    else {\n      callback && callback(clone);\n    }\n  }\n});\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone,\n      toFixed = fabric.util.toFixed,\n      capitalize = fabric.util.string.capitalize,\n      degreesToRadians = fabric.util.degreesToRadians,\n      objectCaching = !fabric.isLikelyNode,\n      ALIASING_LIMIT = 2;\n\n  if (fabric.Object) {\n    return;\n  }\n\n  /**\n   * Root object class from which all 2d shape classes inherit from\n   * @class fabric.Object\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#objects}\n   * @see {@link fabric.Object#initialize} for constructor definition\n   *\n   * @fires added\n   * @fires removed\n   *\n   * @fires selected\n   * @fires deselected\n   * @fires modified\n   * @fires modified\n   * @fires moved\n   * @fires scaled\n   * @fires rotated\n   * @fires skewed\n   *\n   * @fires rotating\n   * @fires scaling\n   * @fires moving\n   * @fires skewing\n   *\n   * @fires mousedown\n   * @fires mouseup\n   * @fires mouseover\n   * @fires mouseout\n   * @fires mousewheel\n   * @fires mousedblclick\n   *\n   * @fires dragover\n   * @fires dragenter\n   * @fires dragleave\n   * @fires drop\n   */\n  fabric.Object = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Type of an object (rect, circle, path, etc.).\n     * Note that this property is meant to be read-only and not meant to be modified.\n     * If you modify, certain parts of Fabric (such as JSON loading) won't work correctly.\n     * @type String\n     * @default\n     */\n    type:                     'object',\n\n    /**\n     * Horizontal origin of transformation of an object (one of \"left\", \"right\", \"center\")\n     * See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups\n     * @type String\n     * @default\n     */\n    originX:                  'left',\n\n    /**\n     * Vertical origin of transformation of an object (one of \"top\", \"bottom\", \"center\")\n     * See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups\n     * @type String\n     * @default\n     */\n    originY:                  'top',\n\n    /**\n     * Top position of an object. Note that by default it's relative to object top. You can change this by setting originY={top/center/bottom}\n     * @type Number\n     * @default\n     */\n    top:                      0,\n\n    /**\n     * Left position of an object. Note that by default it's relative to object left. You can change this by setting originX={left/center/right}\n     * @type Number\n     * @default\n     */\n    left:                     0,\n\n    /**\n     * Object width\n     * @type Number\n     * @default\n     */\n    width:                    0,\n\n    /**\n     * Object height\n     * @type Number\n     * @default\n     */\n    height:                   0,\n\n    /**\n     * Object scale factor (horizontal)\n     * @type Number\n     * @default\n     */\n    scaleX:                   1,\n\n    /**\n     * Object scale factor (vertical)\n     * @type Number\n     * @default\n     */\n    scaleY:                   1,\n\n    /**\n     * When true, an object is rendered as flipped horizontally\n     * @type Boolean\n     * @default\n     */\n    flipX:                    false,\n\n    /**\n     * When true, an object is rendered as flipped vertically\n     * @type Boolean\n     * @default\n     */\n    flipY:                    false,\n\n    /**\n     * Opacity of an object\n     * @type Number\n     * @default\n     */\n    opacity:                  1,\n\n    /**\n     * Angle of rotation of an object (in degrees)\n     * @type Number\n     * @default\n     */\n    angle:                    0,\n\n    /**\n     * Angle of skew on x axes of an object (in degrees)\n     * @type Number\n     * @default\n     */\n    skewX:                    0,\n\n    /**\n     * Angle of skew on y axes of an object (in degrees)\n     * @type Number\n     * @default\n     */\n    skewY:                    0,\n\n    /**\n     * Size of object's controlling corners (in pixels)\n     * @type Number\n     * @default\n     */\n    cornerSize:               13,\n\n    /**\n     * Size of object's controlling corners when touch interaction is detected\n     * @type Number\n     * @default\n     */\n    touchCornerSize:               24,\n\n    /**\n     * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)\n     * @type Boolean\n     * @default\n     */\n    transparentCorners:       true,\n\n    /**\n     * Default cursor value used when hovering over this object on canvas\n     * @type String\n     * @default\n     */\n    hoverCursor:              null,\n\n    /**\n     * Default cursor value used when moving this object on canvas\n     * @type String\n     * @default\n     */\n    moveCursor:               null,\n\n    /**\n     * Padding between object and its controlling borders (in pixels)\n     * @type Number\n     * @default\n     */\n    padding:                  0,\n\n    /**\n     * Color of controlling borders of an object (when it's active)\n     * @type String\n     * @default\n     */\n    borderColor:              'rgb(178,204,255)',\n\n    /**\n     * Array specifying dash pattern of an object's borders (hasBorder must be true)\n     * @since 1.6.2\n     * @type Array\n     */\n    borderDashArray:          null,\n\n    /**\n     * Color of controlling corners of an object (when it's active)\n     * @type String\n     * @default\n     */\n    cornerColor:              'rgb(178,204,255)',\n\n    /**\n     * Color of controlling corners of an object (when it's active and transparentCorners false)\n     * @since 1.6.2\n     * @type String\n     * @default\n     */\n    cornerStrokeColor:        null,\n\n    /**\n     * Specify style of control, 'rect' or 'circle'\n     * @since 1.6.2\n     * @type String\n     */\n    cornerStyle:          'rect',\n\n    /**\n     * Array specifying dash pattern of an object's control (hasBorder must be true)\n     * @since 1.6.2\n     * @type Array\n     */\n    cornerDashArray:          null,\n\n    /**\n     * When true, this object will use center point as the origin of transformation\n     * when being scaled via the controls.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredScaling:          false,\n\n    /**\n     * When true, this object will use center point as the origin of transformation\n     * when being rotated via the controls.\n     * <b>Backwards incompatibility note:</b> This property replaces \"centerTransform\" (Boolean).\n     * @since 1.3.4\n     * @type Boolean\n     * @default\n     */\n    centeredRotation:         true,\n\n    /**\n     * Color of object's fill\n     * takes css colors https://www.w3.org/TR/css-color-3/\n     * @type String\n     * @default\n     */\n    fill:                     'rgb(0,0,0)',\n\n    /**\n     * Fill rule used to fill an object\n     * accepted values are nonzero, evenodd\n     * <b>Backwards incompatibility note:</b> This property was used for setting globalCompositeOperation until v1.4.12 (use `fabric.Object#globalCompositeOperation` instead)\n     * @type String\n     * @default\n     */\n    fillRule:                 'nonzero',\n\n    /**\n     * Composite rule used for canvas globalCompositeOperation\n     * @type String\n     * @default\n     */\n    globalCompositeOperation: 'source-over',\n\n    /**\n     * Background color of an object.\n     * takes css colors https://www.w3.org/TR/css-color-3/\n     * @type String\n     * @default\n     */\n    backgroundColor:          '',\n\n    /**\n     * Selection Background color of an object. colored layer behind the object when it is active.\n     * does not mix good with globalCompositeOperation methods.\n     * @type String\n     * @default\n     */\n    selectionBackgroundColor:          '',\n\n    /**\n     * When defined, an object is rendered via stroke and this property specifies its color\n     * takes css colors https://www.w3.org/TR/css-color-3/\n     * @type String\n     * @default\n     */\n    stroke:                   null,\n\n    /**\n     * Width of a stroke used to render this object\n     * @type Number\n     * @default\n     */\n    strokeWidth:              1,\n\n    /**\n     * Array specifying dash pattern of an object's stroke (stroke must be defined)\n     * @type Array\n     */\n    strokeDashArray:          null,\n\n    /**\n     * Line offset of an object's stroke\n     * @type Number\n     * @default\n     */\n    strokeDashOffset: 0,\n\n    /**\n     * Line endings style of an object's stroke (one of \"butt\", \"round\", \"square\")\n     * @type String\n     * @default\n     */\n    strokeLineCap:            'butt',\n\n    /**\n     * Corner style of an object's stroke (one of \"bevel\", \"round\", \"miter\")\n     * @type String\n     * @default\n     */\n    strokeLineJoin:           'miter',\n\n    /**\n     * Maximum miter length (used for strokeLineJoin = \"miter\") of an object's stroke\n     * @type Number\n     * @default\n     */\n    strokeMiterLimit:         4,\n\n    /**\n     * Shadow object representing shadow of this shape\n     * @type fabric.Shadow\n     * @default\n     */\n    shadow:                   null,\n\n    /**\n     * Opacity of object's controlling borders when object is active and moving\n     * @type Number\n     * @default\n     */\n    borderOpacityWhenMoving:  0.4,\n\n    /**\n     * Scale factor of object's controlling borders\n     * bigger number will make a thicker border\n     * border is 1, so this is basically a border thickness\n     * since there is no way to change the border itself.\n     * @type Number\n     * @default\n     */\n    borderScaleFactor:        1,\n\n    /**\n     * Minimum allowed scale value of an object\n     * @type Number\n     * @default\n     */\n    minScaleLimit:            0,\n\n    /**\n     * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).\n     * But events still fire on it.\n     * @type Boolean\n     * @default\n     */\n    selectable:               true,\n\n    /**\n     * When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4\n     * @type Boolean\n     * @default\n     */\n    evented:                  true,\n\n    /**\n     * When set to `false`, an object is not rendered on canvas\n     * @type Boolean\n     * @default\n     */\n    visible:                  true,\n\n    /**\n     * When set to `false`, object's controls are not displayed and can not be used to manipulate object\n     * @type Boolean\n     * @default\n     */\n    hasControls:              true,\n\n    /**\n     * When set to `false`, object's controlling borders are not rendered\n     * @type Boolean\n     * @default\n     */\n    hasBorders:               true,\n\n    /**\n     * When set to `true`, objects are \"found\" on canvas on per-pixel basis rather than according to bounding box\n     * @type Boolean\n     * @default\n     */\n    perPixelTargetFind:       false,\n\n    /**\n     * When `false`, default object's values are not included in its serialization\n     * @type Boolean\n     * @default\n     */\n    includeDefaultValues:     true,\n\n    /**\n     * When `true`, object horizontal movement is locked\n     * @type Boolean\n     * @default\n     */\n    lockMovementX:            false,\n\n    /**\n     * When `true`, object vertical movement is locked\n     * @type Boolean\n     * @default\n     */\n    lockMovementY:            false,\n\n    /**\n     * When `true`, object rotation is locked\n     * @type Boolean\n     * @default\n     */\n    lockRotation:             false,\n\n    /**\n     * When `true`, object horizontal scaling is locked\n     * @type Boolean\n     * @default\n     */\n    lockScalingX:             false,\n\n    /**\n     * When `true`, object vertical scaling is locked\n     * @type Boolean\n     * @default\n     */\n    lockScalingY:             false,\n\n    /**\n     * When `true`, object horizontal skewing is locked\n     * @type Boolean\n     * @default\n     */\n    lockSkewingX:             false,\n\n    /**\n     * When `true`, object vertical skewing is locked\n     * @type Boolean\n     * @default\n     */\n    lockSkewingY:             false,\n\n    /**\n     * When `true`, object cannot be flipped by scaling into negative values\n     * @type Boolean\n     * @default\n     */\n    lockScalingFlip:          false,\n\n    /**\n     * When `true`, object is not exported in OBJECT/JSON\n     * @since 1.6.3\n     * @type Boolean\n     * @default\n     */\n    excludeFromExport:        false,\n\n    /**\n     * When `true`, object is cached on an additional canvas.\n     * When `false`, object is not cached unless necessary ( clipPath )\n     * default to true\n     * @since 1.7.0\n     * @type Boolean\n     * @default true\n     */\n    objectCaching:            objectCaching,\n\n    /**\n     * When `true`, object properties are checked for cache invalidation. In some particular\n     * situation you may want this to be disabled ( spray brush, very big, groups)\n     * or if your application does not allow you to modify properties for groups child you want\n     * to disable it for groups.\n     * default to false\n     * since 1.7.0\n     * @type Boolean\n     * @default false\n     */\n    statefullCache:            false,\n\n    /**\n     * When `true`, cache does not get updated during scaling. The picture will get blocky if scaled\n     * too much and will be redrawn with correct details at the end of scaling.\n     * this setting is performance and application dependant.\n     * default to true\n     * since 1.7.0\n     * @type Boolean\n     * @default true\n     */\n    noScaleCache:              true,\n\n    /**\n     * When `false`, the stoke width will scale with the object.\n     * When `true`, the stroke will always match the exact pixel size entered for stroke width.\n     * this Property does not work on Text classes or drawing call that uses strokeText,fillText methods\n     * default to false\n     * @since 2.6.0\n     * @type Boolean\n     * @default false\n     * @type Boolean\n     * @default false\n     */\n    strokeUniform:              false,\n\n    /**\n     * When set to `true`, object's cache will be rerendered next render call.\n     * since 1.7.0\n     * @type Boolean\n     * @default true\n     */\n    dirty:                true,\n\n    /**\n     * keeps the value of the last hovered corner during mouse move.\n     * 0 is no corner, or 'mt', 'ml', 'mtr' etc..\n     * It should be private, but there is no harm in using it as\n     * a read-only property.\n     * @type number|string|any\n     * @default 0\n     */\n    __corner: 0,\n\n    /**\n     * Determines if the fill or the stroke is drawn first (one of \"fill\" or \"stroke\")\n     * @type String\n     * @default\n     */\n    paintFirst:           'fill',\n\n    /**\n     * When 'down', object is set to active on mousedown/touchstart\n     * When 'up', object is set to active on mouseup/touchend\n     * Experimental. Let's see if this breaks anything before supporting officially\n     * @private\n     * since 4.4.0\n     * @type String\n     * @default 'down'\n     */\n    activeOn:           'down',\n\n    /**\n     * List of properties to consider when checking if state\n     * of an object is changed (fabric.Object#hasStateChanged)\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: (\n      'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +\n      'stroke strokeWidth strokeDashArray strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit ' +\n      'angle opacity fill globalCompositeOperation shadow visible backgroundColor ' +\n      'skewX skewY fillRule paintFirst clipPath strokeUniform'\n    ).split(' '),\n\n    /**\n     * List of properties to consider when checking if cache needs refresh\n     * Those properties are checked by statefullCache ON ( or lazy mode if we want ) or from single\n     * calls to Object.set(key, value). If the key is in this list, the object is marked as dirty\n     * and refreshed at the next render\n     * @type Array\n     */\n    cacheProperties: (\n      'fill stroke strokeWidth strokeDashArray width height paintFirst strokeUniform' +\n      ' strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit backgroundColor clipPath'\n    ).split(' '),\n\n    /**\n     * List of properties to consider for animating colors.\n     * @type Array\n     */\n    colorProperties: (\n      'fill stroke backgroundColor'\n    ).split(' '),\n\n    /**\n     * a fabricObject that, without stroke define a clipping area with their shape. filled in black\n     * the clipPath object gets used when the object has rendered, and the context is placed in the center\n     * of the object cacheCanvas.\n     * If you want 0,0 of a clipPath to align with an object center, use clipPath.originX/Y to 'center'\n     * @type fabric.Object\n     */\n    clipPath: undefined,\n\n    /**\n     * Meaningful ONLY when the object is used as clipPath.\n     * if true, the clipPath will make the object clip to the outside of the clipPath\n     * since 2.4.0\n     * @type boolean\n     * @default false\n     */\n    inverted: false,\n\n    /**\n     * Meaningful ONLY when the object is used as clipPath.\n     * if true, the clipPath will have its top and left relative to canvas, and will\n     * not be influenced by the object transform. This will make the clipPath relative\n     * to the canvas, but clipping just a particular object.\n     * WARNING this is beta, this feature may change or be renamed.\n     * since 2.4.0\n     * @type boolean\n     * @default false\n     */\n    absolutePositioned: false,\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     */\n    initialize: function(options) {\n      if (options) {\n        this.setOptions(options);\n      }\n    },\n\n    /**\n     * Create a the canvas used to keep the cached copy of the object\n     * @private\n     */\n    _createCacheCanvas: function() {\n      this._cacheProperties = {};\n      this._cacheCanvas = fabric.util.createCanvasElement();\n      this._cacheContext = this._cacheCanvas.getContext('2d');\n      this._updateCacheCanvas();\n      // if canvas gets created, is empty, so dirty.\n      this.dirty = true;\n    },\n\n    /**\n     * Limit the cache dimensions so that X * Y do not cross fabric.perfLimitSizeTotal\n     * and each side do not cross fabric.cacheSideLimit\n     * those numbers are configurable so that you can get as much detail as you want\n     * making bargain with performances.\n     * @param {Object} dims\n     * @param {Object} dims.width width of canvas\n     * @param {Object} dims.height height of canvas\n     * @param {Object} dims.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @param {Object} dims.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     * @return {Object}.width width of canvas\n     * @return {Object}.height height of canvas\n     * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     */\n    _limitCacheSize: function(dims) {\n      var perfLimitSizeTotal = fabric.perfLimitSizeTotal,\n          width = dims.width, height = dims.height,\n          max = fabric.maxCacheSideLimit, min = fabric.minCacheSideLimit;\n      if (width <= max && height <= max && width * height <= perfLimitSizeTotal) {\n        if (width < min) {\n          dims.width = min;\n        }\n        if (height < min) {\n          dims.height = min;\n        }\n        return dims;\n      }\n      var ar = width / height, limitedDims = fabric.util.limitDimsByArea(ar, perfLimitSizeTotal),\n          capValue = fabric.util.capValue,\n          x = capValue(min, limitedDims.x, max),\n          y = capValue(min, limitedDims.y, max);\n      if (width > x) {\n        dims.zoomX /= width / x;\n        dims.width = x;\n        dims.capped = true;\n      }\n      if (height > y) {\n        dims.zoomY /= height / y;\n        dims.height = y;\n        dims.capped = true;\n      }\n      return dims;\n    },\n\n    /**\n     * Return the dimension and the zoom level needed to create a cache canvas\n     * big enough to host the object to be cached.\n     * @private\n     * @return {Object}.x width of object to be cached\n     * @return {Object}.y height of object to be cached\n     * @return {Object}.width width of canvas\n     * @return {Object}.height height of canvas\n     * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     */\n    _getCacheCanvasDimensions: function() {\n      var objectScale = this.getTotalObjectScaling(),\n          // caculate dimensions without skewing\n          dim = this._getTransformedDimensions(0, 0),\n          neededX = dim.x * objectScale.scaleX / this.scaleX,\n          neededY = dim.y * objectScale.scaleY / this.scaleY;\n      return {\n        // for sure this ALIASING_LIMIT is slightly creating problem\n        // in situation in which the cache canvas gets an upper limit\n        // also objectScale contains already scaleX and scaleY\n        width: Math.ceil(neededX + ALIASING_LIMIT),\n        height: Math.ceil(neededY + ALIASING_LIMIT),\n        zoomX: objectScale.scaleX,\n        zoomY: objectScale.scaleY,\n        x: neededX,\n        y: neededY\n      };\n    },\n\n    /**\n     * Update width and height of the canvas for cache\n     * returns true or false if canvas needed resize.\n     * @private\n     * @return {Boolean} true if the canvas has been resized\n     */\n    _updateCacheCanvas: function() {\n      var targetCanvas = this.canvas;\n      if (this.noScaleCache && targetCanvas && targetCanvas._currentTransform) {\n        var target = targetCanvas._currentTransform.target,\n            action = targetCanvas._currentTransform.action;\n        if (this === target && action.slice && action.slice(0, 5) === 'scale') {\n          return false;\n        }\n      }\n      var canvas = this._cacheCanvas,\n          dims = this._limitCacheSize(this._getCacheCanvasDimensions()),\n          width = dims.width, height = dims.height, drawingWidth, drawingHeight,\n          zoomX = dims.zoomX, zoomY = dims.zoomY,\n          dimensionsChanged = width !== this.cacheWidth || height !== this.cacheHeight,\n          zoomChanged = this.zoomX !== zoomX || this.zoomY !== zoomY,\n          shouldRedraw = dimensionsChanged || zoomChanged;\n\n      if (shouldRedraw) {\n        if (dimensionsChanged) {\n          canvas.width = width;\n          canvas.height = height;\n        }\n        else {\n          this._cacheContext.setTransform(1, 0, 0, 1, 0, 0);\n          this._cacheContext.clearRect(0, 0, canvas.width, canvas.height);\n        }\n        drawingWidth = dims.x / 2;\n        drawingHeight = dims.y / 2;\n        this.cacheTranslationX = Math.round(canvas.width / 2 - drawingWidth) + drawingWidth;\n        this.cacheTranslationY = Math.round(canvas.height / 2 - drawingHeight) + drawingHeight;\n        this.cacheWidth = width;\n        this.cacheHeight = height;\n        this._cacheContext.translate(this.cacheTranslationX, this.cacheTranslationY);\n        this._cacheContext.scale(zoomX, zoomY);\n        this.zoomX = zoomX;\n        this.zoomY = zoomY;\n        return true;\n      }\n      return false;\n    },\n\n    /**\n     * Sets object's properties from options\n     * @param {Object} [options] Options object\n     */\n    setOptions: function(options) {\n      this._setOptions(options);\n      this._initGradient(options.fill, 'fill');\n      this._initGradient(options.stroke, 'stroke');\n      this._initPattern(options.fill, 'fill');\n      this._initPattern(options.stroke, 'stroke');\n    },\n\n    /**\n     * Transforms context when rendering an object\n     * @param {CanvasRenderingContext2D} ctx Context\n     */\n    transform: function(ctx) {\n      var needFullTransform = (this.group && !this.group._transformDone) ||\n         (this.group && this.canvas && ctx === this.canvas.contextTop);\n      var m = this.calcTransformMatrix(!needFullTransform);\n      ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n    },\n\n    /**\n     * Returns an object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n\n          object = {\n            type:                     this.type,\n            version:                  fabric.version,\n            originX:                  this.originX,\n            originY:                  this.originY,\n            left:                     toFixed(this.left, NUM_FRACTION_DIGITS),\n            top:                      toFixed(this.top, NUM_FRACTION_DIGITS),\n            width:                    toFixed(this.width, NUM_FRACTION_DIGITS),\n            height:                   toFixed(this.height, NUM_FRACTION_DIGITS),\n            fill:                     (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,\n            stroke:                   (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke,\n            strokeWidth:              toFixed(this.strokeWidth, NUM_FRACTION_DIGITS),\n            strokeDashArray:          this.strokeDashArray ? this.strokeDashArray.concat() : this.strokeDashArray,\n            strokeLineCap:            this.strokeLineCap,\n            strokeDashOffset:         this.strokeDashOffset,\n            strokeLineJoin:           this.strokeLineJoin,\n            strokeUniform:            this.strokeUniform,\n            strokeMiterLimit:         toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS),\n            scaleX:                   toFixed(this.scaleX, NUM_FRACTION_DIGITS),\n            scaleY:                   toFixed(this.scaleY, NUM_FRACTION_DIGITS),\n            angle:                    toFixed(this.angle, NUM_FRACTION_DIGITS),\n            flipX:                    this.flipX,\n            flipY:                    this.flipY,\n            opacity:                  toFixed(this.opacity, NUM_FRACTION_DIGITS),\n            shadow:                   (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow,\n            visible:                  this.visible,\n            backgroundColor:          this.backgroundColor,\n            fillRule:                 this.fillRule,\n            paintFirst:               this.paintFirst,\n            globalCompositeOperation: this.globalCompositeOperation,\n            skewX:                    toFixed(this.skewX, NUM_FRACTION_DIGITS),\n            skewY:                    toFixed(this.skewY, NUM_FRACTION_DIGITS),\n          };\n\n      if (this.clipPath && !this.clipPath.excludeFromExport) {\n        object.clipPath = this.clipPath.toObject(propertiesToInclude);\n        object.clipPath.inverted = this.clipPath.inverted;\n        object.clipPath.absolutePositioned = this.clipPath.absolutePositioned;\n      }\n\n      fabric.util.populateWithProperties(this, object, propertiesToInclude);\n      if (!this.includeDefaultValues) {\n        object = this._removeDefaultValues(object);\n      }\n\n      return object;\n    },\n\n    /**\n     * Returns (dataless) object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toDatalessObject: function(propertiesToInclude) {\n      // will be overwritten by subclasses\n      return this.toObject(propertiesToInclude);\n    },\n\n    /**\n     * @private\n     * @param {Object} object\n     */\n    _removeDefaultValues: function(object) {\n      var prototype = fabric.util.getKlass(object.type).prototype,\n          stateProperties = prototype.stateProperties;\n      stateProperties.forEach(function(prop) {\n        if (prop === 'left' || prop === 'top') {\n          return;\n        }\n        if (object[prop] === prototype[prop]) {\n          delete object[prop];\n        }\n        // basically a check for [] === []\n        if (Array.isArray(object[prop]) && Array.isArray(prototype[prop])\n          && object[prop].length === 0 && prototype[prop].length === 0) {\n          delete object[prop];\n        }\n      });\n\n      return object;\n    },\n\n    /**\n     * Returns a string representation of an instance\n     * @return {String}\n     */\n    toString: function() {\n      return '#<fabric.' + capitalize(this.type) + '>';\n    },\n\n    /**\n     * Return the object scale factor counting also the group scaling\n     * @return {Object} object with scaleX and scaleY properties\n     */\n    getObjectScaling: function() {\n      // if the object is a top level one, on the canvas, we go for simple aritmetic\n      // otherwise the complex method with angles will return approximations and decimals\n      // and will likely kill the cache when not needed\n      // https://github.com/fabricjs/fabric.js/issues/7157\n      if (!this.group) {\n        return {\n          scaleX: this.scaleX,\n          scaleY: this.scaleY,\n        };\n      }\n      // if we are inside a group total zoom calculation is complex, we defer to generic matrices\n      var options = fabric.util.qrDecompose(this.calcTransformMatrix());\n      return { scaleX: Math.abs(options.scaleX), scaleY: Math.abs(options.scaleY) };\n    },\n\n    /**\n     * Return the object scale factor counting also the group scaling, zoom and retina\n     * @return {Object} object with scaleX and scaleY properties\n     */\n    getTotalObjectScaling: function() {\n      var scale = this.getObjectScaling(), scaleX = scale.scaleX, scaleY = scale.scaleY;\n      if (this.canvas) {\n        var zoom = this.canvas.getZoom();\n        var retina = this.canvas.getRetinaScaling();\n        scaleX *= zoom * retina;\n        scaleY *= zoom * retina;\n      }\n      return { scaleX: scaleX, scaleY: scaleY };\n    },\n\n    /**\n     * Return the object opacity counting also the group property\n     * @return {Number}\n     */\n    getObjectOpacity: function() {\n      var opacity = this.opacity;\n      if (this.group) {\n        opacity *= this.group.getObjectOpacity();\n      }\n      return opacity;\n    },\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     * @return {fabric.Object} thisArg\n     */\n    _set: function(key, value) {\n      var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY'),\n          isChanged = this[key] !== value, groupNeedsUpdate = false;\n\n      if (shouldConstrainValue) {\n        value = this._constrainScale(value);\n      }\n      if (key === 'scaleX' && value < 0) {\n        this.flipX = !this.flipX;\n        value *= -1;\n      }\n      else if (key === 'scaleY' && value < 0) {\n        this.flipY = !this.flipY;\n        value *= -1;\n      }\n      else if (key === 'shadow' && value && !(value instanceof fabric.Shadow)) {\n        value = new fabric.Shadow(value);\n      }\n      else if (key === 'dirty' && this.group) {\n        this.group.set('dirty', value);\n      }\n\n      this[key] = value;\n\n      if (isChanged) {\n        groupNeedsUpdate = this.group && this.group.isOnACache();\n        if (this.cacheProperties.indexOf(key) > -1) {\n          this.dirty = true;\n          groupNeedsUpdate && this.group.set('dirty', true);\n        }\n        else if (groupNeedsUpdate && this.stateProperties.indexOf(key) > -1) {\n          this.group.set('dirty', true);\n        }\n      }\n      return this;\n    },\n\n    /**\n     * This callback function is called by the parent group of an object every\n     * time a non-delegated property changes on the group. It is passed the key\n     * and value as parameters. Not adding in this function's signature to avoid\n     * Travis build error about unused variables.\n     */\n    setOnGroup: function() {\n      // implemented by sub-classes, as needed.\n    },\n\n    /**\n     * Retrieves viewportTransform from Object's canvas if possible\n     * @method getViewportTransform\n     * @memberOf fabric.Object.prototype\n     * @return {Array}\n     */\n    getViewportTransform: function() {\n      if (this.canvas && this.canvas.viewportTransform) {\n        return this.canvas.viewportTransform;\n      }\n      return fabric.iMatrix.concat();\n    },\n\n    /*\n     * @private\n     * return if the object would be visible in rendering\n     * @memberOf fabric.Object.prototype\n     * @return {Boolean}\n     */\n    isNotVisible: function() {\n      return this.opacity === 0 ||\n        (!this.width && !this.height && this.strokeWidth === 0) ||\n        !this.visible;\n    },\n\n    /**\n     * Renders an object on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    render: function(ctx) {\n      // do not render if width/height are zeros or object is not visible\n      if (this.isNotVisible()) {\n        return;\n      }\n      if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) {\n        return;\n      }\n      ctx.save();\n      this._setupCompositeOperation(ctx);\n      this.drawSelectionBackground(ctx);\n      this.transform(ctx);\n      this._setOpacity(ctx);\n      this._setShadow(ctx, this);\n      if (this.shouldCache()) {\n        this.renderCache();\n        this.drawCacheOnCanvas(ctx);\n      }\n      else {\n        this._removeCacheCanvas();\n        this.dirty = false;\n        this.drawObject(ctx);\n        if (this.objectCaching && this.statefullCache) {\n          this.saveState({ propertySet: 'cacheProperties' });\n        }\n      }\n      ctx.restore();\n    },\n\n    renderCache: function(options) {\n      options = options || {};\n      if (!this._cacheCanvas || !this._cacheContext) {\n        this._createCacheCanvas();\n      }\n      if (this.isCacheDirty()) {\n        this.statefullCache && this.saveState({ propertySet: 'cacheProperties' });\n        this.drawObject(this._cacheContext, options.forClipping);\n        this.dirty = false;\n      }\n    },\n\n    /**\n     * Remove cacheCanvas and its dimensions from the objects\n     */\n    _removeCacheCanvas: function() {\n      this._cacheCanvas = null;\n      this._cacheContext = null;\n      this.cacheWidth = 0;\n      this.cacheHeight = 0;\n    },\n\n    /**\n     * return true if the object will draw a stroke\n     * Does not consider text styles. This is just a shortcut used at rendering time\n     * We want it to be an approximation and be fast.\n     * wrote to avoid extra caching, it has to return true when stroke happens,\n     * can guess when it will not happen at 100% chance, does not matter if it misses\n     * some use case where the stroke is invisible.\n     * @since 3.0.0\n     * @returns Boolean\n     */\n    hasStroke: function() {\n      return this.stroke && this.stroke !== 'transparent' && this.strokeWidth !== 0;\n    },\n\n    /**\n     * return true if the object will draw a fill\n     * Does not consider text styles. This is just a shortcut used at rendering time\n     * We want it to be an approximation and be fast.\n     * wrote to avoid extra caching, it has to return true when fill happens,\n     * can guess when it will not happen at 100% chance, does not matter if it misses\n     * some use case where the fill is invisible.\n     * @since 3.0.0\n     * @returns Boolean\n     */\n    hasFill: function() {\n      return this.fill && this.fill !== 'transparent';\n    },\n\n    /**\n     * When set to `true`, force the object to have its own cache, even if it is inside a group\n     * it may be needed when your object behave in a particular way on the cache and always needs\n     * its own isolated canvas to render correctly.\n     * Created to be overridden\n     * since 1.7.12\n     * @returns Boolean\n     */\n    needsItsOwnCache: function() {\n      if (this.paintFirst === 'stroke' &&\n        this.hasFill() && this.hasStroke() && typeof this.shadow === 'object') {\n        return true;\n      }\n      if (this.clipPath) {\n        return true;\n      }\n      return false;\n    },\n\n    /**\n     * Decide if the object should cache or not. Create its own cache level\n     * objectCaching is a global flag, wins over everything\n     * needsItsOwnCache should be used when the object drawing method requires\n     * a cache step. None of the fabric classes requires it.\n     * Generally you do not cache objects in groups because the group outside is cached.\n     * Read as: cache if is needed, or if the feature is enabled but we are not already caching.\n     * @return {Boolean}\n     */\n    shouldCache: function() {\n      this.ownCaching = this.needsItsOwnCache() || (\n        this.objectCaching &&\n        (!this.group || !this.group.isOnACache())\n      );\n      return this.ownCaching;\n    },\n\n    /**\n     * Check if this object or a child object will cast a shadow\n     * used by Group.shouldCache to know if child has a shadow recursively\n     * @return {Boolean}\n     */\n    willDrawShadow: function() {\n      return !!this.shadow && (this.shadow.offsetX !== 0 || this.shadow.offsetY !== 0);\n    },\n\n    /**\n     * Execute the drawing operation for an object clipPath\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {fabric.Object} clipPath\n     */\n    drawClipPathOnCache: function(ctx, clipPath) {\n      ctx.save();\n      // DEBUG: uncomment this line, comment the following\n      // ctx.globalAlpha = 0.4\n      if (clipPath.inverted) {\n        ctx.globalCompositeOperation = 'destination-out';\n      }\n      else {\n        ctx.globalCompositeOperation = 'destination-in';\n      }\n      //ctx.scale(1 / 2, 1 / 2);\n      if (clipPath.absolutePositioned) {\n        var m = fabric.util.invertTransform(this.calcTransformMatrix());\n        ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n      }\n      clipPath.transform(ctx);\n      ctx.scale(1 / clipPath.zoomX, 1 / clipPath.zoomY);\n      ctx.drawImage(clipPath._cacheCanvas, -clipPath.cacheTranslationX, -clipPath.cacheTranslationY);\n      ctx.restore();\n    },\n\n    /**\n     * Execute the drawing operation for an object on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    drawObject: function(ctx, forClipping) {\n      var originalFill = this.fill, originalStroke = this.stroke;\n      if (forClipping) {\n        this.fill = 'black';\n        this.stroke = '';\n        this._setClippingProperties(ctx);\n      }\n      else {\n        this._renderBackground(ctx);\n      }\n      this._render(ctx);\n      this._drawClipPath(ctx, this.clipPath);\n      this.fill = originalFill;\n      this.stroke = originalStroke;\n    },\n\n    /**\n     * Prepare clipPath state and cache and draw it on instance's cache\n     * @param {CanvasRenderingContext2D} ctx\n     * @param {fabric.Object} clipPath\n     */\n    _drawClipPath: function (ctx, clipPath) {\n      if (!clipPath) { return; }\n      // needed to setup a couple of variables\n      // path canvas gets overridden with this one.\n      // TODO find a better solution?\n      clipPath.canvas = this.canvas;\n      clipPath.shouldCache();\n      clipPath._transformDone = true;\n      clipPath.renderCache({ forClipping: true });\n      this.drawClipPathOnCache(ctx, clipPath);\n    },\n\n    /**\n     * Paint the cached copy of the object on the target context.\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    drawCacheOnCanvas: function(ctx) {\n      ctx.scale(1 / this.zoomX, 1 / this.zoomY);\n      ctx.drawImage(this._cacheCanvas, -this.cacheTranslationX, -this.cacheTranslationY);\n    },\n\n    /**\n     * Check if cache is dirty\n     * @param {Boolean} skipCanvas skip canvas checks because this object is painted\n     * on parent canvas.\n     */\n    isCacheDirty: function(skipCanvas) {\n      if (this.isNotVisible()) {\n        return false;\n      }\n      if (this._cacheCanvas && this._cacheContext && !skipCanvas && this._updateCacheCanvas()) {\n        // in this case the context is already cleared.\n        return true;\n      }\n      else {\n        if (this.dirty ||\n          (this.clipPath && this.clipPath.absolutePositioned) ||\n          (this.statefullCache && this.hasStateChanged('cacheProperties'))\n        ) {\n          if (this._cacheCanvas && this._cacheContext && !skipCanvas) {\n            var width = this.cacheWidth / this.zoomX;\n            var height = this.cacheHeight / this.zoomY;\n            this._cacheContext.clearRect(-width / 2, -height / 2, width, height);\n          }\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Draws a background for the object big as its untransformed dimensions\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderBackground: function(ctx) {\n      if (!this.backgroundColor) {\n        return;\n      }\n      var dim = this._getNonTransformedDimensions();\n      ctx.fillStyle = this.backgroundColor;\n\n      ctx.fillRect(\n        -dim.x / 2,\n        -dim.y / 2,\n        dim.x,\n        dim.y\n      );\n      // if there is background color no other shadows\n      // should be casted\n      this._removeShadow(ctx);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _setOpacity: function(ctx) {\n      if (this.group && !this.group._transformDone) {\n        ctx.globalAlpha = this.getObjectOpacity();\n      }\n      else {\n        ctx.globalAlpha *= this.opacity;\n      }\n    },\n\n    _setStrokeStyles: function(ctx, decl) {\n      var stroke = decl.stroke;\n      if (stroke) {\n        ctx.lineWidth = decl.strokeWidth;\n        ctx.lineCap = decl.strokeLineCap;\n        ctx.lineDashOffset = decl.strokeDashOffset;\n        ctx.lineJoin = decl.strokeLineJoin;\n        ctx.miterLimit = decl.strokeMiterLimit;\n        if (stroke.toLive) {\n          if (stroke.gradientUnits === 'percentage' || stroke.gradientTransform || stroke.patternTransform) {\n            // need to transform gradient in a pattern.\n            // this is a slow process. If you are hitting this codepath, and the object\n            // is not using caching, you should consider switching it on.\n            // we need a canvas as big as the current object caching canvas.\n            this._applyPatternForTransformedGradient(ctx, stroke);\n          }\n          else {\n            // is a simple gradient or pattern\n            ctx.strokeStyle = stroke.toLive(ctx, this);\n            this._applyPatternGradientTransform(ctx, stroke);\n          }\n        }\n        else {\n          // is a color\n          ctx.strokeStyle = decl.stroke;\n        }\n      }\n    },\n\n    _setFillStyles: function(ctx, decl) {\n      var fill = decl.fill;\n      if (fill) {\n        if (fill.toLive) {\n          ctx.fillStyle = fill.toLive(ctx, this);\n          this._applyPatternGradientTransform(ctx, decl.fill);\n        }\n        else {\n          ctx.fillStyle = fill;\n        }\n      }\n    },\n\n    _setClippingProperties: function(ctx) {\n      ctx.globalAlpha = 1;\n      ctx.strokeStyle = 'transparent';\n      ctx.fillStyle = '#000000';\n    },\n\n    /**\n     * @private\n     * Sets line dash\n     * @param {CanvasRenderingContext2D} ctx Context to set the dash line on\n     * @param {Array} dashArray array representing dashes\n     */\n    _setLineDash: function(ctx, dashArray) {\n      if (!dashArray || dashArray.length === 0) {\n        return;\n      }\n      // Spec requires the concatenation of two copies the dash list when the number of elements is odd\n      if (1 & dashArray.length) {\n        dashArray.push.apply(dashArray, dashArray);\n      }\n      ctx.setLineDash(dashArray);\n    },\n\n    /**\n     * Renders controls and borders for the object\n     * the context here is not transformed\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Object} [styleOverride] properties to override the object style\n     */\n    _renderControls: function(ctx, styleOverride) {\n      var vpt = this.getViewportTransform(),\n          matrix = this.calcTransformMatrix(),\n          options, drawBorders, drawControls;\n      styleOverride = styleOverride || { };\n      drawBorders = typeof styleOverride.hasBorders !== 'undefined' ? styleOverride.hasBorders : this.hasBorders;\n      drawControls = typeof styleOverride.hasControls !== 'undefined' ? styleOverride.hasControls : this.hasControls;\n      matrix = fabric.util.multiplyTransformMatrices(vpt, matrix);\n      options = fabric.util.qrDecompose(matrix);\n      ctx.save();\n      ctx.translate(options.translateX, options.translateY);\n      ctx.lineWidth = 1 * this.borderScaleFactor;\n      if (!this.group) {\n        ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n      }\n      if (this.flipX) {\n        options.angle -= 180;\n      }\n      ctx.rotate(degreesToRadians(this.group ? options.angle : this.angle));\n      if (styleOverride.forActiveSelection || this.group) {\n        drawBorders && this.drawBordersInGroup(ctx, options, styleOverride);\n      }\n      else {\n        drawBorders && this.drawBorders(ctx, styleOverride);\n      }\n      drawControls && this.drawControls(ctx, styleOverride);\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _setShadow: function(ctx) {\n      if (!this.shadow) {\n        return;\n      }\n\n      var shadow = this.shadow, canvas = this.canvas, scaling,\n          multX = (canvas && canvas.viewportTransform[0]) || 1,\n          multY = (canvas && canvas.viewportTransform[3]) || 1;\n      if (shadow.nonScaling) {\n        scaling = { scaleX: 1, scaleY: 1 };\n      }\n      else {\n        scaling = this.getObjectScaling();\n      }\n      if (canvas && canvas._isRetinaScaling()) {\n        multX *= fabric.devicePixelRatio;\n        multY *= fabric.devicePixelRatio;\n      }\n      ctx.shadowColor = shadow.color;\n      ctx.shadowBlur = shadow.blur * fabric.browserShadowBlurConstant *\n        (multX + multY) * (scaling.scaleX + scaling.scaleY) / 4;\n      ctx.shadowOffsetX = shadow.offsetX * multX * scaling.scaleX;\n      ctx.shadowOffsetY = shadow.offsetY * multY * scaling.scaleY;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _removeShadow: function(ctx) {\n      if (!this.shadow) {\n        return;\n      }\n\n      ctx.shadowColor = '';\n      ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Object} filler fabric.Pattern or fabric.Gradient\n     * @return {Object} offset.offsetX offset for text rendering\n     * @return {Object} offset.offsetY offset for text rendering\n     */\n    _applyPatternGradientTransform: function(ctx, filler) {\n      if (!filler || !filler.toLive) {\n        return { offsetX: 0, offsetY: 0 };\n      }\n      var t = filler.gradientTransform || filler.patternTransform;\n      var offsetX = -this.width / 2 + filler.offsetX || 0,\n          offsetY = -this.height / 2 + filler.offsetY || 0;\n\n      if (filler.gradientUnits === 'percentage') {\n        ctx.transform(this.width, 0, 0, this.height, offsetX, offsetY);\n      }\n      else {\n        ctx.transform(1, 0, 0, 1, offsetX, offsetY);\n      }\n      if (t) {\n        ctx.transform(t[0], t[1], t[2], t[3], t[4], t[5]);\n      }\n      return { offsetX: offsetX, offsetY: offsetY };\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderPaintInOrder: function(ctx) {\n      if (this.paintFirst === 'stroke') {\n        this._renderStroke(ctx);\n        this._renderFill(ctx);\n      }\n      else {\n        this._renderFill(ctx);\n        this._renderStroke(ctx);\n      }\n    },\n\n    /**\n     * @private\n     * function that actually render something on the context.\n     * empty here to allow Obects to work on tests to benchmark fabric functionalites\n     * not related to rendering\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(/* ctx */) {\n\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderFill: function(ctx) {\n      if (!this.fill) {\n        return;\n      }\n\n      ctx.save();\n      this._setFillStyles(ctx, this);\n      if (this.fillRule === 'evenodd') {\n        ctx.fill('evenodd');\n      }\n      else {\n        ctx.fill();\n      }\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderStroke: function(ctx) {\n      if (!this.stroke || this.strokeWidth === 0) {\n        return;\n      }\n\n      if (this.shadow && !this.shadow.affectStroke) {\n        this._removeShadow(ctx);\n      }\n\n      ctx.save();\n      if (this.strokeUniform && this.group) {\n        var scaling = this.getObjectScaling();\n        ctx.scale(1 / scaling.scaleX, 1 / scaling.scaleY);\n      }\n      else if (this.strokeUniform) {\n        ctx.scale(1 / this.scaleX, 1 / this.scaleY);\n      }\n      this._setLineDash(ctx, this.strokeDashArray);\n      this._setStrokeStyles(ctx, this);\n      ctx.stroke();\n      ctx.restore();\n    },\n\n    /**\n     * This function try to patch the missing gradientTransform on canvas gradients.\n     * transforming a context to transform the gradient, is going to transform the stroke too.\n     * we want to transform the gradient but not the stroke operation, so we create\n     * a transformed gradient on a pattern and then we use the pattern instead of the gradient.\n     * this method has drwabacks: is slow, is in low resolution, needs a patch for when the size\n     * is limited.\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {fabric.Gradient} filler a fabric gradient instance\n     */\n    _applyPatternForTransformedGradient: function(ctx, filler) {\n      var dims = this._limitCacheSize(this._getCacheCanvasDimensions()),\n          pCanvas = fabric.util.createCanvasElement(), pCtx, retinaScaling = this.canvas.getRetinaScaling(),\n          width = dims.x / this.scaleX / retinaScaling, height = dims.y / this.scaleY / retinaScaling;\n      pCanvas.width = Math.ceil(width);\n      pCanvas.height = Math.ceil(height);\n      pCtx = pCanvas.getContext('2d');\n      pCtx.beginPath(); pCtx.moveTo(0, 0); pCtx.lineTo(width, 0); pCtx.lineTo(width, height);\n      pCtx.lineTo(0, height); pCtx.closePath();\n      pCtx.translate(width / 2, height / 2);\n      pCtx.scale(\n        dims.zoomX / this.scaleX / retinaScaling,\n        dims.zoomY / this.scaleY / retinaScaling\n      );\n      this._applyPatternGradientTransform(pCtx, filler);\n      pCtx.fillStyle = filler.toLive(ctx);\n      pCtx.fill();\n      ctx.translate(-this.width / 2 - this.strokeWidth / 2, -this.height / 2 - this.strokeWidth / 2);\n      ctx.scale(\n        retinaScaling * this.scaleX / dims.zoomX,\n        retinaScaling * this.scaleY / dims.zoomY\n      );\n      ctx.strokeStyle = pCtx.createPattern(pCanvas, 'no-repeat');\n    },\n\n    /**\n     * This function is an helper for svg import. it returns the center of the object in the svg\n     * untransformed coordinates\n     * @private\n     * @return {Object} center point from element coordinates\n     */\n    _findCenterFromElement: function() {\n      return { x: this.left + this.width / 2, y: this.top + this.height / 2 };\n    },\n\n    /**\n     * This function is an helper for svg import. it decompose the transformMatrix\n     * and assign properties to object.\n     * untransformed coordinates\n     * @private\n     * @chainable\n     */\n    _assignTransformMatrixProps: function() {\n      if (this.transformMatrix) {\n        var options = fabric.util.qrDecompose(this.transformMatrix);\n        this.flipX = false;\n        this.flipY = false;\n        this.set('scaleX', options.scaleX);\n        this.set('scaleY', options.scaleY);\n        this.angle = options.angle;\n        this.skewX = options.skewX;\n        this.skewY = 0;\n      }\n    },\n\n    /**\n     * This function is an helper for svg import. it removes the transform matrix\n     * and set to object properties that fabricjs can handle\n     * @private\n     * @param {Object} preserveAspectRatioOptions\n     * @return {thisArg}\n     */\n    _removeTransformMatrix: function(preserveAspectRatioOptions) {\n      var center = this._findCenterFromElement();\n      if (this.transformMatrix) {\n        this._assignTransformMatrixProps();\n        center = fabric.util.transformPoint(center, this.transformMatrix);\n      }\n      this.transformMatrix = null;\n      if (preserveAspectRatioOptions) {\n        this.scaleX *= preserveAspectRatioOptions.scaleX;\n        this.scaleY *= preserveAspectRatioOptions.scaleY;\n        this.cropX = preserveAspectRatioOptions.cropX;\n        this.cropY = preserveAspectRatioOptions.cropY;\n        center.x += preserveAspectRatioOptions.offsetLeft;\n        center.y += preserveAspectRatioOptions.offsetTop;\n        this.width = preserveAspectRatioOptions.width;\n        this.height = preserveAspectRatioOptions.height;\n      }\n      this.setPositionByOrigin(center, 'center', 'center');\n    },\n\n    /**\n     * Clones an instance, using a callback method will work for every object.\n     * @param {Function} callback Callback is invoked with a clone as a first argument\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     */\n    clone: function(callback, propertiesToInclude) {\n      var objectForm = this.toObject(propertiesToInclude);\n      if (this.constructor.fromObject) {\n        this.constructor.fromObject(objectForm, callback);\n      }\n      else {\n        fabric.Object._fromObject('Object', objectForm, callback);\n      }\n    },\n\n    /**\n     * Creates an instance of fabric.Image out of an object\n     * makes use of toCanvasElement.\n     * Once this method was based on toDataUrl and loadImage, so it also had a quality\n     * and format option. toCanvasElement is faster and produce no loss of quality.\n     * If you need to get a real Jpeg or Png from an object, using toDataURL is the right way to do it.\n     * toCanvasElement and then toBlob from the obtained canvas is also a good option.\n     * This method is sync now, but still support the callback because we did not want to break.\n     * When fabricJS 5.0 will be planned, this will probably be changed to not have a callback.\n     * @param {Function} callback callback, invoked with an instance as a first argument\n     * @param {Object} [options] for clone as image, passed to toDataURL\n     * @param {Number} [options.multiplier=1] Multiplier to scale by\n     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n     * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4\n     * @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4\n     * @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2\n     * @return {fabric.Object} thisArg\n     */\n    cloneAsImage: function(callback, options) {\n      var canvasEl = this.toCanvasElement(options);\n      if (callback) {\n        callback(new fabric.Image(canvasEl));\n      }\n      return this;\n    },\n\n    /**\n     * Converts an object into a HTMLCanvas element\n     * @param {Object} options Options object\n     * @param {Number} [options.multiplier=1] Multiplier to scale by\n     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n     * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4\n     * @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4\n     * @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2\n     * @return {HTMLCanvasElement} Returns DOM element <canvas> with the fabric.Object\n     */\n    toCanvasElement: function(options) {\n      options || (options = { });\n\n      var utils = fabric.util, origParams = utils.saveObjectTransform(this),\n          originalGroup = this.group,\n          originalShadow = this.shadow, abs = Math.abs,\n          multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? fabric.devicePixelRatio : 1);\n      delete this.group;\n      if (options.withoutTransform) {\n        utils.resetObjectTransform(this);\n      }\n      if (options.withoutShadow) {\n        this.shadow = null;\n      }\n\n      var el = fabric.util.createCanvasElement(),\n          // skip canvas zoom and calculate with setCoords now.\n          boundingRect = this.getBoundingRect(true, true),\n          shadow = this.shadow, scaling,\n          shadowOffset = { x: 0, y: 0 }, shadowBlur,\n          width, height;\n\n      if (shadow) {\n        shadowBlur = shadow.blur;\n        if (shadow.nonScaling) {\n          scaling = { scaleX: 1, scaleY: 1 };\n        }\n        else {\n          scaling = this.getObjectScaling();\n        }\n        // consider non scaling shadow.\n        shadowOffset.x = 2 * Math.round(abs(shadow.offsetX) + shadowBlur) * (abs(scaling.scaleX));\n        shadowOffset.y = 2 * Math.round(abs(shadow.offsetY) + shadowBlur) * (abs(scaling.scaleY));\n      }\n      width = boundingRect.width + shadowOffset.x;\n      height = boundingRect.height + shadowOffset.y;\n      // if the current width/height is not an integer\n      // we need to make it so.\n      el.width = Math.ceil(width);\n      el.height = Math.ceil(height);\n      var canvas = new fabric.StaticCanvas(el, {\n        enableRetinaScaling: false,\n        renderOnAddRemove: false,\n        skipOffscreen: false,\n      });\n      if (options.format === 'jpeg') {\n        canvas.backgroundColor = '#fff';\n      }\n      this.setPositionByOrigin(new fabric.Point(canvas.width / 2, canvas.height / 2), 'center', 'center');\n\n      var originalCanvas = this.canvas;\n      canvas.add(this);\n      var canvasEl = canvas.toCanvasElement(multiplier || 1, options);\n      this.shadow = originalShadow;\n      this.set('canvas', originalCanvas);\n      if (originalGroup) {\n        this.group = originalGroup;\n      }\n      this.set(origParams).setCoords();\n      // canvas.dispose will call image.dispose that will nullify the elements\n      // since this canvas is a simple element for the process, we remove references\n      // to objects in this way in order to avoid object trashing.\n      canvas._objects = [];\n      canvas.dispose();\n      canvas = null;\n\n      return canvasEl;\n    },\n\n    /**\n     * Converts an object into a data-url-like string\n     * @param {Object} options Options object\n     * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n     * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n     * @param {Number} [options.multiplier=1] Multiplier to scale by\n     * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n     * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n     * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n     * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n     * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4\n     * @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4\n     * @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2\n     * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n     */\n    toDataURL: function(options) {\n      options || (options = { });\n      return fabric.util.toDataURL(this.toCanvasElement(options), options.format || 'png', options.quality || 1);\n    },\n\n    /**\n     * Returns true if specified type is identical to the type of an instance\n     * @param {String} type Type to check against\n     * @return {Boolean}\n     */\n    isType: function(type) {\n      return arguments.length > 1 ? Array.from(arguments).includes(this.type) : this.type === type;\n    },\n\n    /**\n     * Returns complexity of an instance\n     * @return {Number} complexity of this instance (is 1 unless subclassed)\n     */\n    complexity: function() {\n      return 1;\n    },\n\n    /**\n     * Returns a JSON representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} JSON\n     */\n    toJSON: function(propertiesToInclude) {\n      // delegate, not alias\n      return this.toObject(propertiesToInclude);\n    },\n\n    /**\n     * Sets \"angle\" of an instance with centered rotation\n     * @param {Number} angle Angle value (in degrees)\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    rotate: function(angle) {\n      var shouldCenterOrigin = (this.originX !== 'center' || this.originY !== 'center') && this.centeredRotation;\n\n      if (shouldCenterOrigin) {\n        this._setOriginToCenter();\n      }\n\n      this.set('angle', angle);\n\n      if (shouldCenterOrigin) {\n        this._resetOrigin();\n      }\n\n      return this;\n    },\n\n    /**\n     * Centers object horizontally on canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    centerH: function () {\n      this.canvas && this.canvas.centerObjectH(this);\n      return this;\n    },\n\n    /**\n     * Centers object horizontally on current viewport of canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    viewportCenterH: function () {\n      this.canvas && this.canvas.viewportCenterObjectH(this);\n      return this;\n    },\n\n    /**\n     * Centers object vertically on canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    centerV: function () {\n      this.canvas && this.canvas.centerObjectV(this);\n      return this;\n    },\n\n    /**\n     * Centers object vertically on current viewport of canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    viewportCenterV: function () {\n      this.canvas && this.canvas.viewportCenterObjectV(this);\n      return this;\n    },\n\n    /**\n     * Centers object vertically and horizontally on canvas to which is was added last\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    center: function () {\n      this.canvas && this.canvas.centerObject(this);\n      return this;\n    },\n\n    /**\n     * Centers object on current viewport of canvas to which it was added last.\n     * You might need to call `setCoords` on an object after centering, to update controls area.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    viewportCenter: function () {\n      this.canvas && this.canvas.viewportCenterObject(this);\n      return this;\n    },\n\n    /**\n     * Returns coordinates of a pointer relative to an object\n     * @param {Event} e Event to operate upon\n     * @param {Object} [pointer] Pointer to operate upon (instead of event)\n     * @return {Object} Coordinates of a pointer (x, y)\n     */\n    getLocalPointer: function(e, pointer) {\n      pointer = pointer || this.canvas.getPointer(e);\n      var pClicked = new fabric.Point(pointer.x, pointer.y),\n          objectLeftTop = this._getLeftTopCoords();\n      if (this.angle) {\n        pClicked = fabric.util.rotatePoint(\n          pClicked, objectLeftTop, degreesToRadians(-this.angle));\n      }\n      return {\n        x: pClicked.x - objectLeftTop.x,\n        y: pClicked.y - objectLeftTop.y\n      };\n    },\n\n    /**\n     * Sets canvas globalCompositeOperation for specific object\n     * custom composition operation for the particular object can be specified using globalCompositeOperation property\n     * @param {CanvasRenderingContext2D} ctx Rendering canvas context\n     */\n    _setupCompositeOperation: function (ctx) {\n      if (this.globalCompositeOperation) {\n        ctx.globalCompositeOperation = this.globalCompositeOperation;\n      }\n    },\n\n    /**\n     * cancel instance's running animations\n     * override if necessary to dispose artifacts such as `clipPath`\n     */\n    dispose: function () {\n      if (fabric.runningAnimations) {\n        fabric.runningAnimations.cancelByTarget(this);\n      }\n    }\n  });\n\n  fabric.util.createAccessors && fabric.util.createAccessors(fabric.Object);\n\n  extend(fabric.Object.prototype, fabric.Observable);\n\n  /**\n   * Defines the number of fraction digits to use when serializing object values.\n   * You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc.\n   * @static\n   * @memberOf fabric.Object\n   * @constant\n   * @type Number\n   */\n  fabric.Object.NUM_FRACTION_DIGITS = 2;\n\n  /**\n   * Defines which properties should be enlivened from the object passed to {@link fabric.Object._fromObject}\n   * @static\n   * @memberOf fabric.Object\n   * @constant\n   * @type string[]\n   */\n  fabric.Object.ENLIVEN_PROPS = ['clipPath'];\n\n  fabric.Object._fromObject = function(className, object, callback, extraParam) {\n    var klass = fabric[className];\n    object = clone(object, true);\n    fabric.util.enlivenPatterns([object.fill, object.stroke], function(patterns) {\n      if (typeof patterns[0] !== 'undefined') {\n        object.fill = patterns[0];\n      }\n      if (typeof patterns[1] !== 'undefined') {\n        object.stroke = patterns[1];\n      }\n      fabric.util.enlivenObjectEnlivables(object, object, function () {\n        var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);\n        callback && callback(instance);\n      });\n    });\n  };\n\n  /**\n   * Unique id used internally when creating SVG elements\n   * @static\n   * @memberOf fabric.Object\n   * @type Number\n   */\n  fabric.Object.__uid = 0;\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  var degreesToRadians = fabric.util.degreesToRadians,\n      originXOffset = {\n        left: -0.5,\n        center: 0,\n        right: 0.5\n      },\n      originYOffset = {\n        top: -0.5,\n        center: 0,\n        bottom: 0.5\n      };\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Translates the coordinates from a set of origin to another (based on the object's dimensions)\n     * @param {fabric.Point} point The point which corresponds to the originX and originY params\n     * @param {String} fromOriginX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} fromOriginY Vertical origin: 'top', 'center' or 'bottom'\n     * @param {String} toOriginX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} toOriginY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    translateToGivenOrigin: function(point, fromOriginX, fromOriginY, toOriginX, toOriginY) {\n      var x = point.x,\n          y = point.y,\n          offsetX, offsetY, dim;\n\n      if (typeof fromOriginX === 'string') {\n        fromOriginX = originXOffset[fromOriginX];\n      }\n      else {\n        fromOriginX -= 0.5;\n      }\n\n      if (typeof toOriginX === 'string') {\n        toOriginX = originXOffset[toOriginX];\n      }\n      else {\n        toOriginX -= 0.5;\n      }\n\n      offsetX = toOriginX - fromOriginX;\n\n      if (typeof fromOriginY === 'string') {\n        fromOriginY = originYOffset[fromOriginY];\n      }\n      else {\n        fromOriginY -= 0.5;\n      }\n\n      if (typeof toOriginY === 'string') {\n        toOriginY = originYOffset[toOriginY];\n      }\n      else {\n        toOriginY -= 0.5;\n      }\n\n      offsetY = toOriginY - fromOriginY;\n\n      if (offsetX || offsetY) {\n        dim = this._getTransformedDimensions();\n        x = point.x + offsetX * dim.x;\n        y = point.y + offsetY * dim.y;\n      }\n\n      return new fabric.Point(x, y);\n    },\n\n    /**\n     * Translates the coordinates from origin to center coordinates (based on the object's dimensions)\n     * @param {fabric.Point} point The point which corresponds to the originX and originY params\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    translateToCenterPoint: function(point, originX, originY) {\n      var p = this.translateToGivenOrigin(point, originX, originY, 'center', 'center');\n      if (this.angle) {\n        return fabric.util.rotatePoint(p, point, degreesToRadians(this.angle));\n      }\n      return p;\n    },\n\n    /**\n     * Translates the coordinates from center to origin coordinates (based on the object's dimensions)\n     * @param {fabric.Point} center The point which corresponds to center of the object\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    translateToOriginPoint: function(center, originX, originY) {\n      var p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);\n      if (this.angle) {\n        return fabric.util.rotatePoint(p, center, degreesToRadians(this.angle));\n      }\n      return p;\n    },\n\n    /**\n     * Returns the real center coordinates of the object\n     * @return {fabric.Point}\n     */\n    getCenterPoint: function() {\n      var leftTop = new fabric.Point(this.left, this.top);\n      return this.translateToCenterPoint(leftTop, this.originX, this.originY);\n    },\n\n    /**\n     * Returns the coordinates of the object based on center coordinates\n     * @param {fabric.Point} point The point which corresponds to the originX and originY params\n     * @return {fabric.Point}\n     */\n    // getOriginPoint: function(center) {\n    //   return this.translateToOriginPoint(center, this.originX, this.originY);\n    // },\n\n    /**\n     * Returns the coordinates of the object as if it has a different origin\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    getPointByOrigin: function(originX, originY) {\n      var center = this.getCenterPoint();\n      return this.translateToOriginPoint(center, originX, originY);\n    },\n\n    /**\n     * Returns the point in local coordinates\n     * @param {fabric.Point} point The point relative to the global coordinate system\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {fabric.Point}\n     */\n    toLocalPoint: function(point, originX, originY) {\n      var center = this.getCenterPoint(),\n          p, p2;\n\n      if (typeof originX !== 'undefined' && typeof originY !== 'undefined' ) {\n        p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);\n      }\n      else {\n        p = new fabric.Point(this.left, this.top);\n      }\n\n      p2 = new fabric.Point(point.x, point.y);\n      if (this.angle) {\n        p2 = fabric.util.rotatePoint(p2, center, -degreesToRadians(this.angle));\n      }\n      return p2.subtractEquals(p);\n    },\n\n    /**\n     * Returns the point in global coordinates\n     * @param {fabric.Point} The point relative to the local coordinate system\n     * @return {fabric.Point}\n     */\n    // toGlobalPoint: function(point) {\n    //   return fabric.util.rotatePoint(point, this.getCenterPoint(), degreesToRadians(this.angle)).addEquals(new fabric.Point(this.left, this.top));\n    // },\n\n    /**\n     * Sets the position of the object taking into consideration the object's origin\n     * @param {fabric.Point} pos The new position of the object\n     * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n     * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n     * @return {void}\n     */\n    setPositionByOrigin: function(pos, originX, originY) {\n      var center = this.translateToCenterPoint(pos, originX, originY),\n          position = this.translateToOriginPoint(center, this.originX, this.originY);\n      this.set('left', position.x);\n      this.set('top', position.y);\n    },\n\n    /**\n     * @param {String} to One of 'left', 'center', 'right'\n     */\n    adjustPosition: function(to) {\n      var angle = degreesToRadians(this.angle),\n          hypotFull = this.getScaledWidth(),\n          xFull = fabric.util.cos(angle) * hypotFull,\n          yFull = fabric.util.sin(angle) * hypotFull,\n          offsetFrom, offsetTo;\n\n      //TODO: this function does not consider mixed situation like top, center.\n      if (typeof this.originX === 'string') {\n        offsetFrom = originXOffset[this.originX];\n      }\n      else {\n        offsetFrom = this.originX - 0.5;\n      }\n      if (typeof to === 'string') {\n        offsetTo = originXOffset[to];\n      }\n      else {\n        offsetTo = to - 0.5;\n      }\n      this.left += xFull * (offsetTo - offsetFrom);\n      this.top += yFull * (offsetTo - offsetFrom);\n      this.setCoords();\n      this.originX = to;\n    },\n\n    /**\n     * Sets the origin/position of the object to it's center point\n     * @private\n     * @return {void}\n     */\n    _setOriginToCenter: function() {\n      this._originalOriginX = this.originX;\n      this._originalOriginY = this.originY;\n\n      var center = this.getCenterPoint();\n\n      this.originX = 'center';\n      this.originY = 'center';\n\n      this.left = center.x;\n      this.top = center.y;\n    },\n\n    /**\n     * Resets the origin/position of the object to it's original origin\n     * @private\n     * @return {void}\n     */\n    _resetOrigin: function() {\n      var originPoint = this.translateToOriginPoint(\n        this.getCenterPoint(),\n        this._originalOriginX,\n        this._originalOriginY);\n\n      this.originX = this._originalOriginX;\n      this.originY = this._originalOriginY;\n\n      this.left = originPoint.x;\n      this.top = originPoint.y;\n\n      this._originalOriginX = null;\n      this._originalOriginY = null;\n    },\n\n    /**\n     * @private\n     */\n    _getLeftTopCoords: function() {\n      return this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top');\n    },\n  });\n\n})();\n\n\n(function() {\n\n  function arrayFromCoords(coords) {\n    return [\n      new fabric.Point(coords.tl.x, coords.tl.y),\n      new fabric.Point(coords.tr.x, coords.tr.y),\n      new fabric.Point(coords.br.x, coords.br.y),\n      new fabric.Point(coords.bl.x, coords.bl.y)\n    ];\n  }\n\n  var util = fabric.util,\n      degreesToRadians = util.degreesToRadians,\n      multiplyMatrices = util.multiplyTransformMatrices,\n      transformPoint = util.transformPoint;\n\n  util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Describe object's corner position in canvas element coordinates.\n     * properties are depending on control keys and padding the main controls.\n     * each property is an object with x, y and corner.\n     * The `corner` property contains in a similar manner the 4 points of the\n     * interactive area of the corner.\n     * The coordinates depends from the controls positionHandler and are used\n     * to draw and locate controls\n     * @memberOf fabric.Object.prototype\n     */\n    oCoords: null,\n\n    /**\n     * Describe object's corner position in canvas object absolute coordinates\n     * properties are tl,tr,bl,br and describe the four main corner.\n     * each property is an object with x, y, instance of Fabric.Point.\n     * The coordinates depends from this properties: width, height, scaleX, scaleY\n     * skewX, skewY, angle, strokeWidth, top, left.\n     * Those coordinates are useful to understand where an object is. They get updated\n     * with oCoords but they do not need to be updated when zoom or panning change.\n     * The coordinates get updated with @method setCoords.\n     * You can calculate them without updating with @method calcACoords();\n     * @memberOf fabric.Object.prototype\n     */\n    aCoords: null,\n\n    /**\n     * Describe object's corner position in canvas element coordinates.\n     * includes padding. Used of object detection.\n     * set and refreshed with setCoords.\n     * @memberOf fabric.Object.prototype\n     */\n    lineCoords: null,\n\n    /**\n     * storage for object transform matrix\n     */\n    ownMatrixCache: null,\n\n    /**\n     * storage for object full transform matrix\n     */\n    matrixCache: null,\n\n    /**\n     * custom controls interface\n     * controls are added by default_controls.js\n     */\n    controls: { },\n\n    /**\n     * return correct set of coordinates for intersection\n     * this will return either aCoords or lineCoords.\n     * @param {Boolean} absolute will return aCoords if true or lineCoords\n     * @return {Object} {tl, tr, br, bl} points\n     */\n    _getCoords: function(absolute, calculate) {\n      if (calculate) {\n        return (absolute ? this.calcACoords() : this.calcLineCoords());\n      }\n      if (!this.aCoords || !this.lineCoords) {\n        this.setCoords(true);\n      }\n      return (absolute ? this.aCoords : this.lineCoords);\n    },\n\n    /**\n     * return correct set of coordinates for intersection\n     * this will return either aCoords or lineCoords.\n     * The coords are returned in an array.\n     * @return {Array} [tl, tr, br, bl] of points\n     */\n    getCoords: function(absolute, calculate) {\n      return arrayFromCoords(this._getCoords(absolute, calculate));\n    },\n\n    /**\n     * Checks if object intersects with an area formed by 2 points\n     * @param {Object} pointTL top-left point of area\n     * @param {Object} pointBR bottom-right point of area\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object intersects with an area formed by 2 points\n     */\n    intersectsWithRect: function(pointTL, pointBR, absolute, calculate) {\n      var coords = this.getCoords(absolute, calculate),\n          intersection = fabric.Intersection.intersectPolygonRectangle(\n            coords,\n            pointTL,\n            pointBR\n          );\n      return intersection.status === 'Intersection';\n    },\n\n    /**\n     * Checks if object intersects with another object\n     * @param {Object} other Object to test\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object intersects with another object\n     */\n    intersectsWithObject: function(other, absolute, calculate) {\n      var intersection = fabric.Intersection.intersectPolygonPolygon(\n        this.getCoords(absolute, calculate),\n        other.getCoords(absolute, calculate)\n      );\n\n      return intersection.status === 'Intersection'\n        || other.isContainedWithinObject(this, absolute, calculate)\n        || this.isContainedWithinObject(other, absolute, calculate);\n    },\n\n    /**\n     * Checks if object is fully contained within area of another object\n     * @param {Object} other Object to test\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object is fully contained within area of another object\n     */\n    isContainedWithinObject: function(other, absolute, calculate) {\n      var points = this.getCoords(absolute, calculate),\n          otherCoords = absolute ? other.aCoords : other.lineCoords,\n          i = 0, lines = other._getImageLines(otherCoords);\n      for (; i < 4; i++) {\n        if (!other.containsPoint(points[i], lines)) {\n          return false;\n        }\n      }\n      return true;\n    },\n\n    /**\n     * Checks if object is fully contained within area formed by 2 points\n     * @param {Object} pointTL top-left point of area\n     * @param {Object} pointBR bottom-right point of area\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object is fully contained within area formed by 2 points\n     */\n    isContainedWithinRect: function(pointTL, pointBR, absolute, calculate) {\n      var boundingRect = this.getBoundingRect(absolute, calculate);\n\n      return (\n        boundingRect.left >= pointTL.x &&\n        boundingRect.left + boundingRect.width <= pointBR.x &&\n        boundingRect.top >= pointTL.y &&\n        boundingRect.top + boundingRect.height <= pointBR.y\n      );\n    },\n\n    /**\n     * Checks if point is inside the object\n     * @param {fabric.Point} point Point to check against\n     * @param {Object} [lines] object returned from @method _getImageLines\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if point is inside the object\n     */\n    containsPoint: function(point, lines, absolute, calculate) {\n      var coords = this._getCoords(absolute, calculate),\n          lines = lines || this._getImageLines(coords),\n          xPoints = this._findCrossPoints(point, lines);\n      // if xPoints is odd then point is inside the object\n      return (xPoints !== 0 && xPoints % 2 === 1);\n    },\n\n    /**\n     * Checks if object is contained within the canvas with current viewportTransform\n     * the check is done stopping at first point that appears on screen\n     * @param {Boolean} [calculate] use coordinates of current position instead of .aCoords\n     * @return {Boolean} true if object is fully or partially contained within canvas\n     */\n    isOnScreen: function(calculate) {\n      if (!this.canvas) {\n        return false;\n      }\n      var pointTL = this.canvas.vptCoords.tl, pointBR = this.canvas.vptCoords.br;\n      var points = this.getCoords(true, calculate);\n      // if some point is on screen, the object is on screen.\n      if (points.some(function(point) {\n        return point.x <= pointBR.x && point.x >= pointTL.x &&\n        point.y <= pointBR.y && point.y >= pointTL.y;\n      })) {\n        return true;\n      }\n      // no points on screen, check intersection with absolute coordinates\n      if (this.intersectsWithRect(pointTL, pointBR, true, calculate)) {\n        return true;\n      }\n      return this._containsCenterOfCanvas(pointTL, pointBR, calculate);\n    },\n\n    /**\n     * Checks if the object contains the midpoint between canvas extremities\n     * Does not make sense outside the context of isOnScreen and isPartiallyOnScreen\n     * @private\n     * @param {Fabric.Point} pointTL Top Left point\n     * @param {Fabric.Point} pointBR Top Right point\n     * @param {Boolean} calculate use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if the object contains the point\n     */\n    _containsCenterOfCanvas: function(pointTL, pointBR, calculate) {\n      // worst case scenario the object is so big that contains the screen\n      var centerPoint = { x: (pointTL.x + pointBR.x) / 2, y: (pointTL.y + pointBR.y) / 2 };\n      if (this.containsPoint(centerPoint, null, true, calculate)) {\n        return true;\n      }\n      return false;\n    },\n\n    /**\n     * Checks if object is partially contained within the canvas with current viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n     * @return {Boolean} true if object is partially contained within canvas\n     */\n    isPartiallyOnScreen: function(calculate) {\n      if (!this.canvas) {\n        return false;\n      }\n      var pointTL = this.canvas.vptCoords.tl, pointBR = this.canvas.vptCoords.br;\n      if (this.intersectsWithRect(pointTL, pointBR, true, calculate)) {\n        return true;\n      }\n      var allPointsAreOutside = this.getCoords(true, calculate).every(function(point) {\n        return (point.x >= pointBR.x || point.x <= pointTL.x) &&\n        (point.y >= pointBR.y || point.y <= pointTL.y);\n      });\n      return allPointsAreOutside && this._containsCenterOfCanvas(pointTL, pointBR, calculate);\n    },\n\n    /**\n     * Method that returns an object with the object edges in it, given the coordinates of the corners\n     * @private\n     * @param {Object} oCoords Coordinates of the object corners\n     */\n    _getImageLines: function(oCoords) {\n\n      var lines = {\n        topline: {\n          o: oCoords.tl,\n          d: oCoords.tr\n        },\n        rightline: {\n          o: oCoords.tr,\n          d: oCoords.br\n        },\n        bottomline: {\n          o: oCoords.br,\n          d: oCoords.bl\n        },\n        leftline: {\n          o: oCoords.bl,\n          d: oCoords.tl\n        }\n      };\n\n      // // debugging\n      // if (this.canvas.contextTop) {\n      //   this.canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);\n      //   this.canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);\n      //\n      //   this.canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);\n      //   this.canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);\n      //\n      //   this.canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);\n      //   this.canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);\n      //\n      //   this.canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);\n      //   this.canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);\n      // }\n\n      return lines;\n    },\n\n    /**\n     * Helper method to determine how many cross points are between the 4 object edges\n     * and the horizontal line determined by a point on canvas\n     * @private\n     * @param {fabric.Point} point Point to check\n     * @param {Object} lines Coordinates of the object being evaluated\n     */\n    // remove yi, not used but left code here just in case.\n    _findCrossPoints: function(point, lines) {\n      var b1, b2, a1, a2, xi, // yi,\n          xcount = 0,\n          iLine;\n\n      for (var lineKey in lines) {\n        iLine = lines[lineKey];\n        // optimisation 1: line below point. no cross\n        if ((iLine.o.y < point.y) && (iLine.d.y < point.y)) {\n          continue;\n        }\n        // optimisation 2: line above point. no cross\n        if ((iLine.o.y >= point.y) && (iLine.d.y >= point.y)) {\n          continue;\n        }\n        // optimisation 3: vertical line case\n        if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= point.x)) {\n          xi = iLine.o.x;\n          // yi = point.y;\n        }\n        // calculate the intersection point\n        else {\n          b1 = 0;\n          b2 = (iLine.d.y - iLine.o.y) / (iLine.d.x - iLine.o.x);\n          a1 = point.y - b1 * point.x;\n          a2 = iLine.o.y - b2 * iLine.o.x;\n\n          xi = -(a1 - a2) / (b1 - b2);\n          // yi = a1 + b1 * xi;\n        }\n        // dont count xi < point.x cases\n        if (xi >= point.x) {\n          xcount += 1;\n        }\n        // optimisation 4: specific for square images\n        if (xcount === 2) {\n          break;\n        }\n      }\n      return xcount;\n    },\n\n    /**\n     * Returns coordinates of object's bounding rectangle (left, top, width, height)\n     * the box is intended as aligned to axis of canvas.\n     * @param {Boolean} [absolute] use coordinates without viewportTransform\n     * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords / .aCoords\n     * @return {Object} Object with left, top, width, height properties\n     */\n    getBoundingRect: function(absolute, calculate) {\n      var coords = this.getCoords(absolute, calculate);\n      return util.makeBoundingBoxFromPoints(coords);\n    },\n\n    /**\n     * Returns width of an object's bounding box counting transformations\n     * before 2.0 it was named getWidth();\n     * @return {Number} width value\n     */\n    getScaledWidth: function() {\n      return this._getTransformedDimensions().x;\n    },\n\n    /**\n     * Returns height of an object bounding box counting transformations\n     * before 2.0 it was named getHeight();\n     * @return {Number} height value\n     */\n    getScaledHeight: function() {\n      return this._getTransformedDimensions().y;\n    },\n\n    /**\n     * Makes sure the scale is valid and modifies it if necessary\n     * @private\n     * @param {Number} value\n     * @return {Number}\n     */\n    _constrainScale: function(value) {\n      if (Math.abs(value) < this.minScaleLimit) {\n        if (value < 0) {\n          return -this.minScaleLimit;\n        }\n        else {\n          return this.minScaleLimit;\n        }\n      }\n      else if (value === 0) {\n        return 0.0001;\n      }\n      return value;\n    },\n\n    /**\n     * Scales an object (equally by x and y)\n     * @param {Number} value Scale factor\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    scale: function(value) {\n      this._set('scaleX', value);\n      this._set('scaleY', value);\n      return this.setCoords();\n    },\n\n    /**\n     * Scales an object to a given width, with respect to bounding box (scaling by x/y equally)\n     * @param {Number} value New width value\n     * @param {Boolean} absolute ignore viewport\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    scaleToWidth: function(value, absolute) {\n      // adjust to bounding rect factor so that rotated shapes would fit as well\n      var boundingRectFactor = this.getBoundingRect(absolute).width / this.getScaledWidth();\n      return this.scale(value / this.width / boundingRectFactor);\n    },\n\n    /**\n     * Scales an object to a given height, with respect to bounding box (scaling by x/y equally)\n     * @param {Number} value New height value\n     * @param {Boolean} absolute ignore viewport\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    scaleToHeight: function(value, absolute) {\n      // adjust to bounding rect factor so that rotated shapes would fit as well\n      var boundingRectFactor = this.getBoundingRect(absolute).height / this.getScaledHeight();\n      return this.scale(value / this.height / boundingRectFactor);\n    },\n\n    calcLineCoords: function() {\n      var vpt = this.getViewportTransform(),\n          padding = this.padding, angle = degreesToRadians(this.angle),\n          cos = util.cos(angle), sin = util.sin(angle),\n          cosP = cos * padding, sinP = sin * padding, cosPSinP = cosP + sinP,\n          cosPMinusSinP = cosP - sinP, aCoords = this.calcACoords();\n\n      var lineCoords = {\n        tl: transformPoint(aCoords.tl, vpt),\n        tr: transformPoint(aCoords.tr, vpt),\n        bl: transformPoint(aCoords.bl, vpt),\n        br: transformPoint(aCoords.br, vpt),\n      };\n\n      if (padding) {\n        lineCoords.tl.x -= cosPMinusSinP;\n        lineCoords.tl.y -= cosPSinP;\n        lineCoords.tr.x += cosPSinP;\n        lineCoords.tr.y -= cosPMinusSinP;\n        lineCoords.bl.x -= cosPSinP;\n        lineCoords.bl.y += cosPMinusSinP;\n        lineCoords.br.x += cosPMinusSinP;\n        lineCoords.br.y += cosPSinP;\n      }\n\n      return lineCoords;\n    },\n\n    calcOCoords: function() {\n      var rotateMatrix = this._calcRotateMatrix(),\n          translateMatrix = this._calcTranslateMatrix(),\n          vpt = this.getViewportTransform(),\n          startMatrix = multiplyMatrices(vpt, translateMatrix),\n          finalMatrix = multiplyMatrices(startMatrix, rotateMatrix),\n          finalMatrix = multiplyMatrices(finalMatrix, [1 / vpt[0], 0, 0, 1 / vpt[3], 0, 0]),\n          dim = this._calculateCurrentDimensions(),\n          coords = {};\n      this.forEachControl(function(control, key, fabricObject) {\n        coords[key] = control.positionHandler(dim, finalMatrix, fabricObject);\n      });\n\n      // debug code\n      // var canvas = this.canvas;\n      // setTimeout(function() {\n      //   canvas.contextTop.clearRect(0, 0, 700, 700);\n      //   canvas.contextTop.fillStyle = 'green';\n      //   Object.keys(coords).forEach(function(key) {\n      //     var control = coords[key];\n      //     canvas.contextTop.fillRect(control.x, control.y, 3, 3);\n      //   });\n      // }, 50);\n      return coords;\n    },\n\n    calcACoords: function() {\n      var rotateMatrix = this._calcRotateMatrix(),\n          translateMatrix = this._calcTranslateMatrix(),\n          finalMatrix = multiplyMatrices(translateMatrix, rotateMatrix),\n          dim = this._getTransformedDimensions(),\n          w = dim.x / 2, h = dim.y / 2;\n      return {\n        // corners\n        tl: transformPoint({ x: -w, y: -h }, finalMatrix),\n        tr: transformPoint({ x: w, y: -h }, finalMatrix),\n        bl: transformPoint({ x: -w, y: h }, finalMatrix),\n        br: transformPoint({ x: w, y: h }, finalMatrix)\n      };\n    },\n\n    /**\n     * Sets corner and controls position coordinates based on current angle, width and height, left and top.\n     * oCoords are used to find the corners\n     * aCoords are used to quickly find an object on the canvas\n     * lineCoords are used to quickly find object during pointer events.\n     * See {@link https://github.com/fabricjs/fabric.js/wiki/When-to-call-setCoords} and {@link http://fabricjs.com/fabric-gotchas}\n     *\n     * @param {Boolean} [skipCorners] skip calculation of oCoords.\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setCoords: function(skipCorners) {\n      this.aCoords = this.calcACoords();\n      // in case we are in a group, for how the inner group target check works,\n      // lineCoords are exactly aCoords. Since the vpt gets absorbed by the normalized pointer.\n      this.lineCoords = this.group ? this.aCoords : this.calcLineCoords();\n      if (skipCorners) {\n        return this;\n      }\n      // set coordinates of the draggable boxes in the corners used to scale/rotate the image\n      this.oCoords = this.calcOCoords();\n      this._setCornerCoords && this._setCornerCoords();\n      return this;\n    },\n\n    /**\n     * calculate rotation matrix of an object\n     * @return {Array} rotation matrix for the object\n     */\n    _calcRotateMatrix: function() {\n      return util.calcRotateMatrix(this);\n    },\n\n    /**\n     * calculate the translation matrix for an object transform\n     * @return {Array} rotation matrix for the object\n     */\n    _calcTranslateMatrix: function() {\n      var center = this.getCenterPoint();\n      return [1, 0, 0, 1, center.x, center.y];\n    },\n\n    transformMatrixKey: function(skipGroup) {\n      var sep = '_', prefix = '';\n      if (!skipGroup && this.group) {\n        prefix = this.group.transformMatrixKey(skipGroup) + sep;\n      };\n      return prefix + this.top + sep + this.left + sep + this.scaleX + sep + this.scaleY +\n        sep + this.skewX + sep + this.skewY + sep + this.angle + sep + this.originX + sep + this.originY +\n        sep + this.width + sep + this.height + sep + this.strokeWidth + this.flipX + this.flipY;\n    },\n\n    /**\n     * calculate transform matrix that represents the current transformations from the\n     * object's properties.\n     * @param {Boolean} [skipGroup] return transform matrix for object not counting parent transformations\n     * There are some situation in which this is useful to avoid the fake rotation.\n     * @return {Array} transform matrix for the object\n     */\n    calcTransformMatrix: function(skipGroup) {\n      var matrix = this.calcOwnMatrix();\n      if (skipGroup || !this.group) {\n        return matrix;\n      }\n      var key = this.transformMatrixKey(skipGroup), cache = this.matrixCache || (this.matrixCache = {});\n      if (cache.key === key) {\n        return cache.value;\n      }\n      if (this.group) {\n        matrix = multiplyMatrices(this.group.calcTransformMatrix(false), matrix);\n      }\n      cache.key = key;\n      cache.value = matrix;\n      return matrix;\n    },\n\n    /**\n     * calculate transform matrix that represents the current transformations from the\n     * object's properties, this matrix does not include the group transformation\n     * @return {Array} transform matrix for the object\n     */\n    calcOwnMatrix: function() {\n      var key = this.transformMatrixKey(true), cache = this.ownMatrixCache || (this.ownMatrixCache = {});\n      if (cache.key === key) {\n        return cache.value;\n      }\n      var tMatrix = this._calcTranslateMatrix(),\n          options = {\n            angle: this.angle,\n            translateX: tMatrix[4],\n            translateY: tMatrix[5],\n            scaleX: this.scaleX,\n            scaleY: this.scaleY,\n            skewX: this.skewX,\n            skewY: this.skewY,\n            flipX: this.flipX,\n            flipY: this.flipY,\n          };\n      cache.key = key;\n      cache.value = util.composeMatrix(options);\n      return cache.value;\n    },\n\n    /*\n     * Calculate object dimensions from its properties\n     * @private\n     * @return {Object} .x width dimension\n     * @return {Object} .y height dimension\n     */\n    _getNonTransformedDimensions: function() {\n      var strokeWidth = this.strokeWidth,\n          w = this.width + strokeWidth,\n          h = this.height + strokeWidth;\n      return { x: w, y: h };\n    },\n\n    /*\n     * Calculate object bounding box dimensions from its properties scale, skew.\n     * @param {Number} skewX, a value to override current skewX\n     * @param {Number} skewY, a value to override current skewY\n     * @private\n     * @return {Object} .x width dimension\n     * @return {Object} .y height dimension\n     */\n    _getTransformedDimensions: function(skewX, skewY) {\n      if (typeof skewX === 'undefined') {\n        skewX = this.skewX;\n      }\n      if (typeof skewY === 'undefined') {\n        skewY = this.skewY;\n      }\n      var dimensions, dimX, dimY,\n          noSkew = skewX === 0 && skewY === 0;\n\n      if (this.strokeUniform) {\n        dimX = this.width;\n        dimY = this.height;\n      }\n      else {\n        dimensions = this._getNonTransformedDimensions();\n        dimX = dimensions.x;\n        dimY = dimensions.y;\n      }\n      if (noSkew) {\n        return this._finalizeDimensions(dimX * this.scaleX, dimY * this.scaleY);\n      }\n      var bbox = util.sizeAfterTransform(dimX, dimY, {\n        scaleX: this.scaleX,\n        scaleY: this.scaleY,\n        skewX: skewX,\n        skewY: skewY,\n      });\n      return this._finalizeDimensions(bbox.x, bbox.y);\n    },\n\n    /*\n     * Calculate object bounding box dimensions from its properties scale, skew.\n     * @param Number width width of the bbox\n     * @param Number height height of the bbox\n     * @private\n     * @return {Object} .x finalized width dimension\n     * @return {Object} .y finalized height dimension\n     */\n    _finalizeDimensions: function(width, height) {\n      return this.strokeUniform ?\n        { x: width + this.strokeWidth, y: height + this.strokeWidth }\n        :\n        { x: width, y: height };\n    },\n\n    /*\n     * Calculate object dimensions for controls box, including padding and canvas zoom.\n     * and active selection\n     * private\n     */\n    _calculateCurrentDimensions: function()  {\n      var vpt = this.getViewportTransform(),\n          dim = this._getTransformedDimensions(),\n          p = transformPoint(dim, vpt, true);\n      return p.scalarAdd(2 * this.padding);\n    },\n  });\n})();\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n  /**\n   * Moves an object to the bottom of the stack of drawn objects\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  sendToBack: function() {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.sendToBack.call(this.group, this);\n    }\n    else if (this.canvas) {\n      this.canvas.sendToBack(this);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object to the top of the stack of drawn objects\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  bringToFront: function() {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.bringToFront.call(this.group, this);\n    }\n    else if (this.canvas) {\n      this.canvas.bringToFront(this);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object down in stack of drawn objects\n   * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  sendBackwards: function(intersecting) {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.sendBackwards.call(this.group, this, intersecting);\n    }\n    else if (this.canvas) {\n      this.canvas.sendBackwards(this, intersecting);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object up in stack of drawn objects\n   * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  bringForward: function(intersecting) {\n    if (this.group) {\n      fabric.StaticCanvas.prototype.bringForward.call(this.group, this, intersecting);\n    }\n    else if (this.canvas) {\n      this.canvas.bringForward(this, intersecting);\n    }\n    return this;\n  },\n\n  /**\n   * Moves an object to specified level in stack of drawn objects\n   * @param {Number} index New position of object\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  moveTo: function(index) {\n    if (this.group && this.group.type !== 'activeSelection') {\n      fabric.StaticCanvas.prototype.moveTo.call(this.group, this, index);\n    }\n    else if (this.canvas) {\n      this.canvas.moveTo(this, index);\n    }\n    return this;\n  }\n});\n\n\n/* _TO_SVG_START_ */\n(function() {\n  function getSvgColorString(prop, value) {\n    if (!value) {\n      return prop + ': none; ';\n    }\n    else if (value.toLive) {\n      return prop + ': url(#SVGID_' + value.id + '); ';\n    }\n    else {\n      var color = new fabric.Color(value),\n          str = prop + ': ' + color.toRgb() + '; ',\n          opacity = color.getAlpha();\n      if (opacity !== 1) {\n        //change the color in rgb + opacity\n        str += prop + '-opacity: ' + opacity.toString() + '; ';\n      }\n      return str;\n    }\n  }\n\n  var toFixed = fabric.util.toFixed;\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n    /**\n     * Returns styles-string for svg-export\n     * @param {Boolean} skipShadow a boolean to skip shadow filter output\n     * @return {String}\n     */\n    getSvgStyles: function(skipShadow) {\n\n      var fillRule = this.fillRule ? this.fillRule : 'nonzero',\n          strokeWidth = this.strokeWidth ? this.strokeWidth : '0',\n          strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',\n          strokeDashOffset = this.strokeDashOffset ? this.strokeDashOffset : '0',\n          strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',\n          strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',\n          strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',\n          opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1',\n          visibility = this.visible ? '' : ' visibility: hidden;',\n          filter = skipShadow ? '' : this.getSvgFilter(),\n          fill = getSvgColorString('fill', this.fill),\n          stroke = getSvgColorString('stroke', this.stroke);\n\n      return [\n        stroke,\n        'stroke-width: ', strokeWidth, '; ',\n        'stroke-dasharray: ', strokeDashArray, '; ',\n        'stroke-linecap: ', strokeLineCap, '; ',\n        'stroke-dashoffset: ', strokeDashOffset, '; ',\n        'stroke-linejoin: ', strokeLineJoin, '; ',\n        'stroke-miterlimit: ', strokeMiterLimit, '; ',\n        fill,\n        'fill-rule: ', fillRule, '; ',\n        'opacity: ', opacity, ';',\n        filter,\n        visibility\n      ].join('');\n    },\n\n    /**\n     * Returns styles-string for svg-export\n     * @param {Object} style the object from which to retrieve style properties\n     * @param {Boolean} useWhiteSpace a boolean to include an additional attribute in the style.\n     * @return {String}\n     */\n    getSvgSpanStyles: function(style, useWhiteSpace) {\n      var term = '; ';\n      var fontFamily = style.fontFamily ?\n        'font-family: ' + (((style.fontFamily.indexOf('\\'') === -1 && style.fontFamily.indexOf('\"') === -1) ?\n          '\\'' + style.fontFamily  + '\\'' : style.fontFamily)) + term : '';\n      var strokeWidth = style.strokeWidth ? 'stroke-width: ' + style.strokeWidth + term : '',\n          fontFamily = fontFamily,\n          fontSize = style.fontSize ? 'font-size: ' + style.fontSize + 'px' + term : '',\n          fontStyle = style.fontStyle ? 'font-style: ' + style.fontStyle + term : '',\n          fontWeight = style.fontWeight ? 'font-weight: ' + style.fontWeight + term : '',\n          fill = style.fill ? getSvgColorString('fill', style.fill) : '',\n          stroke = style.stroke ? getSvgColorString('stroke', style.stroke) : '',\n          textDecoration = this.getSvgTextDecoration(style),\n          deltaY = style.deltaY ? 'baseline-shift: ' + (-style.deltaY) + '; ' : '';\n      if (textDecoration) {\n        textDecoration = 'text-decoration: ' + textDecoration + term;\n      }\n\n      return [\n        stroke,\n        strokeWidth,\n        fontFamily,\n        fontSize,\n        fontStyle,\n        fontWeight,\n        textDecoration,\n        fill,\n        deltaY,\n        useWhiteSpace ? 'white-space: pre; ' : ''\n      ].join('');\n    },\n\n    /**\n     * Returns text-decoration property for svg-export\n     * @param {Object} style the object from which to retrieve style properties\n     * @return {String}\n     */\n    getSvgTextDecoration: function(style) {\n      return ['overline', 'underline', 'line-through'].filter(function(decoration) {\n        return style[decoration.replace('-', '')];\n      }).join(' ');\n    },\n\n    /**\n     * Returns filter for svg shadow\n     * @return {String}\n     */\n    getSvgFilter: function() {\n      return this.shadow ? 'filter: url(#SVGID_' + this.shadow.id + ');' : '';\n    },\n\n    /**\n     * Returns id attribute for svg output\n     * @return {String}\n     */\n    getSvgCommons: function() {\n      return [\n        this.id ? 'id=\"' + this.id + '\" ' : '',\n        this.clipPath ? 'clip-path=\"url(#' + this.clipPath.clipPathId + ')\" ' : '',\n      ].join('');\n    },\n\n    /**\n     * Returns transform-string for svg-export\n     * @param {Boolean} use the full transform or the single object one.\n     * @return {String}\n     */\n    getSvgTransform: function(full, additionalTransform) {\n      var transform = full ? this.calcTransformMatrix() : this.calcOwnMatrix(),\n          svgTransform = 'transform=\"' + fabric.util.matrixToSVG(transform);\n      return svgTransform +\n        (additionalTransform || '') + '\" ';\n    },\n\n    _setSVGBg: function(textBgRects) {\n      if (this.backgroundColor) {\n        var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n        textBgRects.push(\n          '\\t\\t<rect ',\n          this._getFillAttributes(this.backgroundColor),\n          ' x=\"',\n          toFixed(-this.width / 2, NUM_FRACTION_DIGITS),\n          '\" y=\"',\n          toFixed(-this.height / 2, NUM_FRACTION_DIGITS),\n          '\" width=\"',\n          toFixed(this.width, NUM_FRACTION_DIGITS),\n          '\" height=\"',\n          toFixed(this.height, NUM_FRACTION_DIGITS),\n          '\"></rect>\\n');\n      }\n    },\n\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      return this._createBaseSVGMarkup(this._toSVG(reviver), { reviver: reviver });\n    },\n\n    /**\n     * Returns svg clipPath representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toClipPathSVG: function(reviver) {\n      return '\\t' + this._createBaseClipPathSVGMarkup(this._toSVG(reviver), { reviver: reviver });\n    },\n\n    /**\n     * @private\n     */\n    _createBaseClipPathSVGMarkup: function(objectMarkup, options) {\n      options = options || {};\n      var reviver = options.reviver,\n          additionalTransform = options.additionalTransform || '',\n          commonPieces = [\n            this.getSvgTransform(true, additionalTransform),\n            this.getSvgCommons(),\n          ].join(''),\n          // insert commons in the markup, style and svgCommons\n          index = objectMarkup.indexOf('COMMON_PARTS');\n      objectMarkup[index] = commonPieces;\n      return reviver ? reviver(objectMarkup.join('')) : objectMarkup.join('');\n    },\n\n    /**\n     * @private\n     */\n    _createBaseSVGMarkup: function(objectMarkup, options) {\n      options = options || {};\n      var noStyle = options.noStyle,\n          reviver = options.reviver,\n          styleInfo = noStyle ? '' : 'style=\"' + this.getSvgStyles() + '\" ',\n          shadowInfo = options.withShadow ? 'style=\"' + this.getSvgFilter() + '\" ' : '',\n          clipPath = this.clipPath,\n          vectorEffect = this.strokeUniform ? 'vector-effect=\"non-scaling-stroke\" ' : '',\n          absoluteClipPath = clipPath && clipPath.absolutePositioned,\n          stroke = this.stroke, fill = this.fill, shadow = this.shadow,\n          commonPieces, markup = [], clipPathMarkup,\n          // insert commons in the markup, style and svgCommons\n          index = objectMarkup.indexOf('COMMON_PARTS'),\n          additionalTransform = options.additionalTransform;\n      if (clipPath) {\n        clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;\n        clipPathMarkup = '<clipPath id=\"' + clipPath.clipPathId + '\" >\\n' +\n          clipPath.toClipPathSVG(reviver) +\n          '</clipPath>\\n';\n      }\n      if (absoluteClipPath) {\n        markup.push(\n          '<g ', shadowInfo, this.getSvgCommons(), ' >\\n'\n        );\n      }\n      markup.push(\n        '<g ',\n        this.getSvgTransform(false),\n        !absoluteClipPath ? shadowInfo + this.getSvgCommons() : '',\n        ' >\\n'\n      );\n      commonPieces = [\n        styleInfo,\n        vectorEffect,\n        noStyle ? '' : this.addPaintOrder(), ' ',\n        additionalTransform ? 'transform=\"' + additionalTransform + '\" ' : '',\n      ].join('');\n      objectMarkup[index] = commonPieces;\n      if (fill && fill.toLive) {\n        markup.push(fill.toSVG(this));\n      }\n      if (stroke && stroke.toLive) {\n        markup.push(stroke.toSVG(this));\n      }\n      if (shadow) {\n        markup.push(shadow.toSVG(this));\n      }\n      if (clipPath) {\n        markup.push(clipPathMarkup);\n      }\n      markup.push(objectMarkup.join(''));\n      markup.push('</g>\\n');\n      absoluteClipPath && markup.push('</g>\\n');\n      return reviver ? reviver(markup.join('')) : markup.join('');\n    },\n\n    addPaintOrder: function() {\n      return this.paintFirst !== 'fill' ? ' paint-order=\"' + this.paintFirst + '\" ' : '';\n    }\n  });\n})();\n/* _TO_SVG_END_ */\n\n\n(function() {\n\n  var extend = fabric.util.object.extend,\n      originalSet = 'stateProperties';\n\n  /*\n    Depends on `stateProperties`\n  */\n  function saveProps(origin, destination, props) {\n    var tmpObj = { }, deep = true;\n    props.forEach(function(prop) {\n      tmpObj[prop] = origin[prop];\n    });\n\n    extend(origin[destination], tmpObj, deep);\n  }\n\n  function _isEqual(origValue, currentValue, firstPass) {\n    if (origValue === currentValue) {\n      // if the objects are identical, return\n      return true;\n    }\n    else if (Array.isArray(origValue)) {\n      if (!Array.isArray(currentValue) || origValue.length !== currentValue.length) {\n        return false;\n      }\n      for (var i = 0, len = origValue.length; i < len; i++) {\n        if (!_isEqual(origValue[i], currentValue[i])) {\n          return false;\n        }\n      }\n      return true;\n    }\n    else if (origValue && typeof origValue === 'object') {\n      var keys = Object.keys(origValue), key;\n      if (!currentValue ||\n          typeof currentValue !== 'object' ||\n          (!firstPass && keys.length !== Object.keys(currentValue).length)\n      ) {\n        return false;\n      }\n      for (var i = 0, len = keys.length; i < len; i++) {\n        key = keys[i];\n        // since clipPath is in the statefull cache list and the clipPath objects\n        // would be iterated as an object, this would lead to possible infinite recursion\n        // we do not want to compare those.\n        if (key === 'canvas' || key === 'group') {\n          continue;\n        }\n        if (!_isEqual(origValue[key], currentValue[key])) {\n          return false;\n        }\n      }\n      return true;\n    }\n  }\n\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n    /**\n     * Returns true if object state (one of its state properties) was changed\n     * @param {String} [propertySet] optional name for the set of property we want to save\n     * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called\n     */\n    hasStateChanged: function(propertySet) {\n      propertySet = propertySet || originalSet;\n      var dashedPropertySet = '_' + propertySet;\n      if (Object.keys(this[dashedPropertySet]).length < this[propertySet].length) {\n        return true;\n      }\n      return !_isEqual(this[dashedPropertySet], this, true);\n    },\n\n    /**\n     * Saves state of an object\n     * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n     * @return {fabric.Object} thisArg\n     */\n    saveState: function(options) {\n      var propertySet = options && options.propertySet || originalSet,\n          destination = '_' + propertySet;\n      if (!this[destination]) {\n        return this.setupState(options);\n      }\n      saveProps(this, destination, this[propertySet]);\n      if (options && options.stateProperties) {\n        saveProps(this, destination, options.stateProperties);\n      }\n      return this;\n    },\n\n    /**\n     * Setups state of an object\n     * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n     * @return {fabric.Object} thisArg\n     */\n    setupState: function(options) {\n      options = options || { };\n      var propertySet = options.propertySet || originalSet;\n      options.propertySet = propertySet;\n      this['_' + propertySet] = { };\n      this.saveState(options);\n      return this;\n    }\n  });\n})();\n\n\n(function() {\n\n  var degreesToRadians = fabric.util.degreesToRadians;\n\n  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n    /**\n     * Determines which corner has been clicked\n     * @private\n     * @param {Object} pointer The pointer indicating the mouse position\n     * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found\n     */\n    _findTargetCorner: function(pointer, forTouch) {\n      // objects in group, anykind, are not self modificable,\n      // must not return an hovered corner.\n      if (!this.hasControls || this.group || (!this.canvas || this.canvas._activeObject !== this)) {\n        return false;\n      }\n\n      var ex = pointer.x,\n          ey = pointer.y,\n          xPoints,\n          lines, keys = Object.keys(this.oCoords),\n          j = keys.length - 1, i;\n      this.__corner = 0;\n\n      // cycle in reverse order so we pick first the one on top\n      for (; j >= 0; j--) {\n        i = keys[j];\n        if (!this.isControlVisible(i)) {\n          continue;\n        }\n\n        lines = this._getImageLines(forTouch ? this.oCoords[i].touchCorner : this.oCoords[i].corner);\n        // // debugging\n        //\n        // this.canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);\n        // this.canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);\n        //\n        // this.canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);\n        // this.canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);\n        //\n        // this.canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);\n        // this.canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);\n        //\n        // this.canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);\n        // this.canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);\n\n        xPoints = this._findCrossPoints({ x: ex, y: ey }, lines);\n        if (xPoints !== 0 && xPoints % 2 === 1) {\n          this.__corner = i;\n          return i;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Calls a function for each control. The function gets called,\n     * with the control, the object that is calling the iterator and the control's key\n     * @param {Function} fn function to iterate over the controls over\n     */\n    forEachControl: function(fn) {\n      for (var i in this.controls) {\n        fn(this.controls[i], i, this);\n      };\n    },\n\n    /**\n     * Sets the coordinates of the draggable boxes in the corners of\n     * the image used to scale/rotate it.\n     * note: if we would switch to ROUND corner area, all of this would disappear.\n     * everything would resolve to a single point and a pythagorean theorem for the distance\n     * @private\n     */\n    _setCornerCoords: function() {\n      var coords = this.oCoords;\n\n      for (var control in coords) {\n        var controlObject = this.controls[control];\n        coords[control].corner = controlObject.calcCornerCoords(\n          this.angle, this.cornerSize, coords[control].x, coords[control].y, false);\n        coords[control].touchCorner = controlObject.calcCornerCoords(\n          this.angle, this.touchCornerSize, coords[control].x, coords[control].y, true);\n      }\n    },\n\n    /**\n     * Draws a colored layer behind the object, inside its selection borders.\n     * Requires public options: padding, selectionBackgroundColor\n     * this function is called when the context is transformed\n     * has checks to be skipped when the object is on a staticCanvas\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawSelectionBackground: function(ctx) {\n      if (!this.selectionBackgroundColor ||\n        (this.canvas && !this.canvas.interactive) ||\n        (this.canvas && this.canvas._activeObject !== this)\n      ) {\n        return this;\n      }\n      ctx.save();\n      var center = this.getCenterPoint(), wh = this._calculateCurrentDimensions(),\n          vpt = this.canvas.viewportTransform;\n      ctx.translate(center.x, center.y);\n      ctx.scale(1 / vpt[0], 1 / vpt[3]);\n      ctx.rotate(degreesToRadians(this.angle));\n      ctx.fillStyle = this.selectionBackgroundColor;\n      ctx.fillRect(-wh.x / 2, -wh.y / 2, wh.x, wh.y);\n      ctx.restore();\n      return this;\n    },\n\n    /**\n     * Draws borders of an object's bounding box.\n     * Requires public properties: width, height\n     * Requires public options: padding, borderColor\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @param {Object} styleOverride object to override the object style\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawBorders: function(ctx, styleOverride) {\n      styleOverride = styleOverride || {};\n      var wh = this._calculateCurrentDimensions(),\n          strokeWidth = this.borderScaleFactor,\n          width = wh.x + strokeWidth,\n          height = wh.y + strokeWidth,\n          hasControls = typeof styleOverride.hasControls !== 'undefined' ?\n            styleOverride.hasControls : this.hasControls,\n          shouldStroke = false;\n\n      ctx.save();\n      ctx.strokeStyle = styleOverride.borderColor || this.borderColor;\n      this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray);\n\n      ctx.strokeRect(\n        -width / 2,\n        -height / 2,\n        width,\n        height\n      );\n\n      if (hasControls) {\n        ctx.beginPath();\n        this.forEachControl(function(control, key, fabricObject) {\n          // in this moment, the ctx is centered on the object.\n          // width and height of the above function are the size of the bbox.\n          if (control.withConnection && control.getVisibility(fabricObject, key)) {\n            // reset movement for each control\n            shouldStroke = true;\n            ctx.moveTo(control.x * width, control.y * height);\n            ctx.lineTo(\n              control.x * width + control.offsetX,\n              control.y * height + control.offsetY\n            );\n          }\n        });\n        if (shouldStroke) {\n          ctx.stroke();\n        }\n      }\n      ctx.restore();\n      return this;\n    },\n\n    /**\n     * Draws borders of an object's bounding box when it is inside a group.\n     * Requires public properties: width, height\n     * Requires public options: padding, borderColor\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @param {object} options object representing current object parameters\n     * @param {Object} styleOverride object to override the object style\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawBordersInGroup: function(ctx, options, styleOverride) {\n      styleOverride = styleOverride || {};\n      var bbox = fabric.util.sizeAfterTransform(this.width, this.height, options),\n          strokeWidth = this.strokeWidth,\n          strokeUniform = this.strokeUniform,\n          borderScaleFactor = this.borderScaleFactor,\n          width =\n            bbox.x + strokeWidth * (strokeUniform ? this.canvas.getZoom() : options.scaleX) + borderScaleFactor,\n          height =\n            bbox.y + strokeWidth * (strokeUniform ? this.canvas.getZoom() : options.scaleY) + borderScaleFactor;\n      ctx.save();\n      this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray);\n      ctx.strokeStyle = styleOverride.borderColor || this.borderColor;\n      ctx.strokeRect(\n        -width / 2,\n        -height / 2,\n        width,\n        height\n      );\n\n      ctx.restore();\n      return this;\n    },\n\n    /**\n     * Draws corners of an object's bounding box.\n     * Requires public properties: width, height\n     * Requires public options: cornerSize, padding\n     * @param {CanvasRenderingContext2D} ctx Context to draw on\n     * @param {Object} styleOverride object to override the object style\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    drawControls: function(ctx, styleOverride) {\n      styleOverride = styleOverride || {};\n      ctx.save();\n      var retinaScaling = 1, matrix, p;\n      if (this.canvas) {\n        retinaScaling = this.canvas.getRetinaScaling();\n      }\n      ctx.setTransform(retinaScaling, 0, 0, retinaScaling, 0, 0);\n      ctx.strokeStyle = ctx.fillStyle = styleOverride.cornerColor || this.cornerColor;\n      if (!this.transparentCorners) {\n        ctx.strokeStyle = styleOverride.cornerStrokeColor || this.cornerStrokeColor;\n      }\n      this._setLineDash(ctx, styleOverride.cornerDashArray || this.cornerDashArray);\n      this.setCoords();\n      if (this.group) {\n        // fabricJS does not really support drawing controls inside groups,\n        // this piece of code here helps having at least the control in places.\n        // If an application needs to show some objects as selected because of some UI state\n        // can still call Object._renderControls() on any object they desire, independently of groups.\n        // using no padding, circular controls and hiding the rotating cursor is higly suggested,\n        matrix = this.group.calcTransformMatrix();\n      }\n      this.forEachControl(function(control, key, fabricObject) {\n        p = fabricObject.oCoords[key];\n        if (control.getVisibility(fabricObject, key)) {\n          if (matrix) {\n            p = fabric.util.transformPoint(p, matrix);\n          }\n          control.render(ctx, p.x, p.y, styleOverride, fabricObject);\n        }\n      });\n      ctx.restore();\n\n      return this;\n    },\n\n    /**\n     * Returns true if the specified control is visible, false otherwise.\n     * @param {String} controlKey The key of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n     * @returns {Boolean} true if the specified control is visible, false otherwise\n     */\n    isControlVisible: function(controlKey) {\n      return this.controls[controlKey] && this.controls[controlKey].getVisibility(this, controlKey);\n    },\n\n    /**\n     * Sets the visibility of the specified control.\n     * @param {String} controlKey The key of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n     * @param {Boolean} visible true to set the specified control visible, false otherwise\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setControlVisible: function(controlKey, visible) {\n      if (!this._controlsVisibility) {\n        this._controlsVisibility = {};\n      }\n      this._controlsVisibility[controlKey] = visible;\n      return this;\n    },\n\n    /**\n     * Sets the visibility state of object controls.\n     * @param {Object} [options] Options object\n     * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it\n     * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it\n     * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it\n     * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it\n     * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it\n     * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it\n     * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it\n     * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it\n     * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    setControlsVisibility: function(options) {\n      options || (options = { });\n\n      for (var p in options) {\n        this.setControlVisible(p, options[p]);\n      }\n      return this;\n    },\n\n\n    /**\n     * This callback function is called every time _discardActiveObject or _setActiveObject\n     * try to to deselect this object. If the function returns true, the process is cancelled\n     * @param {Object} [options] options sent from the upper functions\n     * @param {Event} [options.e] event if the process is generated by an event\n     */\n    onDeselect: function() {\n      // implemented by sub-classes, as needed.\n    },\n\n\n    /**\n     * This callback function is called every time _discardActiveObject or _setActiveObject\n     * try to to select this object. If the function returns true, the process is cancelled\n     * @param {Object} [options] options sent from the upper functions\n     * @param {Event} [options.e] event if the process is generated by an event\n     */\n    onSelect: function() {\n      // implemented by sub-classes, as needed.\n    }\n  });\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n  /**\n   * Animation duration (in ms) for fx* methods\n   * @type Number\n   * @default\n   */\n  FX_DURATION: 500,\n\n  /**\n   * Centers object horizontally with animation.\n   * @param {fabric.Object} object Object to center\n   * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.AnimationContext} context\n   */\n  fxCenterObjectH: function (object, callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    return fabric.util.animate({\n      target: this,\n      startValue: object.left,\n      endValue: this.getCenterPoint().x,\n      duration: this.FX_DURATION,\n      onChange: function(value) {\n        object.set('left', value);\n        _this.requestRenderAll();\n        onChange();\n      },\n      onComplete: function() {\n        object.setCoords();\n        onComplete();\n      }\n    });\n  },\n\n  /**\n   * Centers object vertically with animation.\n   * @param {fabric.Object} object Object to center\n   * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.AnimationContext} context\n   */\n  fxCenterObjectV: function (object, callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    return fabric.util.animate({\n      target: this,\n      startValue: object.top,\n      endValue: this.getCenterPoint().y,\n      duration: this.FX_DURATION,\n      onChange: function(value) {\n        object.set('top', value);\n        _this.requestRenderAll();\n        onChange();\n      },\n      onComplete: function() {\n        object.setCoords();\n        onComplete();\n      }\n    });\n  },\n\n  /**\n   * Same as `fabric.Canvas#remove` but animated\n   * @param {fabric.Object} object Object to remove\n   * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.AnimationContext} context\n   */\n  fxRemove: function (object, callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    return fabric.util.animate({\n      target: this,\n      startValue: object.opacity,\n      endValue: 0,\n      duration: this.FX_DURATION,\n      onChange: function(value) {\n        object.set('opacity', value);\n        _this.requestRenderAll();\n        onChange();\n      },\n      onComplete: function () {\n        _this.remove(object);\n        onComplete();\n      }\n    });\n  }\n});\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n  /**\n   * Animates object's properties\n   * @param {String|Object} property Property to animate (if string) or properties to animate (if object)\n   * @param {Number|Object} value Value to animate property to (if string was given first) or options object\n   * @return {fabric.Object} thisArg\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation}\n   * @return {fabric.AnimationContext | fabric.AnimationContext[]} animation context (or an array if passed multiple properties)\n   *\n   * As object — multiple properties\n   *\n   * object.animate({ left: ..., top: ... });\n   * object.animate({ left: ..., top: ... }, { duration: ... });\n   *\n   * As string — one property\n   *\n   * object.animate('left', ...);\n   * object.animate('left', { duration: ... });\n   *\n   */\n  animate: function () {\n    if (arguments[0] && typeof arguments[0] === 'object') {\n      var propsToAnimate = [], prop, skipCallbacks, out = [];\n      for (prop in arguments[0]) {\n        propsToAnimate.push(prop);\n      }\n      for (var i = 0, len = propsToAnimate.length; i < len; i++) {\n        prop = propsToAnimate[i];\n        skipCallbacks = i !== len - 1;\n        out.push(this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks));\n      }\n      return out;\n    }\n    else {\n      return this._animate.apply(this, arguments);\n    }\n  },\n\n  /**\n   * @private\n   * @param {String} property Property to animate\n   * @param {String} to Value to animate to\n   * @param {Object} [options] Options object\n   * @param {Boolean} [skipCallbacks] When true, callbacks like onchange and oncomplete are not invoked\n   */\n  _animate: function(property, to, options, skipCallbacks) {\n    var _this = this, propPair;\n\n    to = to.toString();\n\n    if (!options) {\n      options = { };\n    }\n    else {\n      options = fabric.util.object.clone(options);\n    }\n\n    if (~property.indexOf('.')) {\n      propPair = property.split('.');\n    }\n\n    var propIsColor =\n      _this.colorProperties.indexOf(property) > -1 ||\n      (propPair && _this.colorProperties.indexOf(propPair[1]) > -1);\n\n    var currentValue = propPair\n      ? this.get(propPair[0])[propPair[1]]\n      : this.get(property);\n\n    if (!('from' in options)) {\n      options.from = currentValue;\n    }\n\n    if (!propIsColor) {\n      if (~to.indexOf('=')) {\n        to = currentValue + parseFloat(to.replace('=', ''));\n      }\n      else {\n        to = parseFloat(to);\n      }\n    }\n\n    var _options = {\n      target: this,\n      startValue: options.from,\n      endValue: to,\n      byValue: options.by,\n      easing: options.easing,\n      duration: options.duration,\n      abort: options.abort && function(value, valueProgress, timeProgress) {\n        return options.abort.call(_this, value, valueProgress, timeProgress);\n      },\n      onChange: function (value, valueProgress, timeProgress) {\n        if (propPair) {\n          _this[propPair[0]][propPair[1]] = value;\n        }\n        else {\n          _this.set(property, value);\n        }\n        if (skipCallbacks) {\n          return;\n        }\n        options.onChange && options.onChange(value, valueProgress, timeProgress);\n      },\n      onComplete: function (value, valueProgress, timeProgress) {\n        if (skipCallbacks) {\n          return;\n        }\n\n        _this.setCoords();\n        options.onComplete && options.onComplete(value, valueProgress, timeProgress);\n      }\n    };\n\n    if (propIsColor) {\n      return fabric.util.animateColor(_options.startValue, _options.endValue, _options.duration, _options);\n    }\n    else {\n      return fabric.util.animate(_options);\n    }\n  }\n});\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone,\n      coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 };\n\n  if (fabric.Line) {\n    fabric.warn('fabric.Line is already defined');\n    return;\n  }\n\n  /**\n   * Line class\n   * @class fabric.Line\n   * @extends fabric.Object\n   * @see {@link fabric.Line#initialize} for constructor definition\n   */\n  fabric.Line = fabric.util.createClass(fabric.Object, /** @lends fabric.Line.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'line',\n\n    /**\n     * x value or first line edge\n     * @type Number\n     * @default\n     */\n    x1: 0,\n\n    /**\n     * y value or first line edge\n     * @type Number\n     * @default\n     */\n    y1: 0,\n\n    /**\n     * x value or second line edge\n     * @type Number\n     * @default\n     */\n    x2: 0,\n\n    /**\n     * y value or second line edge\n     * @type Number\n     * @default\n     */\n    y2: 0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('x1', 'x2', 'y1', 'y2'),\n\n    /**\n     * Constructor\n     * @param {Array} [points] Array of points\n     * @param {Object} [options] Options object\n     * @return {fabric.Line} thisArg\n     */\n    initialize: function(points, options) {\n      if (!points) {\n        points = [0, 0, 0, 0];\n      }\n\n      this.callSuper('initialize', options);\n\n      this.set('x1', points[0]);\n      this.set('y1', points[1]);\n      this.set('x2', points[2]);\n      this.set('y2', points[3]);\n\n      this._setWidthHeight(options);\n    },\n\n    /**\n     * @private\n     * @param {Object} [options] Options\n     */\n    _setWidthHeight: function(options) {\n      options || (options = { });\n\n      this.width = Math.abs(this.x2 - this.x1);\n      this.height = Math.abs(this.y2 - this.y1);\n\n      this.left = 'left' in options\n        ? options.left\n        : this._getLeftToOriginX();\n\n      this.top = 'top' in options\n        ? options.top\n        : this._getTopToOriginY();\n    },\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     */\n    _set: function(key, value) {\n      this.callSuper('_set', key, value);\n      if (typeof coordProps[key] !== 'undefined') {\n        this._setWidthHeight();\n      }\n      return this;\n    },\n\n    /**\n     * @private\n     * @return {Number} leftToOriginX Distance from left edge of canvas to originX of Line.\n     */\n    _getLeftToOriginX: makeEdgeToOriginGetter(\n      { // property names\n        origin: 'originX',\n        axis1: 'x1',\n        axis2: 'x2',\n        dimension: 'width'\n      },\n      { // possible values of origin\n        nearest: 'left',\n        center: 'center',\n        farthest: 'right'\n      }\n    ),\n\n    /**\n     * @private\n     * @return {Number} topToOriginY Distance from top edge of canvas to originY of Line.\n     */\n    _getTopToOriginY: makeEdgeToOriginGetter(\n      { // property names\n        origin: 'originY',\n        axis1: 'y1',\n        axis2: 'y2',\n        dimension: 'height'\n      },\n      { // possible values of origin\n        nearest: 'top',\n        center: 'center',\n        farthest: 'bottom'\n      }\n    ),\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      ctx.beginPath();\n\n\n      var p = this.calcLinePoints();\n      ctx.moveTo(p.x1, p.y1);\n      ctx.lineTo(p.x2, p.y2);\n\n      ctx.lineWidth = this.strokeWidth;\n\n      // TODO: test this\n      // make sure setting \"fill\" changes color of a line\n      // (by copying fillStyle to strokeStyle, since line is stroked, not filled)\n      var origStrokeStyle = ctx.strokeStyle;\n      ctx.strokeStyle = this.stroke || ctx.fillStyle;\n      this.stroke && this._renderStroke(ctx);\n      ctx.strokeStyle = origStrokeStyle;\n    },\n\n    /**\n     * This function is an helper for svg import. it returns the center of the object in the svg\n     * untransformed coordinates\n     * @private\n     * @return {Object} center point from element coordinates\n     */\n    _findCenterFromElement: function() {\n      return {\n        x: (this.x1 + this.x2) / 2,\n        y: (this.y1 + this.y2) / 2,\n      };\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @method toObject\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return extend(this.callSuper('toObject', propertiesToInclude), this.calcLinePoints());\n    },\n\n    /*\n     * Calculate object dimensions from its properties\n     * @private\n     */\n    _getNonTransformedDimensions: function() {\n      var dim = this.callSuper('_getNonTransformedDimensions');\n      if (this.strokeLineCap === 'butt') {\n        if (this.width === 0) {\n          dim.y -= this.strokeWidth;\n        }\n        if (this.height === 0) {\n          dim.x -= this.strokeWidth;\n        }\n      }\n      return dim;\n    },\n\n    /**\n     * Recalculates line points given width and height\n     * @private\n     */\n    calcLinePoints: function() {\n      var xMult = this.x1 <= this.x2 ? -1 : 1,\n          yMult = this.y1 <= this.y2 ? -1 : 1,\n          x1 = (xMult * this.width * 0.5),\n          y1 = (yMult * this.height * 0.5),\n          x2 = (xMult * this.width * -0.5),\n          y2 = (yMult * this.height * -0.5);\n\n      return {\n        x1: x1,\n        x2: x2,\n        y1: y1,\n        y2: y2\n      };\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      var p = this.calcLinePoints();\n      return [\n        '<line ', 'COMMON_PARTS',\n        'x1=\"', p.x1,\n        '\" y1=\"', p.y1,\n        '\" x2=\"', p.x2,\n        '\" y2=\"', p.y2,\n        '\" />\\n'\n      ];\n    },\n    /* _TO_SVG_END_ */\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Line.fromElement})\n   * @static\n   * @memberOf fabric.Line\n   * @see http://www.w3.org/TR/SVG/shapes.html#LineElement\n   */\n  fabric.Line.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' '));\n\n  /**\n   * Returns fabric.Line instance from an SVG element\n   * @static\n   * @memberOf fabric.Line\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @param {Function} [callback] callback function invoked after parsing\n   */\n  fabric.Line.fromElement = function(element, callback, options) {\n    options = options || { };\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Line.ATTRIBUTE_NAMES),\n        points = [\n          parsedAttributes.x1 || 0,\n          parsedAttributes.y1 || 0,\n          parsedAttributes.x2 || 0,\n          parsedAttributes.y2 || 0\n        ];\n    callback(new fabric.Line(points, extend(parsedAttributes, options)));\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Line instance from an object representation\n   * @static\n   * @memberOf fabric.Line\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   */\n  fabric.Line.fromObject = function(object, callback) {\n    function _callback(instance) {\n      delete instance.points;\n      callback && callback(instance);\n    };\n    var options = clone(object, true);\n    options.points = [object.x1, object.y1, object.x2, object.y2];\n    fabric.Object._fromObject('Line', options, _callback, 'points');\n  };\n\n  /**\n   * Produces a function that calculates distance from canvas edge to Line origin.\n   */\n  function makeEdgeToOriginGetter(propertyNames, originValues) {\n    var origin = propertyNames.origin,\n        axis1 = propertyNames.axis1,\n        axis2 = propertyNames.axis2,\n        dimension = propertyNames.dimension,\n        nearest = originValues.nearest,\n        center = originValues.center,\n        farthest = originValues.farthest;\n\n    return function() {\n      switch (this.get(origin)) {\n        case nearest:\n          return Math.min(this.get(axis1), this.get(axis2));\n        case center:\n          return Math.min(this.get(axis1), this.get(axis2)) + (0.5 * this.get(dimension));\n        case farthest:\n          return Math.max(this.get(axis1), this.get(axis2));\n      }\n    };\n\n  }\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      degreesToRadians = fabric.util.degreesToRadians;\n\n  if (fabric.Circle) {\n    fabric.warn('fabric.Circle is already defined.');\n    return;\n  }\n\n  /**\n   * Circle class\n   * @class fabric.Circle\n   * @extends fabric.Object\n   * @see {@link fabric.Circle#initialize} for constructor definition\n   */\n  fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'circle',\n\n    /**\n     * Radius of this circle\n     * @type Number\n     * @default\n     */\n    radius: 0,\n\n    /**\n     * degrees of start of the circle.\n     * probably will change to degrees in next major version\n     * @type Number 0 - 359\n     * @default 0\n     */\n    startAngle: 0,\n\n    /**\n     * End angle of the circle\n     * probably will change to degrees in next major version\n     * @type Number 1 - 360\n     * @default 360\n     */\n    endAngle: 360,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('radius', 'startAngle', 'endAngle'),\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     * @return {fabric.Circle} thisArg\n     */\n    _set: function(key, value) {\n      this.callSuper('_set', key, value);\n\n      if (key === 'radius') {\n        this.setRadius(value);\n      }\n\n      return this;\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['radius', 'startAngle', 'endAngle'].concat(propertiesToInclude));\n    },\n\n    /* _TO_SVG_START_ */\n\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      var svgString, x = 0, y = 0,\n          angle = (this.endAngle - this.startAngle) % 360;\n\n      if (angle === 0) {\n        svgString = [\n          '<circle ', 'COMMON_PARTS',\n          'cx=\"' + x + '\" cy=\"' + y + '\" ',\n          'r=\"', this.radius,\n          '\" />\\n'\n        ];\n      }\n      else {\n        var start = degreesToRadians(this.startAngle),\n            end = degreesToRadians(this.endAngle),\n            radius = this.radius,\n            startX = fabric.util.cos(start) * radius,\n            startY = fabric.util.sin(start) * radius,\n            endX = fabric.util.cos(end) * radius,\n            endY = fabric.util.sin(end) * radius,\n            largeFlag = angle > 180 ? '1' : '0';\n        svgString = [\n          '<path d=\"M ' + startX + ' ' + startY,\n          ' A ' + radius + ' ' + radius,\n          ' 0 ', +largeFlag + ' 1', ' ' + endX + ' ' + endY,\n          '\" ', 'COMMON_PARTS', ' />\\n'\n        ];\n      }\n      return svgString;\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render on\n     */\n    _render: function(ctx) {\n      ctx.beginPath();\n      ctx.arc(\n        0,\n        0,\n        this.radius,\n        degreesToRadians(this.startAngle),\n        degreesToRadians(this.endAngle),\n        false\n      );\n      this._renderPaintInOrder(ctx);\n    },\n\n    /**\n     * Returns horizontal radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRadiusX: function() {\n      return this.get('radius') * this.get('scaleX');\n    },\n\n    /**\n     * Returns vertical radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRadiusY: function() {\n      return this.get('radius') * this.get('scaleY');\n    },\n\n    /**\n     * Sets radius of an object (and updates width accordingly)\n     * @return {fabric.Circle} thisArg\n     */\n    setRadius: function(value) {\n      this.radius = value;\n      return this.set('width', value * 2).set('height', value * 2);\n    },\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})\n   * @static\n   * @memberOf fabric.Circle\n   * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement\n   */\n  fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));\n\n  /**\n   * Returns {@link fabric.Circle} instance from an SVG element\n   * @static\n   * @memberOf fabric.Circle\n   * @param {SVGElement} element Element to parse\n   * @param {Function} [callback] Options callback invoked after parsing is finished\n   * @param {Object} [options] Options object\n   * @throws {Error} If value of `r` attribute is missing or invalid\n   */\n  fabric.Circle.fromElement = function(element, callback) {\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);\n\n    if (!isValidRadius(parsedAttributes)) {\n      throw new Error('value of `r` attribute is required and can not be negative');\n    }\n\n    parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.radius;\n    parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.radius;\n    callback(new fabric.Circle(parsedAttributes));\n  };\n\n  /**\n   * @private\n   */\n  function isValidRadius(attributes) {\n    return (('radius' in attributes) && (attributes.radius >= 0));\n  }\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns {@link fabric.Circle} instance from an object representation\n   * @static\n   * @memberOf fabric.Circle\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   * @return {void}\n   */\n  fabric.Circle.fromObject = function(object, callback) {\n    fabric.Object._fromObject('Circle', object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.Triangle) {\n    fabric.warn('fabric.Triangle is already defined');\n    return;\n  }\n\n  /**\n   * Triangle class\n   * @class fabric.Triangle\n   * @extends fabric.Object\n   * @return {fabric.Triangle} thisArg\n   * @see {@link fabric.Triangle#initialize} for constructor definition\n   */\n  fabric.Triangle = fabric.util.createClass(fabric.Object, /** @lends fabric.Triangle.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'triangle',\n\n    /**\n     * Width is set to 100 to compensate the old initialize code that was setting it to 100\n     * @type Number\n     * @default\n     */\n    width: 100,\n\n    /**\n     * Height is set to 100 to compensate the old initialize code that was setting it to 100\n     * @type Number\n     * @default\n     */\n    height: 100,\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      var widthBy2 = this.width / 2,\n          heightBy2 = this.height / 2;\n\n      ctx.beginPath();\n      ctx.moveTo(-widthBy2, heightBy2);\n      ctx.lineTo(0, -heightBy2);\n      ctx.lineTo(widthBy2, heightBy2);\n      ctx.closePath();\n\n      this._renderPaintInOrder(ctx);\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      var widthBy2 = this.width / 2,\n          heightBy2 = this.height / 2,\n          points = [\n            -widthBy2 + ' ' + heightBy2,\n            '0 ' + -heightBy2,\n            widthBy2 + ' ' + heightBy2\n          ].join(',');\n      return [\n        '<polygon ', 'COMMON_PARTS',\n        'points=\"', points,\n        '\" />'\n      ];\n    },\n    /* _TO_SVG_END_ */\n  });\n\n  /**\n   * Returns {@link fabric.Triangle} instance from an object representation\n   * @static\n   * @memberOf fabric.Triangle\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   */\n  fabric.Triangle.fromObject = function(object, callback) {\n    return fabric.Object._fromObject('Triangle', object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      piBy2   = Math.PI * 2;\n\n  if (fabric.Ellipse) {\n    fabric.warn('fabric.Ellipse is already defined.');\n    return;\n  }\n\n  /**\n   * Ellipse class\n   * @class fabric.Ellipse\n   * @extends fabric.Object\n   * @return {fabric.Ellipse} thisArg\n   * @see {@link fabric.Ellipse#initialize} for constructor definition\n   */\n  fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @lends fabric.Ellipse.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'ellipse',\n\n    /**\n     * Horizontal radius\n     * @type Number\n     * @default\n     */\n    rx:   0,\n\n    /**\n     * Vertical radius\n     * @type Number\n     * @default\n     */\n    ry:   0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'),\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @return {fabric.Ellipse} thisArg\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      this.set('rx', options && options.rx || 0);\n      this.set('ry', options && options.ry || 0);\n    },\n\n    /**\n     * @private\n     * @param {String} key\n     * @param {*} value\n     * @return {fabric.Ellipse} thisArg\n     */\n    _set: function(key, value) {\n      this.callSuper('_set', key, value);\n      switch (key) {\n\n        case 'rx':\n          this.rx = value;\n          this.set('width', value * 2);\n          break;\n\n        case 'ry':\n          this.ry = value;\n          this.set('height', value * 2);\n          break;\n\n      }\n      return this;\n    },\n\n    /**\n     * Returns horizontal radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRx: function() {\n      return this.get('rx') * this.get('scaleX');\n    },\n\n    /**\n     * Returns Vertical radius of an object (according to how an object is scaled)\n     * @return {Number}\n     */\n    getRy: function() {\n      return this.get('ry') * this.get('scaleY');\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      return [\n        '<ellipse ', 'COMMON_PARTS',\n        'cx=\"0\" cy=\"0\" ',\n        'rx=\"', this.rx,\n        '\" ry=\"', this.ry,\n        '\" />\\n'\n      ];\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render on\n     */\n    _render: function(ctx) {\n      ctx.beginPath();\n      ctx.save();\n      ctx.transform(1, 0, 0, this.ry / this.rx, 0, 0);\n      ctx.arc(\n        0,\n        0,\n        this.rx,\n        0,\n        piBy2,\n        false);\n      ctx.restore();\n      this._renderPaintInOrder(ctx);\n    },\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Ellipse.fromElement})\n   * @static\n   * @memberOf fabric.Ellipse\n   * @see http://www.w3.org/TR/SVG/shapes.html#EllipseElement\n   */\n  fabric.Ellipse.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy rx ry'.split(' '));\n\n  /**\n   * Returns {@link fabric.Ellipse} instance from an SVG element\n   * @static\n   * @memberOf fabric.Ellipse\n   * @param {SVGElement} element Element to parse\n   * @param {Function} [callback] Options callback invoked after parsing is finished\n   * @return {fabric.Ellipse}\n   */\n  fabric.Ellipse.fromElement = function(element, callback) {\n\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);\n\n    parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.rx;\n    parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.ry;\n    callback(new fabric.Ellipse(parsedAttributes));\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns {@link fabric.Ellipse} instance from an object representation\n   * @static\n   * @memberOf fabric.Ellipse\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as first argument\n   * @return {void}\n   */\n  fabric.Ellipse.fromObject = function(object, callback) {\n    fabric.Object._fromObject('Ellipse', object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend;\n\n  if (fabric.Rect) {\n    fabric.warn('fabric.Rect is already defined');\n    return;\n  }\n\n  /**\n   * Rectangle class\n   * @class fabric.Rect\n   * @extends fabric.Object\n   * @return {fabric.Rect} thisArg\n   * @see {@link fabric.Rect#initialize} for constructor definition\n   */\n  fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ {\n\n    /**\n     * List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged})\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: fabric.Object.prototype.stateProperties.concat('rx', 'ry'),\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'rect',\n\n    /**\n     * Horizontal border radius\n     * @type Number\n     * @default\n     */\n    rx:   0,\n\n    /**\n     * Vertical border radius\n     * @type Number\n     * @default\n     */\n    ry:   0,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'),\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      this._initRxRy();\n    },\n\n    /**\n     * Initializes rx/ry attributes\n     * @private\n     */\n    _initRxRy: function() {\n      if (this.rx && !this.ry) {\n        this.ry = this.rx;\n      }\n      else if (this.ry && !this.rx) {\n        this.rx = this.ry;\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n\n      // 1x1 case (used in spray brush) optimization was removed because\n      // with caching and higher zoom level this makes more damage than help\n\n      var rx = this.rx ? Math.min(this.rx, this.width / 2) : 0,\n          ry = this.ry ? Math.min(this.ry, this.height / 2) : 0,\n          w = this.width,\n          h = this.height,\n          x = -this.width / 2,\n          y = -this.height / 2,\n          isRounded = rx !== 0 || ry !== 0,\n          /* \"magic number\" for bezier approximations of arcs (http://itc.ktu.lt/itc354/Riskus354.pdf) */\n          k = 1 - 0.5522847498;\n      ctx.beginPath();\n\n      ctx.moveTo(x + rx, y);\n\n      ctx.lineTo(x + w - rx, y);\n      isRounded && ctx.bezierCurveTo(x + w - k * rx, y, x + w, y + k * ry, x + w, y + ry);\n\n      ctx.lineTo(x + w, y + h - ry);\n      isRounded && ctx.bezierCurveTo(x + w, y + h - k * ry, x + w - k * rx, y + h, x + w - rx, y + h);\n\n      ctx.lineTo(x + rx, y + h);\n      isRounded && ctx.bezierCurveTo(x + k * rx, y + h, x, y + h - k * ry, x, y + h - ry);\n\n      ctx.lineTo(x, y + ry);\n      isRounded && ctx.bezierCurveTo(x, y + k * ry, x + k * rx, y, x + rx, y);\n\n      ctx.closePath();\n\n      this._renderPaintInOrder(ctx);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      var x = -this.width / 2, y = -this.height / 2;\n      return [\n        '<rect ', 'COMMON_PARTS',\n        'x=\"', x, '\" y=\"', y,\n        '\" rx=\"', this.rx, '\" ry=\"', this.ry,\n        '\" width=\"', this.width, '\" height=\"', this.height,\n        '\" />\\n'\n      ];\n    },\n    /* _TO_SVG_END_ */\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)\n   * @static\n   * @memberOf fabric.Rect\n   * @see: http://www.w3.org/TR/SVG/shapes.html#RectElement\n   */\n  fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));\n\n  /**\n   * Returns {@link fabric.Rect} instance from an SVG element\n   * @static\n   * @memberOf fabric.Rect\n   * @param {SVGElement} element Element to parse\n   * @param {Function} callback callback function invoked after parsing\n   * @param {Object} [options] Options object\n   */\n  fabric.Rect.fromElement = function(element, callback, options) {\n    if (!element) {\n      return callback(null);\n    }\n    options = options || { };\n\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);\n    parsedAttributes.left = parsedAttributes.left || 0;\n    parsedAttributes.top  = parsedAttributes.top  || 0;\n    parsedAttributes.height  = parsedAttributes.height || 0;\n    parsedAttributes.width  = parsedAttributes.width || 0;\n    var rect = new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n    rect.visible = rect.visible && rect.width > 0 && rect.height > 0;\n    callback(rect);\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns {@link fabric.Rect} instance from an object representation\n   * @static\n   * @memberOf fabric.Rect\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Rect instance is created\n   */\n  fabric.Rect.fromObject = function(object, callback) {\n    return fabric.Object._fromObject('Rect', object, callback);\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      min = fabric.util.array.min,\n      max = fabric.util.array.max,\n      toFixed = fabric.util.toFixed,\n      projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;\n\n  if (fabric.Polyline) {\n    fabric.warn('fabric.Polyline is already defined');\n    return;\n  }\n\n  /**\n   * Polyline class\n   * @class fabric.Polyline\n   * @extends fabric.Object\n   * @see {@link fabric.Polyline#initialize} for constructor definition\n   */\n  fabric.Polyline = fabric.util.createClass(fabric.Object, /** @lends fabric.Polyline.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'polyline',\n\n    /**\n     * Points array\n     * @type Array\n     * @default\n     */\n    points: null,\n\n    /**\n     * WARNING: Feature in progress\n     * Calculate the exact bounding box taking in account strokeWidth on acute angles\n     * this will be turned to true by default on fabric 6.0\n     * maybe will be left in as an optimization since calculations may be slow\n     * @deprecated\n     * @type Boolean\n     * @default false\n     */\n    exactBoundingBox: false,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'),\n\n    /**\n     * Constructor\n     * @param {Array} points Array of points (where each point is an object with x and y)\n     * @param {Object} [options] Options object\n     * @return {fabric.Polyline} thisArg\n     * @example\n     * var poly = new fabric.Polyline([\n     *     { x: 10, y: 10 },\n     *     { x: 50, y: 30 },\n     *     { x: 40, y: 70 },\n     *     { x: 60, y: 50 },\n     *     { x: 100, y: 150 },\n     *     { x: 40, y: 100 }\n     *   ], {\n     *   stroke: 'red',\n     *   left: 100,\n     *   top: 100\n     * });\n     */\n    initialize: function(points, options) {\n      options = options || {};\n      this.points = points || [];\n      this.callSuper('initialize', options);\n      this._setPositionDimensions(options);\n    },\n\n    /**\n     * @private\n     */\n    _projectStrokeOnPoints: function () {\n      return projectStrokeOnPoints(this.points, this, true);\n    },\n\n    _setPositionDimensions: function(options) {\n      var calcDim = this._calcDimensions(options), correctLeftTop,\n          correctSize = this.exactBoundingBox ? this.strokeWidth : 0;\n      this.width = calcDim.width - correctSize;\n      this.height = calcDim.height - correctSize;\n      if (!options.fromSVG) {\n        correctLeftTop = this.translateToGivenOrigin(\n          {\n            // this looks bad, but is one way to keep it optional for now.\n            x: calcDim.left - this.strokeWidth / 2 + correctSize / 2,\n            y: calcDim.top - this.strokeWidth / 2 + correctSize / 2\n          },\n          'left',\n          'top',\n          this.originX,\n          this.originY\n        );\n      }\n      if (typeof options.left === 'undefined') {\n        this.left = options.fromSVG ? calcDim.left : correctLeftTop.x;\n      }\n      if (typeof options.top === 'undefined') {\n        this.top = options.fromSVG ? calcDim.top : correctLeftTop.y;\n      }\n      this.pathOffset = {\n        x: calcDim.left + this.width / 2 + correctSize / 2,\n        y: calcDim.top + this.height / 2 + correctSize / 2\n      };\n    },\n\n    /**\n     * Calculate the polygon min and max point from points array,\n     * returning an object with left, top, width, height to measure the\n     * polygon size\n     * @return {Object} object.left X coordinate of the polygon leftmost point\n     * @return {Object} object.top Y coordinate of the polygon topmost point\n     * @return {Object} object.width distance between X coordinates of the polygon leftmost and rightmost point\n     * @return {Object} object.height distance between Y coordinates of the polygon topmost and bottommost point\n     * @private\n     */\n    _calcDimensions: function() {\n\n      var points = this.exactBoundingBox ? this._projectStrokeOnPoints() : this.points,\n          minX = min(points, 'x') || 0,\n          minY = min(points, 'y') || 0,\n          maxX = max(points, 'x') || 0,\n          maxY = max(points, 'y') || 0,\n          width = (maxX - minX),\n          height = (maxY - minY);\n\n      return {\n        left: minX,\n        top: minY,\n        width: width,\n        height: height,\n      };\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return extend(this.callSuper('toObject', propertiesToInclude), {\n        points: this.points.concat()\n      });\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      var points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y,\n          NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n\n      for (var i = 0, len = this.points.length; i < len; i++) {\n        points.push(\n          toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',',\n          toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' '\n        );\n      }\n      return [\n        '<' + this.type + ' ', 'COMMON_PARTS',\n        'points=\"', points.join(''),\n        '\" />\\n'\n      ];\n    },\n    /* _TO_SVG_END_ */\n\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    commonRender: function(ctx) {\n      var point, len = this.points.length,\n          x = this.pathOffset.x,\n          y = this.pathOffset.y;\n\n      if (!len || isNaN(this.points[len - 1].y)) {\n        // do not draw if no points or odd points\n        // NaN comes from parseFloat of a empty string in parser\n        return false;\n      }\n      ctx.beginPath();\n      ctx.moveTo(this.points[0].x - x, this.points[0].y - y);\n      for (var i = 0; i < len; i++) {\n        point = this.points[i];\n        ctx.lineTo(point.x - x, point.y - y);\n      }\n      return true;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      if (!this.commonRender(ctx)) {\n        return;\n      }\n      this._renderPaintInOrder(ctx);\n    },\n\n    /**\n     * Returns complexity of an instance\n     * @return {Number} complexity of this instance\n     */\n    complexity: function() {\n      return this.get('points').length;\n    }\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Polyline.fromElement})\n   * @static\n   * @memberOf fabric.Polyline\n   * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement\n   */\n  fabric.Polyline.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n  /**\n   * Returns fabric.Polyline instance from an SVG element\n   * @static\n   * @memberOf fabric.Polyline\n   * @param {SVGElement} element Element to parser\n   * @param {Function} callback callback function invoked after parsing\n   * @param {Object} [options] Options object\n   */\n  fabric.Polyline.fromElementGenerator = function(_class) {\n    return function(element, callback, options) {\n      if (!element) {\n        return callback(null);\n      }\n      options || (options = { });\n\n      var points = fabric.parsePointsAttribute(element.getAttribute('points')),\n          parsedAttributes = fabric.parseAttributes(element, fabric[_class].ATTRIBUTE_NAMES);\n      parsedAttributes.fromSVG = true;\n      callback(new fabric[_class](points, extend(parsedAttributes, options)));\n    };\n  };\n\n  fabric.Polyline.fromElement = fabric.Polyline.fromElementGenerator('Polyline');\n\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Polyline instance from an object representation\n   * @static\n   * @memberOf fabric.Polyline\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n   */\n  fabric.Polyline.fromObject = function(object, callback) {\n    return fabric.Object._fromObject('Polyline', object, callback, 'points');\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = {}),\n      projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;\n\n  if (fabric.Polygon) {\n    fabric.warn('fabric.Polygon is already defined');\n    return;\n  }\n\n  /**\n   * Polygon class\n   * @class fabric.Polygon\n   * @extends fabric.Polyline\n   * @see {@link fabric.Polygon#initialize} for constructor definition\n   */\n  fabric.Polygon = fabric.util.createClass(fabric.Polyline, /** @lends fabric.Polygon.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'polygon',\n\n    /**\n     * @private\n     */\n    _projectStrokeOnPoints: function () {\n      return projectStrokeOnPoints(this.points, this);\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      if (!this.commonRender(ctx)) {\n        return;\n      }\n      ctx.closePath();\n      this._renderPaintInOrder(ctx);\n    },\n\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`)\n   * @static\n   * @memberOf fabric.Polygon\n   * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement\n   */\n  fabric.Polygon.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n  /**\n   * Returns {@link fabric.Polygon} instance from an SVG element\n   * @static\n   * @memberOf fabric.Polygon\n   * @param {SVGElement} element Element to parse\n   * @param {Function} callback callback function invoked after parsing\n   * @param {Object} [options] Options object\n   */\n  fabric.Polygon.fromElement = fabric.Polyline.fromElementGenerator('Polygon');\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Polygon instance from an object representation\n   * @static\n   * @memberOf fabric.Polygon\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n   * @return {void}\n   */\n  fabric.Polygon.fromObject = function(object, callback) {\n    fabric.Object._fromObject('Polygon', object, callback, 'points');\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      min = fabric.util.array.min,\n      max = fabric.util.array.max,\n      extend = fabric.util.object.extend,\n      clone = fabric.util.object.clone,\n      toFixed = fabric.util.toFixed;\n\n  if (fabric.Path) {\n    fabric.warn('fabric.Path is already defined');\n    return;\n  }\n\n  /**\n   * Path class\n   * @class fabric.Path\n   * @extends fabric.Object\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup}\n   * @see {@link fabric.Path#initialize} for constructor definition\n   */\n  fabric.Path = fabric.util.createClass(fabric.Object, /** @lends fabric.Path.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'path',\n\n    /**\n     * Array of path points\n     * @type Array\n     * @default\n     */\n    path: null,\n\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('path', 'fillRule'),\n\n    stateProperties: fabric.Object.prototype.stateProperties.concat('path'),\n\n    /**\n     * Constructor\n     * @param {Array|String} path Path data (sequence of coordinates and corresponding \"command\" tokens)\n     * @param {Object} [options] Options object\n     * @return {fabric.Path} thisArg\n     */\n    initialize: function (path, options) {\n      options = clone(options || {});\n      delete options.path;\n      this.callSuper('initialize', options);\n      this._setPath(path || [], options);\n    },\n\n    /**\n    * @private\n    * @param {Array|String} path Path data (sequence of coordinates and corresponding \"command\" tokens)\n    * @param {Object} [options] Options object\n    */\n    _setPath: function (path, options) {\n      this.path = fabric.util.makePathSimpler(\n        Array.isArray(path) ? path : fabric.util.parsePath(path)\n      );\n\n      fabric.Polyline.prototype._setPositionDimensions.call(this, options || {});\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render path on\n     */\n    _renderPathCommands: function(ctx) {\n      var current, // current instruction\n          subpathStartX = 0,\n          subpathStartY = 0,\n          x = 0, // current x\n          y = 0, // current y\n          controlX = 0, // current control point x\n          controlY = 0, // current control point y\n          l = -this.pathOffset.x,\n          t = -this.pathOffset.y;\n\n      ctx.beginPath();\n\n      for (var i = 0, len = this.path.length; i < len; ++i) {\n\n        current = this.path[i];\n\n        switch (current[0]) { // first letter\n\n          case 'L': // lineto, absolute\n            x = current[1];\n            y = current[2];\n            ctx.lineTo(x + l, y + t);\n            break;\n\n          case 'M': // moveTo, absolute\n            x = current[1];\n            y = current[2];\n            subpathStartX = x;\n            subpathStartY = y;\n            ctx.moveTo(x + l, y + t);\n            break;\n\n          case 'C': // bezierCurveTo, absolute\n            x = current[5];\n            y = current[6];\n            controlX = current[3];\n            controlY = current[4];\n            ctx.bezierCurveTo(\n              current[1] + l,\n              current[2] + t,\n              controlX + l,\n              controlY + t,\n              x + l,\n              y + t\n            );\n            break;\n\n          case 'Q': // quadraticCurveTo, absolute\n            ctx.quadraticCurveTo(\n              current[1] + l,\n              current[2] + t,\n              current[3] + l,\n              current[4] + t\n            );\n            x = current[3];\n            y = current[4];\n            controlX = current[1];\n            controlY = current[2];\n            break;\n\n          case 'z':\n          case 'Z':\n            x = subpathStartX;\n            y = subpathStartY;\n            ctx.closePath();\n            break;\n        }\n      }\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx context to render path on\n     */\n    _render: function(ctx) {\n      this._renderPathCommands(ctx);\n      this._renderPaintInOrder(ctx);\n    },\n\n    /**\n     * Returns string representation of an instance\n     * @return {String} string representation of an instance\n     */\n    toString: function() {\n      return '#<fabric.Path (' + this.complexity() +\n        '): { \"top\": ' + this.top + ', \"left\": ' + this.left + ' }>';\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return extend(this.callSuper('toObject', propertiesToInclude), {\n        path: this.path.map(function(item) { return item.slice(); }),\n      });\n    },\n\n    /**\n     * Returns dataless object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toDatalessObject: function(propertiesToInclude) {\n      var o = this.toObject(['sourcePath'].concat(propertiesToInclude));\n      if (o.sourcePath) {\n        delete o.path;\n      }\n      return o;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      var path = fabric.util.joinPath(this.path);\n      return [\n        '<path ', 'COMMON_PARTS',\n        'd=\"', path,\n        '\" stroke-linecap=\"round\" ',\n        '/>\\n'\n      ];\n    },\n\n    _getOffsetTransform: function() {\n      var digits = fabric.Object.NUM_FRACTION_DIGITS;\n      return ' translate(' + toFixed(-this.pathOffset.x, digits) + ', ' +\n          toFixed(-this.pathOffset.y, digits) + ')';\n    },\n\n    /**\n     * Returns svg clipPath representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toClipPathSVG: function(reviver) {\n      var additionalTransform = this._getOffsetTransform();\n      return '\\t' + this._createBaseClipPathSVGMarkup(\n        this._toSVG(), { reviver: reviver, additionalTransform: additionalTransform }\n      );\n    },\n\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var additionalTransform = this._getOffsetTransform();\n      return this._createBaseSVGMarkup(this._toSVG(), { reviver: reviver, additionalTransform: additionalTransform  });\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns number representation of an instance complexity\n     * @return {Number} complexity of this instance\n     */\n    complexity: function() {\n      return this.path.length;\n    },\n\n    /**\n     * @private\n     */\n    _calcDimensions: function() {\n\n      var aX = [],\n          aY = [],\n          current, // current instruction\n          subpathStartX = 0,\n          subpathStartY = 0,\n          x = 0, // current x\n          y = 0, // current y\n          bounds;\n\n      for (var i = 0, len = this.path.length; i < len; ++i) {\n\n        current = this.path[i];\n\n        switch (current[0]) { // first letter\n\n          case 'L': // lineto, absolute\n            x = current[1];\n            y = current[2];\n            bounds = [];\n            break;\n\n          case 'M': // moveTo, absolute\n            x = current[1];\n            y = current[2];\n            subpathStartX = x;\n            subpathStartY = y;\n            bounds = [];\n            break;\n\n          case 'C': // bezierCurveTo, absolute\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              current[1],\n              current[2],\n              current[3],\n              current[4],\n              current[5],\n              current[6]\n            );\n            x = current[5];\n            y = current[6];\n            break;\n\n          case 'Q': // quadraticCurveTo, absolute\n            bounds = fabric.util.getBoundsOfCurve(x, y,\n              current[1],\n              current[2],\n              current[1],\n              current[2],\n              current[3],\n              current[4]\n            );\n            x = current[3];\n            y = current[4];\n            break;\n\n          case 'z':\n          case 'Z':\n            x = subpathStartX;\n            y = subpathStartY;\n            break;\n        }\n        bounds.forEach(function (point) {\n          aX.push(point.x);\n          aY.push(point.y);\n        });\n        aX.push(x);\n        aY.push(y);\n      }\n\n      var minX = min(aX) || 0,\n          minY = min(aY) || 0,\n          maxX = max(aX) || 0,\n          maxY = max(aY) || 0,\n          deltaX = maxX - minX,\n          deltaY = maxY - minY;\n\n      return {\n        left: minX,\n        top: minY,\n        width: deltaX,\n        height: deltaY\n      };\n    }\n  });\n\n  /**\n   * Creates an instance of fabric.Path from an object\n   * @static\n   * @memberOf fabric.Path\n   * @param {Object} object\n   * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n   */\n  fabric.Path.fromObject = function(object, callback) {\n    if (typeof object.sourcePath === 'string') {\n      var pathUrl = object.sourcePath;\n      fabric.loadSVGFromURL(pathUrl, function (elements) {\n        var path = elements[0];\n        path.setOptions(object);\n        if (object.clipPath) {\n          fabric.util.enlivenObjects([object.clipPath], function(elivenedObjects) {\n            path.clipPath = elivenedObjects[0];\n            callback && callback(path);\n          });\n        }\n        else {\n          callback && callback(path);\n        }\n      });\n    }\n    else {\n      fabric.Object._fromObject('Path', object, callback, 'path');\n    }\n  };\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by `fabric.Path.fromElement`)\n   * @static\n   * @memberOf fabric.Path\n   * @see http://www.w3.org/TR/SVG/paths.html#PathElement\n   */\n  fabric.Path.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(['d']);\n\n  /**\n   * Creates an instance of fabric.Path from an SVG <path> element\n   * @static\n   * @memberOf fabric.Path\n   * @param {SVGElement} element to parse\n   * @param {Function} callback Callback to invoke when an fabric.Path instance is created\n   * @param {Object} [options] Options object\n   * @param {Function} [callback] Options callback invoked after parsing is finished\n   */\n  fabric.Path.fromElement = function(element, callback, options) {\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES);\n    parsedAttributes.fromSVG = true;\n    callback(new fabric.Path(parsedAttributes.d, extend(parsedAttributes, options)));\n  };\n  /* _FROM_SVG_END_ */\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      min = fabric.util.array.min,\n      max = fabric.util.array.max;\n\n  if (fabric.Group) {\n    return;\n  }\n\n  /**\n   * Group class\n   * @class fabric.Group\n   * @extends fabric.Object\n   * @mixes fabric.Collection\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#groups}\n   * @see {@link fabric.Group#initialize} for constructor definition\n   */\n  fabric.Group = fabric.util.createClass(fabric.Object, fabric.Collection, /** @lends fabric.Group.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'group',\n\n    /**\n     * Width of stroke\n     * @type Number\n     * @default\n     */\n    strokeWidth: 0,\n\n    /**\n     * Indicates if click, mouseover, mouseout events & hoverCursor should also check for subtargets\n     * @type Boolean\n     * @default\n     */\n    subTargetCheck: false,\n\n    /**\n     * Groups are container, do not render anything on theyr own, ence no cache properties\n     * @type Array\n     * @default\n     */\n    cacheProperties: [],\n\n    /**\n     * setOnGroup is a method used for TextBox that is no more used since 2.0.0 The behavior is still\n     * available setting this boolean to true.\n     * @type Boolean\n     * @since 2.0.0\n     * @default\n     */\n    useSetOnGroup: false,\n\n    /**\n     * Constructor\n     * @param {Object} objects Group objects\n     * @param {Object} [options] Options object\n     * @param {Boolean} [isAlreadyGrouped] if true, objects have been grouped already.\n     * @return {Object} thisArg\n     */\n    initialize: function(objects, options, isAlreadyGrouped) {\n      options = options || {};\n      this._objects = [];\n      // if objects enclosed in a group have been grouped already,\n      // we cannot change properties of objects.\n      // Thus we need to set options to group without objects,\n      isAlreadyGrouped && this.callSuper('initialize', options);\n      this._objects = objects || [];\n      for (var i = this._objects.length; i--; ) {\n        this._objects[i].group = this;\n      }\n\n      if (!isAlreadyGrouped) {\n        var center = options && options.centerPoint;\n        // we want to set origins before calculating the bounding box.\n        // so that the topleft can be set with that in mind.\n        // if specific top and left are passed, are overwritten later\n        // with the callSuper('initialize', options)\n        if (options.originX !== undefined) {\n          this.originX = options.originX;\n        }\n        if (options.originY !== undefined) {\n          this.originY = options.originY;\n        }\n        // if coming from svg i do not want to calc bounds.\n        // i assume width and height are passed along options\n        center || this._calcBounds();\n        this._updateObjectsCoords(center);\n        delete options.centerPoint;\n        this.callSuper('initialize', options);\n      }\n      else {\n        this._updateObjectsACoords();\n      }\n\n      this.setCoords();\n    },\n\n    /**\n     * @private\n     */\n    _updateObjectsACoords: function() {\n      var skipControls = true;\n      for (var i = this._objects.length; i--; ){\n        this._objects[i].setCoords(skipControls);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Boolean} [skipCoordsChange] if true, coordinates of objects enclosed in a group do not change\n     */\n    _updateObjectsCoords: function(center) {\n      var center = center || this.getCenterPoint();\n      for (var i = this._objects.length; i--; ){\n        this._updateObjectCoords(this._objects[i], center);\n      }\n    },\n\n    /**\n     * @private\n     * @param {Object} object\n     * @param {fabric.Point} center, current center of group.\n     */\n    _updateObjectCoords: function(object, center) {\n      var objectLeft = object.left,\n          objectTop = object.top,\n          skipControls = true;\n\n      object.set({\n        left: objectLeft - center.x,\n        top: objectTop - center.y\n      });\n      object.group = this;\n      object.setCoords(skipControls);\n    },\n\n    /**\n     * Returns string represenation of a group\n     * @return {String}\n     */\n    toString: function() {\n      return '#<fabric.Group: (' + this.complexity() + ')>';\n    },\n\n    /**\n     * Adds an object to a group; Then recalculates group's dimension, position.\n     * @param {Object} object\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    addWithUpdate: function(object) {\n      var nested = !!this.group;\n      this._restoreObjectsState();\n      fabric.util.resetObjectTransform(this);\n      if (object) {\n        if (nested) {\n          // if this group is inside another group, we need to pre transform the object\n          fabric.util.removeTransformFromObject(object, this.group.calcTransformMatrix());\n        }\n        this._objects.push(object);\n        object.group = this;\n        object._set('canvas', this.canvas);\n      }\n      this._calcBounds();\n      this._updateObjectsCoords();\n      this.dirty = true;\n      if (nested) {\n        this.group.addWithUpdate();\n      }\n      else {\n        this.setCoords();\n      }\n      return this;\n    },\n\n    /**\n     * Removes an object from a group; Then recalculates group's dimension, position.\n     * @param {Object} object\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    removeWithUpdate: function(object) {\n      this._restoreObjectsState();\n      fabric.util.resetObjectTransform(this);\n\n      this.remove(object);\n      this._calcBounds();\n      this._updateObjectsCoords();\n      this.setCoords();\n      this.dirty = true;\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _onObjectAdded: function(object) {\n      this.dirty = true;\n      object.group = this;\n      object._set('canvas', this.canvas);\n    },\n\n    /**\n     * @private\n     */\n    _onObjectRemoved: function(object) {\n      this.dirty = true;\n      delete object.group;\n    },\n\n    /**\n     * @private\n     */\n    _set: function(key, value) {\n      var i = this._objects.length;\n      if (this.useSetOnGroup) {\n        while (i--) {\n          this._objects[i].setOnGroup(key, value);\n        }\n      }\n      if (key === 'canvas') {\n        while (i--) {\n          this._objects[i]._set(key, value);\n        }\n      }\n      fabric.Object.prototype._set.call(this, key, value);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var _includeDefaultValues = this.includeDefaultValues;\n      var objsToObject = this._objects\n        .filter(function (obj) {\n          return !obj.excludeFromExport;\n        })\n        .map(function (obj) {\n          var originalDefaults = obj.includeDefaultValues;\n          obj.includeDefaultValues = _includeDefaultValues;\n          var _obj = obj.toObject(propertiesToInclude);\n          obj.includeDefaultValues = originalDefaults;\n          return _obj;\n        });\n      var obj = fabric.Object.prototype.toObject.call(this, propertiesToInclude);\n      obj.objects = objsToObject;\n      return obj;\n    },\n\n    /**\n     * Returns object representation of an instance, in dataless mode.\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toDatalessObject: function(propertiesToInclude) {\n      var objsToObject, sourcePath = this.sourcePath;\n      if (sourcePath) {\n        objsToObject = sourcePath;\n      }\n      else {\n        var _includeDefaultValues = this.includeDefaultValues;\n        objsToObject = this._objects.map(function(obj) {\n          var originalDefaults = obj.includeDefaultValues;\n          obj.includeDefaultValues = _includeDefaultValues;\n          var _obj = obj.toDatalessObject(propertiesToInclude);\n          obj.includeDefaultValues = originalDefaults;\n          return _obj;\n        });\n      }\n      var obj = fabric.Object.prototype.toDatalessObject.call(this, propertiesToInclude);\n      obj.objects = objsToObject;\n      return obj;\n    },\n\n    /**\n     * Renders instance on a given context\n     * @param {CanvasRenderingContext2D} ctx context to render instance on\n     */\n    render: function(ctx) {\n      this._transformDone = true;\n      this.callSuper('render', ctx);\n      this._transformDone = false;\n    },\n\n    /**\n     * Decide if the object should cache or not. Create its own cache level\n     * needsItsOwnCache should be used when the object drawing method requires\n     * a cache step. None of the fabric classes requires it.\n     * Generally you do not cache objects in groups because the group is already cached.\n     * @return {Boolean}\n     */\n    shouldCache: function() {\n      var ownCache = fabric.Object.prototype.shouldCache.call(this);\n      if (ownCache) {\n        for (var i = 0, len = this._objects.length; i < len; i++) {\n          if (this._objects[i].willDrawShadow()) {\n            this.ownCaching = false;\n            return false;\n          }\n        }\n      }\n      return ownCache;\n    },\n\n    /**\n     * Check if this object or a child object will cast a shadow\n     * @return {Boolean}\n     */\n    willDrawShadow: function() {\n      if (fabric.Object.prototype.willDrawShadow.call(this)) {\n        return true;\n      }\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        if (this._objects[i].willDrawShadow()) {\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Check if this group or its parent group are caching, recursively up\n     * @return {Boolean}\n     */\n    isOnACache: function() {\n      return this.ownCaching || (this.group && this.group.isOnACache());\n    },\n\n    /**\n     * Execute the drawing operation for an object on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    drawObject: function(ctx) {\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        this._objects[i].render(ctx);\n      }\n      this._drawClipPath(ctx, this.clipPath);\n    },\n\n    /**\n     * Check if cache is dirty\n     */\n    isCacheDirty: function(skipCanvas) {\n      if (this.callSuper('isCacheDirty', skipCanvas)) {\n        return true;\n      }\n      if (!this.statefullCache) {\n        return false;\n      }\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        if (this._objects[i].isCacheDirty(true)) {\n          if (this._cacheCanvas) {\n            // if this group has not a cache canvas there is nothing to clean\n            var x = this.cacheWidth / this.zoomX, y = this.cacheHeight / this.zoomY;\n            this._cacheContext.clearRect(-x / 2, -y / 2, x, y);\n          }\n          return true;\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Restores original state of each of group objects (original state is that which was before group was created).\n     * if the nested boolean is true, the original state will be restored just for the\n     * first group and not for all the group chain\n     * @private\n     * @param {Boolean} nested tell the function to restore object state up to the parent group and not more\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    _restoreObjectsState: function() {\n      var groupMatrix = this.calcOwnMatrix();\n      this._objects.forEach(function(object) {\n        // instead of using _this = this;\n        fabric.util.addTransformToObject(object, groupMatrix);\n        delete object.group;\n        object.setCoords();\n      });\n      return this;\n    },\n\n    /**\n     * Destroys a group (restoring state of its objects)\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    destroy: function() {\n      // when group is destroyed objects needs to get a repaint to be eventually\n      // displayed on canvas.\n      this._objects.forEach(function(object) {\n        object.set('dirty', true);\n      });\n      return this._restoreObjectsState();\n    },\n\n    dispose: function () {\n      this.callSuper('dispose');\n      this.forEachObject(function (object) {\n        object.dispose && object.dispose();\n      });\n      this._objects = [];\n    },\n\n    /**\n     * make a group an active selection, remove the group from canvas\n     * the group has to be on canvas for this to work.\n     * @return {fabric.ActiveSelection} thisArg\n     * @chainable\n     */\n    toActiveSelection: function() {\n      if (!this.canvas) {\n        return;\n      }\n      var objects = this._objects, canvas = this.canvas;\n      this._objects = [];\n      var options = this.toObject();\n      delete options.objects;\n      var activeSelection = new fabric.ActiveSelection([]);\n      activeSelection.set(options);\n      activeSelection.type = 'activeSelection';\n      canvas.remove(this);\n      objects.forEach(function(object) {\n        object.group = activeSelection;\n        object.dirty = true;\n        canvas.add(object);\n      });\n      activeSelection.canvas = canvas;\n      activeSelection._objects = objects;\n      canvas._activeObject = activeSelection;\n      activeSelection.setCoords();\n      return activeSelection;\n    },\n\n    /**\n     * Destroys a group (restoring state of its objects)\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    ungroupOnCanvas: function() {\n      return this._restoreObjectsState();\n    },\n\n    /**\n     * Sets coordinates of all objects inside group\n     * @return {fabric.Group} thisArg\n     * @chainable\n     */\n    setObjectsCoords: function() {\n      var skipControls = true;\n      this.forEachObject(function(object) {\n        object.setCoords(skipControls);\n      });\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _calcBounds: function(onlyWidthHeight) {\n      var aX = [],\n          aY = [],\n          o, prop, coords,\n          props = ['tr', 'br', 'bl', 'tl'],\n          i = 0, iLen = this._objects.length,\n          j, jLen = props.length;\n\n      for ( ; i < iLen; ++i) {\n        o = this._objects[i];\n        coords = o.calcACoords();\n        for (j = 0; j < jLen; j++) {\n          prop = props[j];\n          aX.push(coords[prop].x);\n          aY.push(coords[prop].y);\n        }\n        o.aCoords = coords;\n      }\n\n      this._getBounds(aX, aY, onlyWidthHeight);\n    },\n\n    /**\n     * @private\n     */\n    _getBounds: function(aX, aY, onlyWidthHeight) {\n      var minXY = new fabric.Point(min(aX), min(aY)),\n          maxXY = new fabric.Point(max(aX), max(aY)),\n          top = minXY.y || 0, left = minXY.x || 0,\n          width = (maxXY.x - minXY.x) || 0,\n          height = (maxXY.y - minXY.y) || 0;\n      this.width = width;\n      this.height = height;\n      if (!onlyWidthHeight) {\n        // the bounding box always finds the topleft most corner.\n        // whatever is the group origin, we set up here the left/top position.\n        this.setPositionByOrigin({ x: left, y: top }, 'left', 'top');\n      }\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    _toSVG: function(reviver) {\n      var svgString = ['<g ', 'COMMON_PARTS', ' >\\n'];\n\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        svgString.push('\\t\\t', this._objects[i].toSVG(reviver));\n      }\n      svgString.push('</g>\\n');\n      return svgString;\n    },\n\n    /**\n     * Returns styles-string for svg-export, specific version for group\n     * @return {String}\n     */\n    getSvgStyles: function() {\n      var opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ?\n            'opacity: ' + this.opacity + ';' : '',\n          visibility = this.visible ? '' : ' visibility: hidden;';\n      return [\n        opacity,\n        this.getSvgFilter(),\n        visibility\n      ].join('');\n    },\n\n    /**\n     * Returns svg clipPath representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toClipPathSVG: function(reviver) {\n      var svgString = [];\n\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        svgString.push('\\t', this._objects[i].toClipPathSVG(reviver));\n      }\n\n      return this._createBaseClipPathSVGMarkup(svgString, { reviver: reviver });\n    },\n    /* _TO_SVG_END_ */\n  });\n\n  /**\n   * Returns {@link fabric.Group} instance from an object representation\n   * @static\n   * @memberOf fabric.Group\n   * @param {Object} object Object to create a group from\n   * @param {Function} [callback] Callback to invoke when an group instance is created\n   */\n  fabric.Group.fromObject = function(object, callback) {\n    var objects = object.objects,\n        options = fabric.util.object.clone(object, true);\n    delete options.objects;\n    if (typeof objects === 'string') {\n      // it has to be an url or something went wrong.\n      fabric.loadSVGFromURL(objects, function (elements) {\n        var group = fabric.util.groupSVGElements(elements, object, objects);\n        var clipPath = options.clipPath;\n        delete options.clipPath;\n        group.set(options);\n        if (clipPath) {\n          fabric.util.enlivenObjects([clipPath], function(elivenedObjects) {\n            group.clipPath = elivenedObjects[0];\n            callback && callback(group);\n          });\n        }\n        else {\n          callback && callback(group);\n        }\n      });\n      return;\n    }\n    fabric.util.enlivenObjects(objects, function (enlivenedObjects) {\n      fabric.util.enlivenObjectEnlivables(object, options, function () {\n        callback && callback(new fabric.Group(enlivenedObjects, options, true));\n      });\n    });\n  };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { });\n\n  if (fabric.ActiveSelection) {\n    return;\n  }\n\n  /**\n   * Group class\n   * @class fabric.ActiveSelection\n   * @extends fabric.Group\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#groups}\n   * @see {@link fabric.ActiveSelection#initialize} for constructor definition\n   */\n  fabric.ActiveSelection = fabric.util.createClass(fabric.Group, /** @lends fabric.ActiveSelection.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'activeSelection',\n\n    /**\n     * Constructor\n     * @param {Object} objects ActiveSelection objects\n     * @param {Object} [options] Options object\n     * @return {Object} thisArg\n     */\n    initialize: function(objects, options) {\n      options = options || {};\n      this._objects = objects || [];\n      for (var i = this._objects.length; i--; ) {\n        this._objects[i].group = this;\n      }\n\n      if (options.originX) {\n        this.originX = options.originX;\n      }\n      if (options.originY) {\n        this.originY = options.originY;\n      }\n      this._calcBounds();\n      this._updateObjectsCoords();\n      fabric.Object.prototype.initialize.call(this, options);\n      this.setCoords();\n    },\n\n    /**\n     * Change te activeSelection to a normal group,\n     * High level function that automatically adds it to canvas as\n     * active object. no events fired.\n     * @since 2.0.0\n     * @return {fabric.Group}\n     */\n    toGroup: function() {\n      var objects = this._objects.concat();\n      this._objects = [];\n      var options = fabric.Object.prototype.toObject.call(this);\n      var newGroup = new fabric.Group([]);\n      delete options.type;\n      newGroup.set(options);\n      objects.forEach(function(object) {\n        object.canvas.remove(object);\n        object.group = newGroup;\n      });\n      newGroup._objects = objects;\n      if (!this.canvas) {\n        return newGroup;\n      }\n      var canvas = this.canvas;\n      canvas.add(newGroup);\n      canvas._activeObject = newGroup;\n      newGroup.setCoords();\n      return newGroup;\n    },\n\n    /**\n     * If returns true, deselection is cancelled.\n     * @since 2.0.0\n     * @return {Boolean} [cancel]\n     */\n    onDeselect: function() {\n      this.destroy();\n      return false;\n    },\n\n    /**\n     * Returns string representation of a group\n     * @return {String}\n     */\n    toString: function() {\n      return '#<fabric.ActiveSelection: (' + this.complexity() + ')>';\n    },\n\n    /**\n     * Decide if the object should cache or not. Create its own cache level\n     * objectCaching is a global flag, wins over everything\n     * needsItsOwnCache should be used when the object drawing method requires\n     * a cache step. None of the fabric classes requires it.\n     * Generally you do not cache objects in groups because the group outside is cached.\n     * @return {Boolean}\n     */\n    shouldCache: function() {\n      return false;\n    },\n\n    /**\n     * Check if this group or its parent group are caching, recursively up\n     * @return {Boolean}\n     */\n    isOnACache: function() {\n      return false;\n    },\n\n    /**\n     * Renders controls and borders for the object\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Object} [styleOverride] properties to override the object style\n     * @param {Object} [childrenOverride] properties to override the children overrides\n     */\n    _renderControls: function(ctx, styleOverride, childrenOverride) {\n      ctx.save();\n      ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n      childrenOverride = childrenOverride || { };\n      if (typeof childrenOverride.hasControls === 'undefined') {\n        childrenOverride.hasControls = false;\n      }\n      childrenOverride.forActiveSelection = true;\n      for (var i = 0, len = this._objects.length; i < len; i++) {\n        this._objects[i]._renderControls(ctx, childrenOverride);\n      }\n      this.callSuper('_renderControls', ctx, styleOverride);\n      ctx.restore();\n    },\n  });\n\n  /**\n   * Returns {@link fabric.ActiveSelection} instance from an object representation\n   * @static\n   * @memberOf fabric.ActiveSelection\n   * @param {Object} object Object to create a group from\n   * @param {Function} [callback] Callback to invoke when an ActiveSelection instance is created\n   */\n  fabric.ActiveSelection.fromObject = function(object, callback) {\n    fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) {\n      delete object.objects;\n      callback && callback(new fabric.ActiveSelection(enlivenedObjects, object, true));\n    });\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var extend = fabric.util.object.extend;\n\n  if (!global.fabric) {\n    global.fabric = { };\n  }\n\n  if (global.fabric.Image) {\n    fabric.warn('fabric.Image is already defined.');\n    return;\n  }\n\n  /**\n   * Image class\n   * @class fabric.Image\n   * @extends fabric.Object\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#images}\n   * @see {@link fabric.Image#initialize} for constructor definition\n   */\n  fabric.Image = fabric.util.createClass(fabric.Object, /** @lends fabric.Image.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'image',\n\n    /**\n     * Width of a stroke.\n     * For image quality a stroke multiple of 2 gives better results.\n     * @type Number\n     * @default\n     */\n    strokeWidth: 0,\n\n    /**\n     * When calling {@link fabric.Image.getSrc}, return value from element src with `element.getAttribute('src')`.\n     * This allows for relative urls as image src.\n     * @since 2.7.0\n     * @type Boolean\n     * @default\n     */\n    srcFromAttribute: false,\n\n    /**\n     * private\n     * contains last value of scaleX to detect\n     * if the Image got resized after the last Render\n     * @type Number\n     */\n    _lastScaleX: 1,\n\n    /**\n     * private\n     * contains last value of scaleY to detect\n     * if the Image got resized after the last Render\n     * @type Number\n     */\n    _lastScaleY: 1,\n\n    /**\n     * private\n     * contains last value of scaling applied by the apply filter chain\n     * @type Number\n     */\n    _filterScalingX: 1,\n\n    /**\n     * private\n     * contains last value of scaling applied by the apply filter chain\n     * @type Number\n     */\n    _filterScalingY: 1,\n\n    /**\n     * minimum scale factor under which any resizeFilter is triggered to resize the image\n     * 0 will disable the automatic resize. 1 will trigger automatically always.\n     * number bigger than 1 are not implemented yet.\n     * @type Number\n     */\n    minimumScaleTrigger: 0.5,\n\n    /**\n     * List of properties to consider when checking if\n     * state of an object is changed ({@link fabric.Object#hasStateChanged})\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: fabric.Object.prototype.stateProperties.concat('cropX', 'cropY'),\n\n    /**\n     * List of properties to consider when checking if cache needs refresh\n     * Those properties are checked by statefullCache ON ( or lazy mode if we want ) or from single\n     * calls to Object.set(key, value). If the key is in this list, the object is marked as dirty\n     * and refreshed at the next render\n     * @type Array\n     */\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat('cropX', 'cropY'),\n\n    /**\n     * key used to retrieve the texture representing this image\n     * @since 2.0.0\n     * @type String\n     * @default\n     */\n    cacheKey: '',\n\n    /**\n     * Image crop in pixels from original image size.\n     * @since 2.0.0\n     * @type Number\n     * @default\n     */\n    cropX: 0,\n\n    /**\n     * Image crop in pixels from original image size.\n     * @since 2.0.0\n     * @type Number\n     * @default\n     */\n    cropY: 0,\n\n    /**\n     * Indicates whether this canvas will use image smoothing when painting this image.\n     * Also influence if the cacheCanvas for this image uses imageSmoothing\n     * @since 4.0.0-beta.11\n     * @type Boolean\n     * @default\n     */\n    imageSmoothing: true,\n\n    /**\n     * Constructor\n     * Image can be initialized with any canvas drawable or a string.\n     * The string should be a url and will be loaded as an image.\n     * Canvas and Image element work out of the box, while videos require extra code to work.\n     * Please check video element events for seeking.\n     * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | String} element Image element\n     * @param {Object} [options] Options object\n     * @param {function} [callback] callback function to call after eventual filters applied.\n     * @return {fabric.Image} thisArg\n     */\n    initialize: function(element, options) {\n      options || (options = { });\n      this.filters = [];\n      this.cacheKey = 'texture' + fabric.Object.__uid++;\n      this.callSuper('initialize', options);\n      this._initElement(element, options);\n    },\n\n    /**\n     * Returns image element which this instance if based on\n     * @return {HTMLImageElement} Image element\n     */\n    getElement: function() {\n      return this._element || {};\n    },\n\n    /**\n     * Sets image element for this instance to a specified one.\n     * If filters defined they are applied to new image.\n     * You might need to call `canvas.renderAll` and `object.setCoords` after replacing, to render new image and update controls area.\n     * @param {HTMLImageElement} element\n     * @param {Object} [options] Options object\n     * @return {fabric.Image} thisArg\n     * @chainable\n     */\n    setElement: function(element, options) {\n      this.removeTexture(this.cacheKey);\n      this.removeTexture(this.cacheKey + '_filtered');\n      this._element = element;\n      this._originalElement = element;\n      this._initConfig(options);\n      if (this.filters.length !== 0) {\n        this.applyFilters();\n      }\n      // resizeFilters work on the already filtered copy.\n      // we need to apply resizeFilters AFTER normal filters.\n      // applyResizeFilters is run more often than normal filters\n      // and is triggered by user interactions rather than dev code\n      if (this.resizeFilter) {\n        this.applyResizeFilters();\n      }\n      return this;\n    },\n\n    /**\n     * Delete a single texture if in webgl mode\n     */\n    removeTexture: function(key) {\n      var backend = fabric.filterBackend;\n      if (backend && backend.evictCachesForKey) {\n        backend.evictCachesForKey(key);\n      }\n    },\n\n    /**\n     * Delete textures, reference to elements and eventually JSDOM cleanup\n     */\n    dispose: function () {\n      this.callSuper('dispose');\n      this.removeTexture(this.cacheKey);\n      this.removeTexture(this.cacheKey + '_filtered');\n      this._cacheContext = undefined;\n      ['_originalElement', '_element', '_filteredEl', '_cacheCanvas'].forEach((function(element) {\n        fabric.util.cleanUpJsdomNode(this[element]);\n        this[element] = undefined;\n      }).bind(this));\n    },\n\n    /**\n     * Get the crossOrigin value (of the corresponding image element)\n     */\n    getCrossOrigin: function() {\n      return this._originalElement && (this._originalElement.crossOrigin || null);\n    },\n\n    /**\n     * Returns original size of an image\n     * @return {Object} Object with \"width\" and \"height\" properties\n     */\n    getOriginalSize: function() {\n      var element = this.getElement();\n      return {\n        width: element.naturalWidth || element.width,\n        height: element.naturalHeight || element.height\n      };\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _stroke: function(ctx) {\n      if (!this.stroke || this.strokeWidth === 0) {\n        return;\n      }\n      var w = this.width / 2, h = this.height / 2;\n      ctx.beginPath();\n      ctx.moveTo(-w, -h);\n      ctx.lineTo(w, -h);\n      ctx.lineTo(w, h);\n      ctx.lineTo(-w, h);\n      ctx.lineTo(-w, -h);\n      ctx.closePath();\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var filters = [];\n\n      this.filters.forEach(function(filterObj) {\n        if (filterObj) {\n          filters.push(filterObj.toObject());\n        }\n      });\n      var object = extend(\n        this.callSuper(\n          'toObject',\n          ['cropX', 'cropY'].concat(propertiesToInclude)\n        ), {\n          src: this.getSrc(),\n          crossOrigin: this.getCrossOrigin(),\n          filters: filters,\n        });\n      if (this.resizeFilter) {\n        object.resizeFilter = this.resizeFilter.toObject();\n      }\n      return object;\n    },\n\n    /**\n     * Returns true if an image has crop applied, inspecting values of cropX,cropY,width,height.\n     * @return {Boolean}\n     */\n    hasCrop: function() {\n      return this.cropX || this.cropY || this.width < this._element.width || this.height < this._element.height;\n    },\n\n    /* _TO_SVG_START_ */\n    /**\n     * Returns svg representation of an instance\n     * @return {Array} an array of strings with the specific svg representation\n     * of the instance\n     */\n    _toSVG: function() {\n      var svgString = [], imageMarkup = [], strokeSvg, element = this._element,\n          x = -this.width / 2, y = -this.height / 2, clipPath = '', imageRendering = '';\n      if (!element) {\n        return [];\n      }\n      if (this.hasCrop()) {\n        var clipPathId = fabric.Object.__uid++;\n        svgString.push(\n          '<clipPath id=\"imageCrop_' + clipPathId + '\">\\n',\n          '\\t<rect x=\"' + x + '\" y=\"' + y + '\" width=\"' + this.width + '\" height=\"' + this.height + '\" />\\n',\n          '</clipPath>\\n'\n        );\n        clipPath = ' clip-path=\"url(#imageCrop_' + clipPathId + ')\" ';\n      }\n      if (!this.imageSmoothing) {\n        imageRendering = '\" image-rendering=\"optimizeSpeed';\n      }\n      imageMarkup.push('\\t<image ', 'COMMON_PARTS', 'xlink:href=\"', this.getSvgSrc(true),\n        '\" x=\"', x - this.cropX, '\" y=\"', y - this.cropY,\n        // we're essentially moving origin of transformation from top/left corner to the center of the shape\n        // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left\n        // so that object's center aligns with container's left/top\n        '\" width=\"', element.width || element.naturalWidth,\n        '\" height=\"', element.height || element.height,\n        imageRendering,\n        '\"', clipPath,\n        '></image>\\n');\n\n      if (this.stroke || this.strokeDashArray) {\n        var origFill = this.fill;\n        this.fill = null;\n        strokeSvg = [\n          '\\t<rect ',\n          'x=\"', x, '\" y=\"', y,\n          '\" width=\"', this.width, '\" height=\"', this.height,\n          '\" style=\"', this.getSvgStyles(),\n          '\"/>\\n'\n        ];\n        this.fill = origFill;\n      }\n      if (this.paintFirst !== 'fill') {\n        svgString = svgString.concat(strokeSvg, imageMarkup);\n      }\n      else {\n        svgString = svgString.concat(imageMarkup, strokeSvg);\n      }\n      return svgString;\n    },\n    /* _TO_SVG_END_ */\n\n    /**\n     * Returns source of an image\n     * @param {Boolean} filtered indicates if the src is needed for svg\n     * @return {String} Source of an image\n     */\n    getSrc: function(filtered) {\n      var element = filtered ? this._element : this._originalElement;\n      if (element) {\n        if (element.toDataURL) {\n          return element.toDataURL();\n        }\n\n        if (this.srcFromAttribute) {\n          return element.getAttribute('src');\n        }\n        else {\n          return element.src;\n        }\n      }\n      else {\n        return this.src || '';\n      }\n    },\n\n    /**\n     * Sets source of an image\n     * @param {String} src Source string (URL)\n     * @param {Function} [callback] Callback is invoked when image has been loaded (and all filters have been applied)\n     * @param {Object} [options] Options object\n     * @param {String} [options.crossOrigin] crossOrigin value (one of \"\", \"anonymous\", \"use-credentials\")\n     * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes\n     * @return {fabric.Image} thisArg\n     * @chainable\n     */\n    setSrc: function(src, callback, options) {\n      fabric.util.loadImage(src, function(img, isError) {\n        this.setElement(img, options);\n        this._setWidthHeight();\n        callback && callback(this, isError);\n      }, this, options && options.crossOrigin);\n      return this;\n    },\n\n    /**\n     * Returns string representation of an instance\n     * @return {String} String representation of an instance\n     */\n    toString: function() {\n      return '#<fabric.Image: { src: \"' + this.getSrc() + '\" }>';\n    },\n\n    applyResizeFilters: function() {\n      var filter = this.resizeFilter,\n          minimumScale = this.minimumScaleTrigger,\n          objectScale = this.getTotalObjectScaling(),\n          scaleX = objectScale.scaleX,\n          scaleY = objectScale.scaleY,\n          elementToFilter = this._filteredEl || this._originalElement;\n      if (this.group) {\n        this.set('dirty', true);\n      }\n      if (!filter || (scaleX > minimumScale && scaleY > minimumScale)) {\n        this._element = elementToFilter;\n        this._filterScalingX = 1;\n        this._filterScalingY = 1;\n        this._lastScaleX = scaleX;\n        this._lastScaleY = scaleY;\n        return;\n      }\n      if (!fabric.filterBackend) {\n        fabric.filterBackend = fabric.initFilterBackend();\n      }\n      var canvasEl = fabric.util.createCanvasElement(),\n          cacheKey = this._filteredEl ? (this.cacheKey + '_filtered') : this.cacheKey,\n          sourceWidth = elementToFilter.width, sourceHeight = elementToFilter.height;\n      canvasEl.width = sourceWidth;\n      canvasEl.height = sourceHeight;\n      this._element = canvasEl;\n      this._lastScaleX = filter.scaleX = scaleX;\n      this._lastScaleY = filter.scaleY = scaleY;\n      fabric.filterBackend.applyFilters(\n        [filter], elementToFilter, sourceWidth, sourceHeight, this._element, cacheKey);\n      this._filterScalingX = canvasEl.width / this._originalElement.width;\n      this._filterScalingY = canvasEl.height / this._originalElement.height;\n    },\n\n    /**\n     * Applies filters assigned to this image (from \"filters\" array) or from filter param\n     * @method applyFilters\n     * @param {Array} filters to be applied\n     * @param {Boolean} forResizing specify if the filter operation is a resize operation\n     * @return {thisArg} return the fabric.Image object\n     * @chainable\n     */\n    applyFilters: function(filters) {\n\n      filters = filters || this.filters || [];\n      filters = filters.filter(function(filter) { return filter && !filter.isNeutralState(); });\n      this.set('dirty', true);\n\n      // needs to clear out or WEBGL will not resize correctly\n      this.removeTexture(this.cacheKey + '_filtered');\n\n      if (filters.length === 0) {\n        this._element = this._originalElement;\n        this._filteredEl = null;\n        this._filterScalingX = 1;\n        this._filterScalingY = 1;\n        return this;\n      }\n\n      var imgElement = this._originalElement,\n          sourceWidth = imgElement.naturalWidth || imgElement.width,\n          sourceHeight = imgElement.naturalHeight || imgElement.height;\n\n      if (this._element === this._originalElement) {\n        // if the element is the same we need to create a new element\n        var canvasEl = fabric.util.createCanvasElement();\n        canvasEl.width = sourceWidth;\n        canvasEl.height = sourceHeight;\n        this._element = canvasEl;\n        this._filteredEl = canvasEl;\n      }\n      else {\n        // clear the existing element to get new filter data\n        // also dereference the eventual resized _element\n        this._element = this._filteredEl;\n        this._filteredEl.getContext('2d').clearRect(0, 0, sourceWidth, sourceHeight);\n        // we also need to resize again at next renderAll, so remove saved _lastScaleX/Y\n        this._lastScaleX = 1;\n        this._lastScaleY = 1;\n      }\n      if (!fabric.filterBackend) {\n        fabric.filterBackend = fabric.initFilterBackend();\n      }\n      fabric.filterBackend.applyFilters(\n        filters, this._originalElement, sourceWidth, sourceHeight, this._element, this.cacheKey);\n      if (this._originalElement.width !== this._element.width ||\n        this._originalElement.height !== this._element.height) {\n        this._filterScalingX = this._element.width / this._originalElement.width;\n        this._filterScalingY = this._element.height / this._originalElement.height;\n      }\n      return this;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      fabric.util.setImageSmoothing(ctx, this.imageSmoothing);\n      if (this.isMoving !== true && this.resizeFilter && this._needsResize()) {\n        this.applyResizeFilters();\n      }\n      this._stroke(ctx);\n      this._renderPaintInOrder(ctx);\n    },\n\n    /**\n     * Paint the cached copy of the object on the target context.\n     * it will set the imageSmoothing for the draw operation\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    drawCacheOnCanvas: function(ctx) {\n      fabric.util.setImageSmoothing(ctx, this.imageSmoothing);\n      fabric.Object.prototype.drawCacheOnCanvas.call(this, ctx);\n    },\n\n    /**\n     * Decide if the object should cache or not. Create its own cache level\n     * needsItsOwnCache should be used when the object drawing method requires\n     * a cache step. None of the fabric classes requires it.\n     * Generally you do not cache objects in groups because the group outside is cached.\n     * This is the special image version where we would like to avoid caching where possible.\n     * Essentially images do not benefit from caching. They may require caching, and in that\n     * case we do it. Also caching an image usually ends in a loss of details.\n     * A full performance audit should be done.\n     * @return {Boolean}\n     */\n    shouldCache: function() {\n      return this.needsItsOwnCache();\n    },\n\n    _renderFill: function(ctx) {\n      var elementToDraw = this._element;\n      if (!elementToDraw) {\n        return;\n      }\n      var scaleX = this._filterScalingX, scaleY = this._filterScalingY,\n          w = this.width, h = this.height, min = Math.min, max = Math.max,\n          // crop values cannot be lesser than 0.\n          cropX = max(this.cropX, 0), cropY = max(this.cropY, 0),\n          elWidth = elementToDraw.naturalWidth || elementToDraw.width,\n          elHeight = elementToDraw.naturalHeight || elementToDraw.height,\n          sX = cropX * scaleX,\n          sY = cropY * scaleY,\n          // the width height cannot exceed element width/height, starting from the crop offset.\n          sW = min(w * scaleX, elWidth - sX),\n          sH = min(h * scaleY, elHeight - sY),\n          x = -w / 2, y = -h / 2,\n          maxDestW = min(w, elWidth / scaleX - cropX),\n          maxDestH = min(h, elHeight / scaleY - cropY);\n\n      elementToDraw && ctx.drawImage(elementToDraw, sX, sY, sW, sH, x, y, maxDestW, maxDestH);\n    },\n\n    /**\n     * needed to check if image needs resize\n     * @private\n     */\n    _needsResize: function() {\n      var scale = this.getTotalObjectScaling();\n      return (scale.scaleX !== this._lastScaleX || scale.scaleY !== this._lastScaleY);\n    },\n\n    /**\n     * @private\n     */\n    _resetWidthHeight: function() {\n      this.set(this.getOriginalSize());\n    },\n\n    /**\n     * The Image class's initialization method. This method is automatically\n     * called by the constructor.\n     * @private\n     * @param {HTMLImageElement|String} element The element representing the image\n     * @param {Object} [options] Options object\n     */\n    _initElement: function(element, options) {\n      this.setElement(fabric.util.getById(element), options);\n      fabric.util.addClass(this.getElement(), fabric.Image.CSS_CANVAS);\n    },\n\n    /**\n     * @private\n     * @param {Object} [options] Options object\n     */\n    _initConfig: function(options) {\n      options || (options = { });\n      this.setOptions(options);\n      this._setWidthHeight(options);\n    },\n\n    /**\n     * @private\n     * @param {Array} filters to be initialized\n     * @param {Function} callback Callback to invoke when all fabric.Image.filters instances are created\n     */\n    _initFilters: function(filters, callback) {\n      if (filters && filters.length) {\n        fabric.util.enlivenObjects(filters, function(enlivenedObjects) {\n          callback && callback(enlivenedObjects);\n        }, 'fabric.Image.filters');\n      }\n      else {\n        callback && callback();\n      }\n    },\n\n    /**\n     * @private\n     * Set the width and the height of the image object, using the element or the\n     * options.\n     * @param {Object} [options] Object with width/height properties\n     */\n    _setWidthHeight: function(options) {\n      options || (options = { });\n      var el = this.getElement();\n      this.width = options.width || el.naturalWidth || el.width || 0;\n      this.height = options.height || el.naturalHeight || el.height || 0;\n    },\n\n    /**\n     * Calculate offset for center and scale factor for the image in order to respect\n     * the preserveAspectRatio attribute\n     * @private\n     * @return {Object}\n     */\n    parsePreserveAspectRatioAttribute: function() {\n      var pAR = fabric.util.parsePreserveAspectRatioAttribute(this.preserveAspectRatio || ''),\n          rWidth = this._element.width, rHeight = this._element.height,\n          scaleX = 1, scaleY = 1, offsetLeft = 0, offsetTop = 0, cropX = 0, cropY = 0,\n          offset, pWidth = this.width, pHeight = this.height, parsedAttributes = { width: pWidth, height: pHeight };\n      if (pAR && (pAR.alignX !== 'none' || pAR.alignY !== 'none')) {\n        if (pAR.meetOrSlice === 'meet') {\n          scaleX = scaleY = fabric.util.findScaleToFit(this._element, parsedAttributes);\n          offset = (pWidth - rWidth * scaleX) / 2;\n          if (pAR.alignX === 'Min') {\n            offsetLeft = -offset;\n          }\n          if (pAR.alignX === 'Max') {\n            offsetLeft = offset;\n          }\n          offset = (pHeight - rHeight * scaleY) / 2;\n          if (pAR.alignY === 'Min') {\n            offsetTop = -offset;\n          }\n          if (pAR.alignY === 'Max') {\n            offsetTop = offset;\n          }\n        }\n        if (pAR.meetOrSlice === 'slice') {\n          scaleX = scaleY = fabric.util.findScaleToCover(this._element, parsedAttributes);\n          offset = rWidth - pWidth / scaleX;\n          if (pAR.alignX === 'Mid') {\n            cropX = offset / 2;\n          }\n          if (pAR.alignX === 'Max') {\n            cropX = offset;\n          }\n          offset = rHeight - pHeight / scaleY;\n          if (pAR.alignY === 'Mid') {\n            cropY = offset / 2;\n          }\n          if (pAR.alignY === 'Max') {\n            cropY = offset;\n          }\n          rWidth = pWidth / scaleX;\n          rHeight = pHeight / scaleY;\n        }\n      }\n      else {\n        scaleX = pWidth / rWidth;\n        scaleY = pHeight / rHeight;\n      }\n      return {\n        width: rWidth,\n        height: rHeight,\n        scaleX: scaleX,\n        scaleY: scaleY,\n        offsetLeft: offsetLeft,\n        offsetTop: offsetTop,\n        cropX: cropX,\n        cropY: cropY\n      };\n    }\n  });\n\n  /**\n   * Default CSS class name for canvas\n   * @static\n   * @type String\n   * @default\n   */\n  fabric.Image.CSS_CANVAS = 'canvas-img';\n\n  /**\n   * Alias for getSrc\n   * @static\n   */\n  fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc;\n\n  /**\n   * Creates an instance of fabric.Image from its object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} callback Callback to invoke when an image instance is created\n   */\n  fabric.Image.fromObject = function(_object, callback) {\n    var object = fabric.util.object.clone(_object);\n    fabric.util.loadImage(object.src, function(img, isError) {\n      if (isError) {\n        callback && callback(null, true);\n        return;\n      }\n      fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) {\n        object.filters = filters || [];\n        fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) {\n          object.resizeFilter = resizeFilters[0];\n          fabric.util.enlivenObjectEnlivables(object, object, function () {\n            var image = new fabric.Image(img, object);\n            callback(image, false);\n          });\n        });\n      });\n    }, null, object.crossOrigin);\n  };\n\n  /**\n   * Creates an instance of fabric.Image from an URL string\n   * @static\n   * @param {String} url URL to create an image from\n   * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument). Second argument is a boolean indicating if an error occurred or not.\n   * @param {Object} [imgOptions] Options object\n   */\n  fabric.Image.fromURL = function(url, callback, imgOptions) {\n    fabric.util.loadImage(url, function(img, isError) {\n      callback && callback(new fabric.Image(img, imgOptions), isError);\n    }, null, imgOptions && imgOptions.crossOrigin);\n  };\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Image.fromElement})\n   * @static\n   * @see {@link http://www.w3.org/TR/SVG/struct.html#ImageElement}\n   */\n  fabric.Image.ATTRIBUTE_NAMES =\n    fabric.SHARED_ATTRIBUTES.concat(\n      'x y width height preserveAspectRatio xlink:href crossOrigin image-rendering'.split(' ')\n    );\n\n  /**\n   * Returns {@link fabric.Image} instance from an SVG element\n   * @static\n   * @param {SVGElement} element Element to parse\n   * @param {Object} [options] Options object\n   * @param {Function} callback Callback to execute when fabric.Image object is created\n   * @return {fabric.Image} Instance of fabric.Image\n   */\n  fabric.Image.fromElement = function(element, callback, options) {\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES);\n    fabric.Image.fromURL(parsedAttributes['xlink:href'], callback,\n      extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n  };\n  /* _FROM_SVG_END_ */\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n  /**\n   * @private\n   * @return {Number} angle value\n   */\n  _getAngleValueForStraighten: function() {\n    var angle = this.angle % 360;\n    if (angle > 0) {\n      return Math.round((angle - 1) / 90) * 90;\n    }\n    return Math.round(angle / 90) * 90;\n  },\n\n  /**\n   * Straightens an object (rotating it from current angle to one of 0, 90, 180, 270, etc. depending on which is closer)\n   * @return {fabric.Object} thisArg\n   * @chainable\n   */\n  straighten: function() {\n    return this.rotate(this._getAngleValueForStraighten());\n  },\n\n  /**\n   * Same as {@link fabric.Object.prototype.straighten} but with animation\n   * @param {Object} callbacks Object with callback functions\n   * @param {Function} [callbacks.onComplete] Invoked on completion\n   * @param {Function} [callbacks.onChange] Invoked on every step of animation\n   * @return {fabric.Object} thisArg\n   */\n  fxStraighten: function(callbacks) {\n    callbacks = callbacks || { };\n\n    var empty = function() { },\n        onComplete = callbacks.onComplete || empty,\n        onChange = callbacks.onChange || empty,\n        _this = this;\n\n    return fabric.util.animate({\n      target: this,\n      startValue: this.get('angle'),\n      endValue: this._getAngleValueForStraighten(),\n      duration: this.FX_DURATION,\n      onChange: function(value) {\n        _this.rotate(value);\n        onChange();\n      },\n      onComplete: function() {\n        _this.setCoords();\n        onComplete();\n      },\n    });\n  }\n});\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n  /**\n   * Straightens object, then rerenders canvas\n   * @param {fabric.Object} object Object to straighten\n   * @return {fabric.Canvas} thisArg\n   * @chainable\n   */\n  straightenObject: function (object) {\n    object.straighten();\n    this.requestRenderAll();\n    return this;\n  },\n\n  /**\n   * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated\n   * @param {fabric.Object} object Object to straighten\n   * @return {fabric.Canvas} thisArg\n   */\n  fxStraightenObject: function (object) {\n    return object.fxStraighten({\n      onChange: this.requestRenderAllBound\n    });\n  }\n});\n\n\n(function() {\n\n  'use strict';\n\n  /**\n   * Tests if webgl supports certain precision\n   * @param {WebGL} Canvas WebGL context to test on\n   * @param {String} Precision to test can be any of following: 'lowp', 'mediump', 'highp'\n   * @returns {Boolean} Whether the user's browser WebGL supports given precision.\n   */\n  function testPrecision(gl, precision){\n    var fragmentSource = 'precision ' + precision + ' float;\\nvoid main(){}';\n    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n    gl.shaderSource(fragmentShader, fragmentSource);\n    gl.compileShader(fragmentShader);\n    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {\n      return false;\n    }\n    return true;\n  }\n\n  /**\n   * Indicate whether this filtering backend is supported by the user's browser.\n   * @param {Number} tileSize check if the tileSize is supported\n   * @returns {Boolean} Whether the user's browser supports WebGL.\n   */\n  fabric.isWebglSupported = function(tileSize) {\n    if (fabric.isLikelyNode) {\n      return false;\n    }\n    tileSize = tileSize || fabric.WebglFilterBackend.prototype.tileSize;\n    var canvas = document.createElement('canvas');\n    var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');\n    var isSupported = false;\n    // eslint-disable-next-line\n    if (gl) {\n      fabric.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);\n      isSupported = fabric.maxTextureSize >= tileSize;\n      var precisions = ['highp', 'mediump', 'lowp'];\n      for (var i = 0; i < 3; i++){\n        if (testPrecision(gl, precisions[i])){\n          fabric.webGlPrecision = precisions[i];\n          break;\n        };\n      }\n    }\n    this.isSupported = isSupported;\n    return isSupported;\n  };\n\n  fabric.WebglFilterBackend = WebglFilterBackend;\n\n  /**\n   * WebGL filter backend.\n   */\n  function WebglFilterBackend(options) {\n    if (options && options.tileSize) {\n      this.tileSize = options.tileSize;\n    }\n    this.setupGLContext(this.tileSize, this.tileSize);\n    this.captureGPUInfo();\n  };\n\n  WebglFilterBackend.prototype = /** @lends fabric.WebglFilterBackend.prototype */ {\n\n    tileSize: 2048,\n\n    /**\n     * Experimental. This object is a sort of repository of help layers used to avoid\n     * of recreating them during frequent filtering. If you are previewing a filter with\n     * a slider you probably do not want to create help layers every filter step.\n     * in this object there will be appended some canvases, created once, resized sometimes\n     * cleared never. Clearing is left to the developer.\n     **/\n    resources: {\n\n    },\n\n    /**\n     * Setup a WebGL context suitable for filtering, and bind any needed event handlers.\n     */\n    setupGLContext: function(width, height) {\n      this.dispose();\n      this.createWebGLCanvas(width, height);\n      // eslint-disable-next-line\n      this.aPosition = new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]);\n      this.chooseFastestCopyGLTo2DMethod(width, height);\n    },\n\n    /**\n     * Pick a method to copy data from GL context to 2d canvas.  In some browsers using\n     * putImageData is faster than drawImage for that specific operation.\n     */\n    chooseFastestCopyGLTo2DMethod: function(width, height) {\n      var canMeasurePerf = typeof window.performance !== 'undefined', canUseImageData;\n      try {\n        new ImageData(1, 1);\n        canUseImageData = true;\n      }\n      catch (e) {\n        canUseImageData = false;\n      }\n      // eslint-disable-next-line no-undef\n      var canUseArrayBuffer = typeof ArrayBuffer !== 'undefined';\n      // eslint-disable-next-line no-undef\n      var canUseUint8Clamped = typeof Uint8ClampedArray !== 'undefined';\n\n      if (!(canMeasurePerf && canUseImageData && canUseArrayBuffer && canUseUint8Clamped)) {\n        return;\n      }\n\n      var targetCanvas = fabric.util.createCanvasElement();\n      // eslint-disable-next-line no-undef\n      var imageBuffer = new ArrayBuffer(width * height * 4);\n      if (fabric.forceGLPutImageData) {\n        this.imageBuffer = imageBuffer;\n        this.copyGLTo2D = copyGLTo2DPutImageData;\n        return;\n      }\n      var testContext = {\n        imageBuffer: imageBuffer,\n        destinationWidth: width,\n        destinationHeight: height,\n        targetCanvas: targetCanvas\n      };\n      var startTime, drawImageTime, putImageDataTime;\n      targetCanvas.width = width;\n      targetCanvas.height = height;\n\n      startTime = window.performance.now();\n      copyGLTo2DDrawImage.call(testContext, this.gl, testContext);\n      drawImageTime = window.performance.now() - startTime;\n\n      startTime = window.performance.now();\n      copyGLTo2DPutImageData.call(testContext, this.gl, testContext);\n      putImageDataTime = window.performance.now() - startTime;\n\n      if (drawImageTime > putImageDataTime) {\n        this.imageBuffer = imageBuffer;\n        this.copyGLTo2D = copyGLTo2DPutImageData;\n      }\n      else {\n        this.copyGLTo2D = copyGLTo2DDrawImage;\n      }\n    },\n\n    /**\n     * Create a canvas element and associated WebGL context and attaches them as\n     * class properties to the GLFilterBackend class.\n     */\n    createWebGLCanvas: function(width, height) {\n      var canvas = fabric.util.createCanvasElement();\n      canvas.width = width;\n      canvas.height = height;\n      var glOptions = {\n            alpha: true,\n            premultipliedAlpha: false,\n            depth: false,\n            stencil: false,\n            antialias: false\n          },\n          gl = canvas.getContext('webgl', glOptions);\n      if (!gl) {\n        gl = canvas.getContext('experimental-webgl', glOptions);\n      }\n      if (!gl) {\n        return;\n      }\n      gl.clearColor(0, 0, 0, 0);\n      // this canvas can fire webglcontextlost and webglcontextrestored\n      this.canvas = canvas;\n      this.gl = gl;\n    },\n\n    /**\n     * Attempts to apply the requested filters to the source provided, drawing the filtered output\n     * to the provided target canvas.\n     *\n     * @param {Array} filters The filters to apply.\n     * @param {HTMLImageElement|HTMLCanvasElement} source The source to be filtered.\n     * @param {Number} width The width of the source input.\n     * @param {Number} height The height of the source input.\n     * @param {HTMLCanvasElement} targetCanvas The destination for filtered output to be drawn.\n     * @param {String|undefined} cacheKey A key used to cache resources related to the source. If\n     * omitted, caching will be skipped.\n     */\n    applyFilters: function(filters, source, width, height, targetCanvas, cacheKey) {\n      var gl = this.gl;\n      var cachedTexture;\n      if (cacheKey) {\n        cachedTexture = this.getCachedTexture(cacheKey, source);\n      }\n      var pipelineState = {\n        originalWidth: source.width || source.originalWidth,\n        originalHeight: source.height || source.originalHeight,\n        sourceWidth: width,\n        sourceHeight: height,\n        destinationWidth: width,\n        destinationHeight: height,\n        context: gl,\n        sourceTexture: this.createTexture(gl, width, height, !cachedTexture && source),\n        targetTexture: this.createTexture(gl, width, height),\n        originalTexture: cachedTexture ||\n          this.createTexture(gl, width, height, !cachedTexture && source),\n        passes: filters.length,\n        webgl: true,\n        aPosition: this.aPosition,\n        programCache: this.programCache,\n        pass: 0,\n        filterBackend: this,\n        targetCanvas: targetCanvas\n      };\n      var tempFbo = gl.createFramebuffer();\n      gl.bindFramebuffer(gl.FRAMEBUFFER, tempFbo);\n      filters.forEach(function(filter) { filter && filter.applyTo(pipelineState); });\n      resizeCanvasIfNeeded(pipelineState);\n      this.copyGLTo2D(gl, pipelineState);\n      gl.bindTexture(gl.TEXTURE_2D, null);\n      gl.deleteTexture(pipelineState.sourceTexture);\n      gl.deleteTexture(pipelineState.targetTexture);\n      gl.deleteFramebuffer(tempFbo);\n      targetCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);\n      return pipelineState;\n    },\n\n    /**\n     * Detach event listeners, remove references, and clean up caches.\n     */\n    dispose: function() {\n      if (this.canvas) {\n        this.canvas = null;\n        this.gl = null;\n      }\n      this.clearWebGLCaches();\n    },\n\n    /**\n     * Wipe out WebGL-related caches.\n     */\n    clearWebGLCaches: function() {\n      this.programCache = {};\n      this.textureCache = {};\n    },\n\n    /**\n     * Create a WebGL texture object.\n     *\n     * Accepts specific dimensions to initialize the texture to or a source image.\n     *\n     * @param {WebGLRenderingContext} gl The GL context to use for creating the texture.\n     * @param {Number} width The width to initialize the texture at.\n     * @param {Number} height The height to initialize the texture.\n     * @param {HTMLImageElement|HTMLCanvasElement} textureImageSource A source for the texture data.\n     * @param {Number} filterType gl.NEAREST or gl.LINEAR usually, webgl numeri constants\n     * @returns {WebGLTexture}\n     */\n    createTexture: function(gl, width, height, textureImageSource, filterType) {\n      var texture = gl.createTexture();\n      gl.bindTexture(gl.TEXTURE_2D, texture);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterType || gl.NEAREST);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterType || gl.NEAREST);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n      if (textureImageSource) {\n        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImageSource);\n      }\n      else {\n        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n      }\n      return texture;\n    },\n\n    /**\n     * Can be optionally used to get a texture from the cache array\n     *\n     * If an existing texture is not found, a new texture is created and cached.\n     *\n     * @param {String} uniqueId A cache key to use to find an existing texture.\n     * @param {HTMLImageElement|HTMLCanvasElement} textureImageSource A source to use to create the\n     * texture cache entry if one does not already exist.\n     */\n    getCachedTexture: function(uniqueId, textureImageSource) {\n      if (this.textureCache[uniqueId]) {\n        return this.textureCache[uniqueId];\n      }\n      else {\n        var texture = this.createTexture(\n          this.gl, textureImageSource.width, textureImageSource.height, textureImageSource);\n        this.textureCache[uniqueId] = texture;\n        return texture;\n      }\n    },\n\n    /**\n     * Clear out cached resources related to a source image that has been\n     * filtered previously.\n     *\n     * @param {String} cacheKey The cache key provided when the source image was filtered.\n     */\n    evictCachesForKey: function(cacheKey) {\n      if (this.textureCache[cacheKey]) {\n        this.gl.deleteTexture(this.textureCache[cacheKey]);\n        delete this.textureCache[cacheKey];\n      }\n    },\n\n    copyGLTo2D: copyGLTo2DDrawImage,\n\n    /**\n     * Attempt to extract GPU information strings from a WebGL context.\n     *\n     * Useful information when debugging or blacklisting specific GPUs.\n     *\n     * @returns {Object} A GPU info object with renderer and vendor strings.\n     */\n    captureGPUInfo: function() {\n      if (this.gpuInfo) {\n        return this.gpuInfo;\n      }\n      var gl = this.gl, gpuInfo = { renderer: '', vendor: '' };\n      if (!gl) {\n        return gpuInfo;\n      }\n      var ext = gl.getExtension('WEBGL_debug_renderer_info');\n      if (ext) {\n        var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);\n        var vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);\n        if (renderer) {\n          gpuInfo.renderer = renderer.toLowerCase();\n        }\n        if (vendor) {\n          gpuInfo.vendor = vendor.toLowerCase();\n        }\n      }\n      this.gpuInfo = gpuInfo;\n      return gpuInfo;\n    },\n  };\n})();\n\nfunction resizeCanvasIfNeeded(pipelineState) {\n  var targetCanvas = pipelineState.targetCanvas,\n      width = targetCanvas.width, height = targetCanvas.height,\n      dWidth = pipelineState.destinationWidth,\n      dHeight = pipelineState.destinationHeight;\n\n  if (width !== dWidth || height !== dHeight) {\n    targetCanvas.width = dWidth;\n    targetCanvas.height = dHeight;\n  }\n}\n\n/**\n * Copy an input WebGL canvas on to an output 2D canvas.\n *\n * The WebGL canvas is assumed to be upside down, with the top-left pixel of the\n * desired output image appearing in the bottom-left corner of the WebGL canvas.\n *\n * @param {WebGLRenderingContext} sourceContext The WebGL context to copy from.\n * @param {HTMLCanvasElement} targetCanvas The 2D target canvas to copy on to.\n * @param {Object} pipelineState The 2D target canvas to copy on to.\n */\nfunction copyGLTo2DDrawImage(gl, pipelineState) {\n  var glCanvas = gl.canvas, targetCanvas = pipelineState.targetCanvas,\n      ctx = targetCanvas.getContext('2d');\n  ctx.translate(0, targetCanvas.height); // move it down again\n  ctx.scale(1, -1); // vertical flip\n  // where is my image on the big glcanvas?\n  var sourceY = glCanvas.height - targetCanvas.height;\n  ctx.drawImage(glCanvas, 0, sourceY, targetCanvas.width, targetCanvas.height, 0, 0,\n    targetCanvas.width, targetCanvas.height);\n}\n\n/**\n * Copy an input WebGL canvas on to an output 2D canvas using 2d canvas' putImageData\n * API. Measurably faster than using ctx.drawImage in Firefox (version 54 on OSX Sierra).\n *\n * @param {WebGLRenderingContext} sourceContext The WebGL context to copy from.\n * @param {HTMLCanvasElement} targetCanvas The 2D target canvas to copy on to.\n * @param {Object} pipelineState The 2D target canvas to copy on to.\n */\nfunction copyGLTo2DPutImageData(gl, pipelineState) {\n  var targetCanvas = pipelineState.targetCanvas, ctx = targetCanvas.getContext('2d'),\n      dWidth = pipelineState.destinationWidth,\n      dHeight = pipelineState.destinationHeight,\n      numBytes = dWidth * dHeight * 4;\n\n  // eslint-disable-next-line no-undef\n  var u8 = new Uint8Array(this.imageBuffer, 0, numBytes);\n  // eslint-disable-next-line no-undef\n  var u8Clamped = new Uint8ClampedArray(this.imageBuffer, 0, numBytes);\n\n  gl.readPixels(0, 0, dWidth, dHeight, gl.RGBA, gl.UNSIGNED_BYTE, u8);\n  var imgData = new ImageData(u8Clamped, dWidth, dHeight);\n  ctx.putImageData(imgData, 0, 0);\n}\n\n\n(function() {\n\n  'use strict';\n\n  var noop = function() {};\n\n  fabric.Canvas2dFilterBackend = Canvas2dFilterBackend;\n\n  /**\n   * Canvas 2D filter backend.\n   */\n  function Canvas2dFilterBackend() {};\n\n  Canvas2dFilterBackend.prototype = /** @lends fabric.Canvas2dFilterBackend.prototype */ {\n    evictCachesForKey: noop,\n    dispose: noop,\n    clearWebGLCaches: noop,\n\n    /**\n     * Experimental. This object is a sort of repository of help layers used to avoid\n     * of recreating them during frequent filtering. If you are previewing a filter with\n     * a slider you probably do not want to create help layers every filter step.\n     * in this object there will be appended some canvases, created once, resized sometimes\n     * cleared never. Clearing is left to the developer.\n     **/\n    resources: {\n\n    },\n\n    /**\n     * Apply a set of filters against a source image and draw the filtered output\n     * to the provided destination canvas.\n     *\n     * @param {EnhancedFilter} filters The filter to apply.\n     * @param {HTMLImageElement|HTMLCanvasElement} sourceElement The source to be filtered.\n     * @param {Number} sourceWidth The width of the source input.\n     * @param {Number} sourceHeight The height of the source input.\n     * @param {HTMLCanvasElement} targetCanvas The destination for filtered output to be drawn.\n     */\n    applyFilters: function(filters, sourceElement, sourceWidth, sourceHeight, targetCanvas) {\n      var ctx = targetCanvas.getContext('2d');\n      ctx.drawImage(sourceElement, 0, 0, sourceWidth, sourceHeight);\n      var imageData = ctx.getImageData(0, 0, sourceWidth, sourceHeight);\n      var originalImageData = ctx.getImageData(0, 0, sourceWidth, sourceHeight);\n      var pipelineState = {\n        sourceWidth: sourceWidth,\n        sourceHeight: sourceHeight,\n        imageData: imageData,\n        originalEl: sourceElement,\n        originalImageData: originalImageData,\n        canvasEl: targetCanvas,\n        ctx: ctx,\n        filterBackend: this,\n      };\n      filters.forEach(function(filter) { filter.applyTo(pipelineState); });\n      if (pipelineState.imageData.width !== sourceWidth || pipelineState.imageData.height !== sourceHeight) {\n        targetCanvas.width = pipelineState.imageData.width;\n        targetCanvas.height = pipelineState.imageData.height;\n      }\n      ctx.putImageData(pipelineState.imageData, 0, 0);\n      return pipelineState;\n    },\n\n  };\n})();\n\n\n/**\n * @namespace fabric.Image.filters\n * @memberOf fabric.Image\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#image_filters}\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n */\nfabric.Image = fabric.Image || { };\nfabric.Image.filters = fabric.Image.filters || { };\n\n/**\n * Root filter class from which all filter classes inherit from\n * @class fabric.Image.filters.BaseFilter\n * @memberOf fabric.Image.filters\n */\nfabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Image.filters.BaseFilter.prototype */ {\n\n  /**\n   * Filter type\n   * @param {String} type\n   * @default\n   */\n  type: 'BaseFilter',\n\n  /**\n   * Array of attributes to send with buffers. do not modify\n   * @private\n   */\n\n  vertexSource: 'attribute vec2 aPosition;\\n' +\n    'varying vec2 vTexCoord;\\n' +\n    'void main() {\\n' +\n      'vTexCoord = aPosition;\\n' +\n      'gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);\\n' +\n    '}',\n\n  fragmentSource: 'precision highp float;\\n' +\n    'varying vec2 vTexCoord;\\n' +\n    'uniform sampler2D uTexture;\\n' +\n    'void main() {\\n' +\n      'gl_FragColor = texture2D(uTexture, vTexCoord);\\n' +\n    '}',\n\n  /**\n   * Constructor\n   * @param {Object} [options] Options object\n   */\n  initialize: function(options) {\n    if (options) {\n      this.setOptions(options);\n    }\n  },\n\n  /**\n   * Sets filter's properties from options\n   * @param {Object} [options] Options object\n   */\n  setOptions: function(options) {\n    for (var prop in options) {\n      this[prop] = options[prop];\n    }\n  },\n\n  /**\n   * Compile this filter's shader program.\n   *\n   * @param {WebGLRenderingContext} gl The GL canvas context to use for shader compilation.\n   * @param {String} fragmentSource fragmentShader source for compilation\n   * @param {String} vertexSource vertexShader source for compilation\n   */\n  createProgram: function(gl, fragmentSource, vertexSource) {\n    fragmentSource = fragmentSource || this.fragmentSource;\n    vertexSource = vertexSource || this.vertexSource;\n    if (fabric.webGlPrecision !== 'highp'){\n      fragmentSource = fragmentSource.replace(\n        /precision highp float/g,\n        'precision ' + fabric.webGlPrecision + ' float'\n      );\n    }\n    var vertexShader = gl.createShader(gl.VERTEX_SHADER);\n    gl.shaderSource(vertexShader, vertexSource);\n    gl.compileShader(vertexShader);\n    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {\n      throw new Error(\n        // eslint-disable-next-line prefer-template\n        'Vertex shader compile error for ' + this.type + ': ' +\n        gl.getShaderInfoLog(vertexShader)\n      );\n    }\n\n    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n    gl.shaderSource(fragmentShader, fragmentSource);\n    gl.compileShader(fragmentShader);\n    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {\n      throw new Error(\n        // eslint-disable-next-line prefer-template\n        'Fragment shader compile error for ' + this.type + ': ' +\n        gl.getShaderInfoLog(fragmentShader)\n      );\n    }\n\n    var program = gl.createProgram();\n    gl.attachShader(program, vertexShader);\n    gl.attachShader(program, fragmentShader);\n    gl.linkProgram(program);\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n      throw new Error(\n        // eslint-disable-next-line prefer-template\n        'Shader link error for \"${this.type}\" ' +\n        gl.getProgramInfoLog(program)\n      );\n    }\n\n    var attributeLocations = this.getAttributeLocations(gl, program);\n    var uniformLocations = this.getUniformLocations(gl, program) || { };\n    uniformLocations.uStepW = gl.getUniformLocation(program, 'uStepW');\n    uniformLocations.uStepH = gl.getUniformLocation(program, 'uStepH');\n    return {\n      program: program,\n      attributeLocations: attributeLocations,\n      uniformLocations: uniformLocations\n    };\n  },\n\n  /**\n   * Return a map of attribute names to WebGLAttributeLocation objects.\n   *\n   * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n   * @param {WebGLShaderProgram} program The shader program from which to take attribute locations.\n   * @returns {Object} A map of attribute names to attribute locations.\n   */\n  getAttributeLocations: function(gl, program) {\n    return {\n      aPosition: gl.getAttribLocation(program, 'aPosition'),\n    };\n  },\n\n  /**\n   * Return a map of uniform names to WebGLUniformLocation objects.\n   *\n   * Intended to be overridden by subclasses.\n   *\n   * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n   * @param {WebGLShaderProgram} program The shader program from which to take uniform locations.\n   * @returns {Object} A map of uniform names to uniform locations.\n   */\n  getUniformLocations: function (/* gl, program */) {\n    // in case i do not need any special uniform i need to return an empty object\n    return { };\n  },\n\n  /**\n   * Send attribute data from this filter to its shader program on the GPU.\n   *\n   * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n   * @param {Object} attributeLocations A map of shader attribute names to their locations.\n   */\n  sendAttributeData: function(gl, attributeLocations, aPositionData) {\n    var attributeLocation = attributeLocations.aPosition;\n    var buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.enableVertexAttribArray(attributeLocation);\n    gl.vertexAttribPointer(attributeLocation, 2, gl.FLOAT, false, 0, 0);\n    gl.bufferData(gl.ARRAY_BUFFER, aPositionData, gl.STATIC_DRAW);\n  },\n\n  _setupFrameBuffer: function(options) {\n    var gl = options.context, width, height;\n    if (options.passes > 1) {\n      width = options.destinationWidth;\n      height = options.destinationHeight;\n      if (options.sourceWidth !== width || options.sourceHeight !== height) {\n        gl.deleteTexture(options.targetTexture);\n        options.targetTexture = options.filterBackend.createTexture(gl, width, height);\n      }\n      gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,\n        options.targetTexture, 0);\n    }\n    else {\n      // draw last filter on canvas and not to framebuffer.\n      gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n      gl.finish();\n    }\n  },\n\n  _swapTextures: function(options) {\n    options.passes--;\n    options.pass++;\n    var temp = options.targetTexture;\n    options.targetTexture = options.sourceTexture;\n    options.sourceTexture = temp;\n  },\n\n  /**\n   * Generic isNeutral implementation for one parameter based filters.\n   * Used only in image applyFilters to discard filters that will not have an effect\n   * on the image\n   * Other filters may need their own version ( ColorMatrix, HueRotation, gamma, ComposedFilter )\n   * @param {Object} options\n   **/\n  isNeutralState: function(/* options */) {\n    var main = this.mainParameter,\n        _class = fabric.Image.filters[this.type].prototype;\n    if (main) {\n      if (Array.isArray(_class[main])) {\n        for (var i = _class[main].length; i--;) {\n          if (this[main][i] !== _class[main][i]) {\n            return false;\n          }\n        }\n        return true;\n      }\n      else {\n        return _class[main] === this[main];\n      }\n    }\n    else {\n      return false;\n    }\n  },\n\n  /**\n   * Apply this filter to the input image data provided.\n   *\n   * Determines whether to use WebGL or Canvas2D based on the options.webgl flag.\n   *\n   * @param {Object} options\n   * @param {Number} options.passes The number of filters remaining to be executed\n   * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n   * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n   * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n   * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n   * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n   */\n  applyTo: function(options) {\n    if (options.webgl) {\n      this._setupFrameBuffer(options);\n      this.applyToWebGL(options);\n      this._swapTextures(options);\n    }\n    else {\n      this.applyTo2d(options);\n    }\n  },\n\n  /**\n   * Retrieves the cached shader.\n   * @param {Object} options\n   * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n   * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n   */\n  retrieveShader: function(options) {\n    if (!options.programCache.hasOwnProperty(this.type)) {\n      options.programCache[this.type] = this.createProgram(options.context);\n    }\n    return options.programCache[this.type];\n  },\n\n  /**\n   * Apply this filter using webgl.\n   *\n   * @param {Object} options\n   * @param {Number} options.passes The number of filters remaining to be executed\n   * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n   * @param {WebGLTexture} options.originalTexture The texture of the original input image.\n   * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n   * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n   * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n   * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n   */\n  applyToWebGL: function(options) {\n    var gl = options.context;\n    var shader = this.retrieveShader(options);\n    if (options.pass === 0 && options.originalTexture) {\n      gl.bindTexture(gl.TEXTURE_2D, options.originalTexture);\n    }\n    else {\n      gl.bindTexture(gl.TEXTURE_2D, options.sourceTexture);\n    }\n    gl.useProgram(shader.program);\n    this.sendAttributeData(gl, shader.attributeLocations, options.aPosition);\n\n    gl.uniform1f(shader.uniformLocations.uStepW, 1 / options.sourceWidth);\n    gl.uniform1f(shader.uniformLocations.uStepH, 1 / options.sourceHeight);\n\n    this.sendUniformData(gl, shader.uniformLocations);\n    gl.viewport(0, 0, options.destinationWidth, options.destinationHeight);\n    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n  },\n\n  bindAdditionalTexture: function(gl, texture, textureUnit) {\n    gl.activeTexture(textureUnit);\n    gl.bindTexture(gl.TEXTURE_2D, texture);\n    // reset active texture to 0 as usual\n    gl.activeTexture(gl.TEXTURE0);\n  },\n\n  unbindAdditionalTexture: function(gl, textureUnit) {\n    gl.activeTexture(textureUnit);\n    gl.bindTexture(gl.TEXTURE_2D, null);\n    gl.activeTexture(gl.TEXTURE0);\n  },\n\n  getMainParameter: function() {\n    return this[this.mainParameter];\n  },\n\n  setMainParameter: function(value) {\n    this[this.mainParameter] = value;\n  },\n\n  /**\n   * Send uniform data from this filter to its shader program on the GPU.\n   *\n   * Intended to be overridden by subclasses.\n   *\n   * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n   * @param {Object} uniformLocations A map of shader uniform names to their locations.\n   */\n  sendUniformData: function(/* gl, uniformLocations */) {\n    // Intentionally left blank.  Override me in subclasses.\n  },\n\n  /**\n   * If needed by a 2d filter, this functions can create an helper canvas to be used\n   * remember that options.targetCanvas is available for use till end of chain.\n   */\n  createHelpLayer: function(options) {\n    if (!options.helpLayer) {\n      var helpLayer = document.createElement('canvas');\n      helpLayer.width = options.sourceWidth;\n      helpLayer.height = options.sourceHeight;\n      options.helpLayer = helpLayer;\n    }\n  },\n\n  /**\n   * Returns object representation of an instance\n   * @return {Object} Object representation of an instance\n   */\n  toObject: function() {\n    var object = { type: this.type }, mainP = this.mainParameter;\n    if (mainP) {\n      object[mainP] = this[mainP];\n    }\n    return object;\n  },\n\n  /**\n   * Returns a JSON representation of an instance\n   * @return {Object} JSON\n   */\n  toJSON: function() {\n    // delegate, not alias\n    return this.toObject();\n  }\n});\n\nfabric.Image.filters.BaseFilter.fromObject = function(object, callback) {\n  var filter = new fabric.Image.filters[object.type](object);\n  callback && callback(filter);\n  return filter;\n};\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Color Matrix filter class\n   * @class fabric.Image.filters.ColorMatrix\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.ColorMatrix#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @see {@Link http://www.webwasp.co.uk/tutorials/219/Color_Matrix_Filter.php}\n   * @see {@Link http://phoboslab.org/log/2013/11/fast-image-filters-with-webgl}\n   * @example <caption>Kodachrome filter</caption>\n   * var filter = new fabric.Image.filters.ColorMatrix({\n   *  matrix: [\n       1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,\n       -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,\n       -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,\n       0, 0, 0, 1, 0\n      ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.ColorMatrix = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.ColorMatrix.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'ColorMatrix',\n\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'uniform mat4 uColorMatrix;\\n' +\n      'uniform vec4 uConstants;\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'color *= uColorMatrix;\\n' +\n        'color += uConstants;\\n' +\n        'gl_FragColor = color;\\n' +\n      '}',\n\n    /**\n     * Colormatrix for pixels.\n     * array of 20 floats. Numbers in positions 4, 9, 14, 19 loose meaning\n     * outside the -1, 1 range.\n     * 0.0039215686 is the part of 1 that get translated to 1 in 2d\n     * @param {Array} matrix array of 20 numbers.\n     * @default\n     */\n    matrix: [\n      1, 0, 0, 0, 0,\n      0, 1, 0, 0, 0,\n      0, 0, 1, 0, 0,\n      0, 0, 0, 1, 0\n    ],\n\n    mainParameter: 'matrix',\n\n    /**\n     * Lock the colormatrix on the color part, skipping alpha, mainly for non webgl scenario\n     * to save some calculation\n     * @type Boolean\n     * @default true\n     */\n    colorsOnly: true,\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      // create a new array instead mutating the prototype with push\n      this.matrix = this.matrix.slice(0);\n    },\n\n    /**\n     * Apply the ColorMatrix operation to a Uint8Array representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8Array to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          data = imageData.data,\n          iLen = data.length,\n          m = this.matrix,\n          r, g, b, a, i, colorsOnly = this.colorsOnly;\n\n      for (i = 0; i < iLen; i += 4) {\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n        if (colorsOnly) {\n          data[i] = r * m[0] + g * m[1] + b * m[2] + m[4] * 255;\n          data[i + 1] = r * m[5] + g * m[6] + b * m[7] + m[9] * 255;\n          data[i + 2] = r * m[10] + g * m[11] + b * m[12] + m[14] * 255;\n        }\n        else {\n          a = data[i + 3];\n          data[i] = r * m[0] + g * m[1] + b * m[2] + a * m[3] + m[4] * 255;\n          data[i + 1] = r * m[5] + g * m[6] + b * m[7] + a * m[8] + m[9] * 255;\n          data[i + 2] = r * m[10] + g * m[11] + b * m[12] + a * m[13] + m[14] * 255;\n          data[i + 3] = r * m[15] + g * m[16] + b * m[17] + a * m[18] + m[19] * 255;\n        }\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uColorMatrix: gl.getUniformLocation(program, 'uColorMatrix'),\n        uConstants: gl.getUniformLocation(program, 'uConstants'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      var m = this.matrix,\n          matrix = [\n            m[0], m[1], m[2], m[3],\n            m[5], m[6], m[7], m[8],\n            m[10], m[11], m[12], m[13],\n            m[15], m[16], m[17], m[18]\n          ],\n          constants = [m[4], m[9], m[14], m[19]];\n      gl.uniformMatrix4fv(uniformLocations.uColorMatrix, false, matrix);\n      gl.uniform4fv(uniformLocations.uConstants, constants);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] function to invoke after filter creation\n   * @return {fabric.Image.filters.ColorMatrix} Instance of fabric.Image.filters.ColorMatrix\n   */\n  fabric.Image.filters.ColorMatrix.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Brightness filter class\n   * @class fabric.Image.filters.Brightness\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Brightness#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Brightness({\n   *   brightness: 0.05\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.Brightness = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Brightness',\n\n    /**\n     * Fragment source for the brightness program\n     */\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform float uBrightness;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'color.rgb += uBrightness;\\n' +\n        'gl_FragColor = color;\\n' +\n      '}',\n\n    /**\n     * Brightness value, from -1 to 1.\n     * translated to -255 to 255 for 2d\n     * 0.0039215686 is the part of 1 that get translated to 1 in 2d\n     * @param {Number} brightness\n     * @default\n     */\n    brightness: 0,\n\n    /**\n     * Describe the property that is the filter parameter\n     * @param {String} m\n     * @default\n     */\n    mainParameter: 'brightness',\n\n    /**\n    * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.\n    *\n    * @param {Object} options\n    * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n    */\n    applyTo2d: function(options) {\n      if (this.brightness === 0) {\n        return;\n      }\n      var imageData = options.imageData,\n          data = imageData.data, i, len = data.length,\n          brightness = Math.round(this.brightness * 255);\n      for (i = 0; i < len; i += 4) {\n        data[i] = data[i] + brightness;\n        data[i + 1] = data[i + 1] + brightness;\n        data[i + 2] = data[i + 2] + brightness;\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uBrightness: gl.getUniformLocation(program, 'uBrightness'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1f(uniformLocations.uBrightness, this.brightness);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Brightness} Instance of fabric.Image.filters.Brightness\n   */\n  fabric.Image.filters.Brightness.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Adapted from <a href=\"http://www.html5rocks.com/en/tutorials/canvas/imagefilters/\">html5rocks article</a>\n   * @class fabric.Image.filters.Convolute\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Convolute#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example <caption>Sharpen filter</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 0, -1,  0,\n   *            -1,  5, -1,\n   *             0, -1,  0 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   * @example <caption>Blur filter</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 1/9, 1/9, 1/9,\n   *             1/9, 1/9, 1/9,\n   *             1/9, 1/9, 1/9 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   * @example <caption>Emboss filter</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   matrix: [ 1,   1,  1,\n   *             1, 0.7, -1,\n   *            -1,  -1, -1 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   * @example <caption>Emboss filter with opaqueness</caption>\n   * var filter = new fabric.Image.filters.Convolute({\n   *   opaque: true,\n   *   matrix: [ 1,   1,  1,\n   *             1, 0.7, -1,\n   *            -1,  -1, -1 ]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   */\n  filters.Convolute = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Convolute',\n\n    /*\n     * Opaque value (true/false)\n     */\n    opaque: false,\n\n    /*\n     * matrix for the filter, max 9x9\n     */\n    matrix: [0, 0, 0, 0, 1, 0, 0, 0, 0],\n\n    /**\n     * Fragment source for the brightness program\n     */\n    fragmentSource: {\n      Convolute_3_1: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[9];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 0);\\n' +\n          'for (float h = 0.0; h < 3.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 3.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 1), uStepH * (h - 1));\\n' +\n              'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 3.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'gl_FragColor = color;\\n' +\n        '}',\n      Convolute_3_0: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[9];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 1);\\n' +\n          'for (float h = 0.0; h < 3.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 3.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 1.0), uStepH * (h - 1.0));\\n' +\n              'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 3.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n          'gl_FragColor = color;\\n' +\n          'gl_FragColor.a = alpha;\\n' +\n        '}',\n      Convolute_5_1: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[25];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 0);\\n' +\n          'for (float h = 0.0; h < 5.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 5.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 2.0), uStepH * (h - 2.0));\\n' +\n              'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 5.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'gl_FragColor = color;\\n' +\n        '}',\n      Convolute_5_0: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[25];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 1);\\n' +\n          'for (float h = 0.0; h < 5.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 5.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 2.0), uStepH * (h - 2.0));\\n' +\n              'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 5.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n          'gl_FragColor = color;\\n' +\n          'gl_FragColor.a = alpha;\\n' +\n        '}',\n      Convolute_7_1: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[49];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 0);\\n' +\n          'for (float h = 0.0; h < 7.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 7.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 3.0), uStepH * (h - 3.0));\\n' +\n              'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 7.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'gl_FragColor = color;\\n' +\n        '}',\n      Convolute_7_0: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[49];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 1);\\n' +\n          'for (float h = 0.0; h < 7.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 7.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 3.0), uStepH * (h - 3.0));\\n' +\n              'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 7.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n          'gl_FragColor = color;\\n' +\n          'gl_FragColor.a = alpha;\\n' +\n        '}',\n      Convolute_9_1: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[81];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 0);\\n' +\n          'for (float h = 0.0; h < 9.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 9.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 4.0), uStepH * (h - 4.0));\\n' +\n              'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 9.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'gl_FragColor = color;\\n' +\n        '}',\n      Convolute_9_0: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform float uMatrix[81];\\n' +\n        'uniform float uStepW;\\n' +\n        'uniform float uStepH;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = vec4(0, 0, 0, 1);\\n' +\n          'for (float h = 0.0; h < 9.0; h+=1.0) {\\n' +\n            'for (float w = 0.0; w < 9.0; w+=1.0) {\\n' +\n              'vec2 matrixPos = vec2(uStepW * (w - 4.0), uStepH * (h - 4.0));\\n' +\n              'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 9.0 + w)];\\n' +\n            '}\\n' +\n          '}\\n' +\n          'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n          'gl_FragColor = color;\\n' +\n          'gl_FragColor.a = alpha;\\n' +\n        '}',\n    },\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Convolute.prototype\n     * @param {Object} [options] Options object\n     * @param {Boolean} [options.opaque=false] Opaque value (true/false)\n     * @param {Array} [options.matrix] Filter matrix\n     */\n\n\n    /**\n    * Retrieves the cached shader.\n    * @param {Object} options\n    * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n    * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n    */\n    retrieveShader: function(options) {\n      var size = Math.sqrt(this.matrix.length);\n      var cacheKey = this.type + '_' + size + '_' + (this.opaque ? 1 : 0);\n      var shaderSource = this.fragmentSource[cacheKey];\n      if (!options.programCache.hasOwnProperty(cacheKey)) {\n        options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n      }\n      return options.programCache[cacheKey];\n    },\n\n    /**\n     * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          data = imageData.data,\n          weights = this.matrix,\n          side = Math.round(Math.sqrt(weights.length)),\n          halfSide = Math.floor(side / 2),\n          sw = imageData.width,\n          sh = imageData.height,\n          output = options.ctx.createImageData(sw, sh),\n          dst = output.data,\n          // go through the destination image pixels\n          alphaFac = this.opaque ? 1 : 0,\n          r, g, b, a, dstOff,\n          scx, scy, srcOff, wt,\n          x, y, cx, cy;\n\n      for (y = 0; y < sh; y++) {\n        for (x = 0; x < sw; x++) {\n          dstOff = (y * sw + x) * 4;\n          // calculate the weighed sum of the source image pixels that\n          // fall under the convolution matrix\n          r = 0; g = 0; b = 0; a = 0;\n\n          for (cy = 0; cy < side; cy++) {\n            for (cx = 0; cx < side; cx++) {\n              scy = y + cy - halfSide;\n              scx = x + cx - halfSide;\n\n              // eslint-disable-next-line max-depth\n              if (scy < 0 || scy >= sh || scx < 0 || scx >= sw) {\n                continue;\n              }\n\n              srcOff = (scy * sw + scx) * 4;\n              wt = weights[cy * side + cx];\n\n              r += data[srcOff] * wt;\n              g += data[srcOff + 1] * wt;\n              b += data[srcOff + 2] * wt;\n              // eslint-disable-next-line max-depth\n              if (!alphaFac) {\n                a += data[srcOff + 3] * wt;\n              }\n            }\n          }\n          dst[dstOff] = r;\n          dst[dstOff + 1] = g;\n          dst[dstOff + 2] = b;\n          if (!alphaFac) {\n            dst[dstOff + 3] = a;\n          }\n          else {\n            dst[dstOff + 3] = data[dstOff + 3];\n          }\n        }\n      }\n      options.imageData = output;\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uMatrix: gl.getUniformLocation(program, 'uMatrix'),\n        uOpaque: gl.getUniformLocation(program, 'uOpaque'),\n        uHalfSize: gl.getUniformLocation(program, 'uHalfSize'),\n        uSize: gl.getUniformLocation(program, 'uSize'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1fv(uniformLocations.uMatrix, this.matrix);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        opaque: this.opaque,\n        matrix: this.matrix\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Convolute} Instance of fabric.Image.filters.Convolute\n   */\n  fabric.Image.filters.Convolute.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Grayscale image filter class\n   * @class fabric.Image.filters.Grayscale\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Grayscale();\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.Grayscale = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Grayscale',\n\n    fragmentSource: {\n      average: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n          'float average = (color.r + color.b + color.g) / 3.0;\\n' +\n          'gl_FragColor = vec4(average, average, average, color.a);\\n' +\n        '}',\n      lightness: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform int uMode;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 col = texture2D(uTexture, vTexCoord);\\n' +\n          'float average = (max(max(col.r, col.g),col.b) + min(min(col.r, col.g),col.b)) / 2.0;\\n' +\n          'gl_FragColor = vec4(average, average, average, col.a);\\n' +\n        '}',\n      luminosity: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform int uMode;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 col = texture2D(uTexture, vTexCoord);\\n' +\n          'float average = 0.21 * col.r + 0.72 * col.g + 0.07 * col.b;\\n' +\n          'gl_FragColor = vec4(average, average, average, col.a);\\n' +\n        '}',\n    },\n\n\n    /**\n     * Grayscale mode, between 'average', 'lightness', 'luminosity'\n     * @param {String} type\n     * @default\n     */\n    mode: 'average',\n\n    mainParameter: 'mode',\n\n    /**\n     * Apply the Grayscale operation to a Uint8Array representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8Array to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          data = imageData.data, i,\n          len = data.length, value,\n          mode = this.mode;\n      for (i = 0; i < len; i += 4) {\n        if (mode === 'average') {\n          value = (data[i] + data[i + 1] + data[i + 2]) / 3;\n        }\n        else if (mode === 'lightness') {\n          value = (Math.min(data[i], data[i + 1], data[i + 2]) +\n            Math.max(data[i], data[i + 1], data[i + 2])) / 2;\n        }\n        else if (mode === 'luminosity') {\n          value = 0.21 * data[i] + 0.72 * data[i + 1] + 0.07 * data[i + 2];\n        }\n        data[i] = value;\n        data[i + 1] = value;\n        data[i + 2] = value;\n      }\n    },\n\n    /**\n     * Retrieves the cached shader.\n     * @param {Object} options\n     * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n     * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n     */\n    retrieveShader: function(options) {\n      var cacheKey = this.type + '_' + this.mode;\n      if (!options.programCache.hasOwnProperty(cacheKey)) {\n        var shaderSource = this.fragmentSource[this.mode];\n        options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n      }\n      return options.programCache[cacheKey];\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uMode: gl.getUniformLocation(program, 'uMode'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      // default average mode.\n      var mode = 1;\n      gl.uniform1i(uniformLocations.uMode, mode);\n    },\n\n    /**\n     * Grayscale filter isNeutralState implementation\n     * The filter is never neutral\n     * on the image\n     **/\n    isNeutralState: function() {\n      return false;\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale\n   */\n  fabric.Image.filters.Grayscale.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Invert filter class\n   * @class fabric.Image.filters.Invert\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Invert();\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Invert = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Invert',\n\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform int uInvert;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'if (uInvert == 1) {\\n' +\n          'gl_FragColor = vec4(1.0 - color.r,1.0 -color.g,1.0 -color.b,color.a);\\n' +\n        '} else {\\n' +\n          'gl_FragColor = color;\\n' +\n        '}\\n' +\n      '}',\n\n    /**\n     * Filter invert. if false, does nothing\n     * @param {Boolean} invert\n     * @default\n     */\n    invert: true,\n\n    mainParameter: 'invert',\n\n    /**\n     * Apply the Invert operation to a Uint8Array representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8Array to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          data = imageData.data, i,\n          len = data.length;\n      for (i = 0; i < len; i += 4) {\n        data[i] = 255 - data[i];\n        data[i + 1] = 255 - data[i + 1];\n        data[i + 2] = 255 - data[i + 2];\n      }\n    },\n\n    /**\n     * Invert filter isNeutralState implementation\n     * Used only in image applyFilters to discard filters that will not have an effect\n     * on the image\n     * @param {Object} options\n     **/\n    isNeutralState: function() {\n      return !this.invert;\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uInvert: gl.getUniformLocation(program, 'uInvert'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1i(uniformLocations.uInvert, this.invert);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Invert} Instance of fabric.Image.filters.Invert\n   */\n  fabric.Image.filters.Invert.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Noise filter class\n   * @class fabric.Image.filters.Noise\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Noise#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Noise({\n   *   noise: 700\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   */\n  filters.Noise = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Noise',\n\n    /**\n     * Fragment source for the noise program\n     */\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform float uStepH;\\n' +\n      'uniform float uNoise;\\n' +\n      'uniform float uSeed;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'float rand(vec2 co, float seed, float vScale) {\\n' +\n        'return fract(sin(dot(co.xy * vScale ,vec2(12.9898 , 78.233))) * 43758.5453 * (seed + 0.01) / 2.0);\\n' +\n      '}\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'color.rgb += (0.5 - rand(vTexCoord, uSeed, 0.1 / uStepH)) * uNoise;\\n' +\n        'gl_FragColor = color;\\n' +\n      '}',\n\n    /**\n     * Describe the property that is the filter parameter\n     * @param {String} m\n     * @default\n     */\n    mainParameter: 'noise',\n\n    /**\n     * Noise value, from\n     * @param {Number} noise\n     * @default\n     */\n    noise: 0,\n\n    /**\n     * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n     */\n    applyTo2d: function(options) {\n      if (this.noise === 0) {\n        return;\n      }\n      var imageData = options.imageData,\n          data = imageData.data, i, len = data.length,\n          noise = this.noise, rand;\n\n      for (i = 0, len = data.length; i < len; i += 4) {\n\n        rand = (0.5 - Math.random()) * noise;\n\n        data[i] += rand;\n        data[i + 1] += rand;\n        data[i + 2] += rand;\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uNoise: gl.getUniformLocation(program, 'uNoise'),\n        uSeed: gl.getUniformLocation(program, 'uSeed'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1f(uniformLocations.uNoise, this.noise / 255);\n      gl.uniform1f(uniformLocations.uSeed, Math.random());\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        noise: this.noise\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Noise} Instance of fabric.Image.filters.Noise\n   */\n  fabric.Image.filters.Noise.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Pixelate filter class\n   * @class fabric.Image.filters.Pixelate\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Pixelate#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Pixelate({\n   *   blocksize: 8\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.Pixelate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Pixelate',\n\n    blocksize: 4,\n\n    mainParameter: 'blocksize',\n\n    /**\n     * Fragment source for the Pixelate program\n     */\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform float uBlocksize;\\n' +\n      'uniform float uStepW;\\n' +\n      'uniform float uStepH;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'float blockW = uBlocksize * uStepW;\\n' +\n        'float blockH = uBlocksize * uStepW;\\n' +\n        'int posX = int(vTexCoord.x / blockW);\\n' +\n        'int posY = int(vTexCoord.y / blockH);\\n' +\n        'float fposX = float(posX);\\n' +\n        'float fposY = float(posY);\\n' +\n        'vec2 squareCoords = vec2(fposX * blockW, fposY * blockH);\\n' +\n        'vec4 color = texture2D(uTexture, squareCoords);\\n' +\n        'gl_FragColor = color;\\n' +\n      '}',\n\n    /**\n     * Apply the Pixelate operation to a Uint8ClampedArray representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          data = imageData.data,\n          iLen = imageData.height,\n          jLen = imageData.width,\n          index, i, j, r, g, b, a,\n          _i, _j, _iLen, _jLen;\n\n      for (i = 0; i < iLen; i += this.blocksize) {\n        for (j = 0; j < jLen; j += this.blocksize) {\n\n          index = (i * 4) * jLen + (j * 4);\n\n          r = data[index];\n          g = data[index + 1];\n          b = data[index + 2];\n          a = data[index + 3];\n\n          _iLen = Math.min(i + this.blocksize, iLen);\n          _jLen = Math.min(j + this.blocksize, jLen);\n          for (_i = i; _i < _iLen; _i++) {\n            for (_j = j; _j < _jLen; _j++) {\n              index = (_i * 4) * jLen + (_j * 4);\n              data[index] = r;\n              data[index + 1] = g;\n              data[index + 2] = b;\n              data[index + 3] = a;\n            }\n          }\n        }\n      }\n    },\n\n    /**\n     * Indicate when the filter is not gonna apply changes to the image\n     **/\n    isNeutralState: function() {\n      return this.blocksize === 1;\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uBlocksize: gl.getUniformLocation(program, 'uBlocksize'),\n        uStepW: gl.getUniformLocation(program, 'uStepW'),\n        uStepH: gl.getUniformLocation(program, 'uStepH'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1f(uniformLocations.uBlocksize, this.blocksize);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Pixelate} Instance of fabric.Image.filters.Pixelate\n   */\n  fabric.Image.filters.Pixelate.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      extend = fabric.util.object.extend,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Remove white filter class\n   * @class fabric.Image.filters.RemoveColor\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.RemoveColor#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.RemoveColor({\n   *   threshold: 0.2,\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   */\n  filters.RemoveColor = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.RemoveColor.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'RemoveColor',\n\n    /**\n     * Color to remove, in any format understood by fabric.Color.\n     * @param {String} type\n     * @default\n     */\n    color: '#FFFFFF',\n\n    /**\n     * Fragment source for the brightness program\n     */\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform vec4 uLow;\\n' +\n      'uniform vec4 uHigh;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'gl_FragColor = texture2D(uTexture, vTexCoord);\\n' +\n        'if(all(greaterThan(gl_FragColor.rgb,uLow.rgb)) && all(greaterThan(uHigh.rgb,gl_FragColor.rgb))) {\\n' +\n          'gl_FragColor.a = 0.0;\\n' +\n        '}\\n' +\n      '}',\n\n    /**\n     * distance to actual color, as value up or down from each r,g,b\n     * between 0 and 1\n     **/\n    distance: 0.02,\n\n    /**\n     * For color to remove inside distance, use alpha channel for a smoother deletion\n     * NOT IMPLEMENTED YET\n     **/\n    useAlpha: false,\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.RemoveWhite.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.color=#RRGGBB] Threshold value\n     * @param {Number} [options.distance=10] Distance value\n     */\n\n    /**\n     * Applies filter to canvas element\n     * @param {Object} canvasEl Canvas element to apply filter to\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          data = imageData.data, i,\n          distance = this.distance * 255,\n          r, g, b,\n          source = new fabric.Color(this.color).getSource(),\n          lowC = [\n            source[0] - distance,\n            source[1] - distance,\n            source[2] - distance,\n          ],\n          highC = [\n            source[0] + distance,\n            source[1] + distance,\n            source[2] + distance,\n          ];\n\n\n      for (i = 0; i < data.length; i += 4) {\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n\n        if (r > lowC[0] &&\n            g > lowC[1] &&\n            b > lowC[2] &&\n            r < highC[0] &&\n            g < highC[1] &&\n            b < highC[2]) {\n          data[i + 3] = 0;\n        }\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uLow: gl.getUniformLocation(program, 'uLow'),\n        uHigh: gl.getUniformLocation(program, 'uHigh'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      var source = new fabric.Color(this.color).getSource(),\n          distance = parseFloat(this.distance),\n          lowC = [\n            0 + source[0] / 255 - distance,\n            0 + source[1] / 255 - distance,\n            0 + source[2] / 255 - distance,\n            1\n          ],\n          highC = [\n            source[0] / 255 + distance,\n            source[1] / 255 + distance,\n            source[2] / 255 + distance,\n            1\n          ];\n      gl.uniform4fv(uniformLocations.uLow, lowC);\n      gl.uniform4fv(uniformLocations.uHigh, highC);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return extend(this.callSuper('toObject'), {\n        color: this.color,\n        distance: this.distance\n      });\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.RemoveColor} Instance of fabric.Image.filters.RemoveWhite\n   */\n  fabric.Image.filters.RemoveColor.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  var matrices = {\n    Brownie: [\n      0.59970,0.34553,-0.27082,0,0.186,\n      -0.03770,0.86095,0.15059,0,-0.1449,\n      0.24113,-0.07441,0.44972,0,-0.02965,\n      0,0,0,1,0\n    ],\n    Vintage: [\n      0.62793,0.32021,-0.03965,0,0.03784,\n      0.02578,0.64411,0.03259,0,0.02926,\n      0.04660,-0.08512,0.52416,0,0.02023,\n      0,0,0,1,0\n    ],\n    Kodachrome: [\n      1.12855,-0.39673,-0.03992,0,0.24991,\n      -0.16404,1.08352,-0.05498,0,0.09698,\n      -0.16786,-0.56034,1.60148,0,0.13972,\n      0,0,0,1,0\n    ],\n    Technicolor: [\n      1.91252,-0.85453,-0.09155,0,0.04624,\n      -0.30878,1.76589,-0.10601,0,-0.27589,\n      -0.23110,-0.75018,1.84759,0,0.12137,\n      0,0,0,1,0\n    ],\n    Polaroid: [\n      1.438,-0.062,-0.062,0,0,\n      -0.122,1.378,-0.122,0,0,\n      -0.016,-0.016,1.483,0,0,\n      0,0,0,1,0\n    ],\n    Sepia: [\n      0.393, 0.769, 0.189, 0, 0,\n      0.349, 0.686, 0.168, 0, 0,\n      0.272, 0.534, 0.131, 0, 0,\n      0, 0, 0, 1, 0\n    ],\n    BlackWhite: [\n      1.5, 1.5, 1.5, 0, -1,\n      1.5, 1.5, 1.5, 0, -1,\n      1.5, 1.5, 1.5, 0, -1,\n      0, 0, 0, 1, 0,\n    ]\n  };\n\n  for (var key in matrices) {\n    filters[key] = createClass(filters.ColorMatrix, /** @lends fabric.Image.filters.Sepia.prototype */ {\n\n      /**\n       * Filter type\n       * @param {String} type\n       * @default\n       */\n      type: key,\n\n      /**\n       * Colormatrix for the effect\n       * array of 20 floats. Numbers in positions 4, 9, 14, 19 loose meaning\n       * outside the -1, 1 range.\n       * @param {Array} matrix array of 20 numbers.\n       * @default\n       */\n      matrix: matrices[key],\n\n      /**\n       * Lock the matrix export for this kind of static, parameter less filters.\n       */\n      mainParameter: false,\n      /**\n       * Lock the colormatrix on the color part, skipping alpha\n       */\n      colorsOnly: true,\n\n    });\n    fabric.Image.filters[key].fromObject = fabric.Image.filters.BaseFilter.fromObject;\n  }\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n  'use strict';\n\n  var fabric = global.fabric,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Color Blend filter class\n   * @class fabric.Image.filter.BlendColor\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @example\n   * var filter = new fabric.Image.filters.BlendColor({\n   *  color: '#000',\n   *  mode: 'multiply'\n   * });\n   *\n   * var filter = new fabric.Image.filters.BlendImage({\n   *  image: fabricImageObject,\n   *  mode: 'multiply',\n   *  alpha: 0.5\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   */\n\n  filters.BlendColor = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blend.prototype */ {\n    type: 'BlendColor',\n\n    /**\n     * Color to make the blend operation with. default to a reddish color since black or white\n     * gives always strong result.\n     * @type String\n     * @default\n     **/\n    color: '#F95C63',\n\n    /**\n     * Blend mode for the filter: one of multiply, add, diff, screen, subtract,\n     * darken, lighten, overlay, exclusion, tint.\n     * @type String\n     * @default\n     **/\n    mode: 'multiply',\n\n    /**\n     * alpha value. represent the strength of the blend color operation.\n     * @type Number\n     * @default\n     **/\n    alpha: 1,\n\n    /**\n     * Fragment source for the Multiply program\n     */\n    fragmentSource: {\n      multiply: 'gl_FragColor.rgb *= uColor.rgb;\\n',\n      screen: 'gl_FragColor.rgb = 1.0 - (1.0 - gl_FragColor.rgb) * (1.0 - uColor.rgb);\\n',\n      add: 'gl_FragColor.rgb += uColor.rgb;\\n',\n      diff: 'gl_FragColor.rgb = abs(gl_FragColor.rgb - uColor.rgb);\\n',\n      subtract: 'gl_FragColor.rgb -= uColor.rgb;\\n',\n      lighten: 'gl_FragColor.rgb = max(gl_FragColor.rgb, uColor.rgb);\\n',\n      darken: 'gl_FragColor.rgb = min(gl_FragColor.rgb, uColor.rgb);\\n',\n      exclusion: 'gl_FragColor.rgb += uColor.rgb - 2.0 * (uColor.rgb * gl_FragColor.rgb);\\n',\n      overlay: 'if (uColor.r < 0.5) {\\n' +\n          'gl_FragColor.r *= 2.0 * uColor.r;\\n' +\n        '} else {\\n' +\n          'gl_FragColor.r = 1.0 - 2.0 * (1.0 - gl_FragColor.r) * (1.0 - uColor.r);\\n' +\n        '}\\n' +\n        'if (uColor.g < 0.5) {\\n' +\n          'gl_FragColor.g *= 2.0 * uColor.g;\\n' +\n        '} else {\\n' +\n          'gl_FragColor.g = 1.0 - 2.0 * (1.0 - gl_FragColor.g) * (1.0 - uColor.g);\\n' +\n        '}\\n' +\n        'if (uColor.b < 0.5) {\\n' +\n          'gl_FragColor.b *= 2.0 * uColor.b;\\n' +\n        '} else {\\n' +\n          'gl_FragColor.b = 1.0 - 2.0 * (1.0 - gl_FragColor.b) * (1.0 - uColor.b);\\n' +\n        '}\\n',\n      tint: 'gl_FragColor.rgb *= (1.0 - uColor.a);\\n' +\n        'gl_FragColor.rgb += uColor.rgb;\\n',\n    },\n\n    /**\n     * build the fragment source for the filters, joining the common part with\n     * the specific one.\n     * @param {String} mode the mode of the filter, a key of this.fragmentSource\n     * @return {String} the source to be compiled\n     * @private\n     */\n    buildSource: function(mode) {\n      return 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform vec4 uColor;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'void main() {\\n' +\n          'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n          'gl_FragColor = color;\\n' +\n          'if (color.a > 0.0) {\\n' +\n            this.fragmentSource[mode] +\n          '}\\n' +\n        '}';\n    },\n\n    /**\n     * Retrieves the cached shader.\n     * @param {Object} options\n     * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n     * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n     */\n    retrieveShader: function(options) {\n      var cacheKey = this.type + '_' + this.mode, shaderSource;\n      if (!options.programCache.hasOwnProperty(cacheKey)) {\n        shaderSource = this.buildSource(this.mode);\n        options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n      }\n      return options.programCache[cacheKey];\n    },\n\n    /**\n     * Apply the Blend operation to a Uint8ClampedArray representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          data = imageData.data, iLen = data.length,\n          tr, tg, tb,\n          r, g, b,\n          source, alpha1 = 1 - this.alpha;\n\n      source = new fabric.Color(this.color).getSource();\n      tr = source[0] * this.alpha;\n      tg = source[1] * this.alpha;\n      tb = source[2] * this.alpha;\n\n      for (var i = 0; i < iLen; i += 4) {\n\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n\n        switch (this.mode) {\n          case 'multiply':\n            data[i] = r * tr / 255;\n            data[i + 1] = g * tg / 255;\n            data[i + 2] = b * tb / 255;\n            break;\n          case 'screen':\n            data[i] = 255 - (255 - r) * (255 - tr) / 255;\n            data[i + 1] = 255 - (255 - g) * (255 - tg) / 255;\n            data[i + 2] = 255 - (255 - b) * (255 - tb) / 255;\n            break;\n          case 'add':\n            data[i] = r + tr;\n            data[i + 1] = g + tg;\n            data[i + 2] = b + tb;\n            break;\n          case 'diff':\n          case 'difference':\n            data[i] = Math.abs(r - tr);\n            data[i + 1] = Math.abs(g - tg);\n            data[i + 2] = Math.abs(b - tb);\n            break;\n          case 'subtract':\n            data[i] = r - tr;\n            data[i + 1] = g - tg;\n            data[i + 2] = b - tb;\n            break;\n          case 'darken':\n            data[i] = Math.min(r, tr);\n            data[i + 1] = Math.min(g, tg);\n            data[i + 2] = Math.min(b, tb);\n            break;\n          case 'lighten':\n            data[i] = Math.max(r, tr);\n            data[i + 1] = Math.max(g, tg);\n            data[i + 2] = Math.max(b, tb);\n            break;\n          case 'overlay':\n            data[i] = tr < 128 ? (2 * r * tr / 255) : (255 - 2 * (255 - r) * (255 - tr) / 255);\n            data[i + 1] = tg < 128 ? (2 * g * tg / 255) : (255 - 2 * (255 - g) * (255 - tg) / 255);\n            data[i + 2] = tb < 128 ? (2 * b * tb / 255) : (255 - 2 * (255 - b) * (255 - tb) / 255);\n            break;\n          case 'exclusion':\n            data[i] = tr + r - ((2 * tr * r) / 255);\n            data[i + 1] = tg + g - ((2 * tg * g) / 255);\n            data[i + 2] = tb + b - ((2 * tb * b) / 255);\n            break;\n          case 'tint':\n            data[i] = tr + r * alpha1;\n            data[i + 1] = tg + g * alpha1;\n            data[i + 2] = tb + b * alpha1;\n        }\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uColor: gl.getUniformLocation(program, 'uColor'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      var source = new fabric.Color(this.color).getSource();\n      source[0] = this.alpha * source[0] / 255;\n      source[1] = this.alpha * source[1] / 255;\n      source[2] = this.alpha * source[2] / 255;\n      source[3] = this.alpha;\n      gl.uniform4fv(uniformLocations.uColor, source);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return {\n        type: this.type,\n        color: this.color,\n        mode: this.mode,\n        alpha: this.alpha\n      };\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.BlendColor} Instance of fabric.Image.filters.BlendColor\n   */\n  fabric.Image.filters.BlendColor.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n  'use strict';\n\n  var fabric = global.fabric,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Image Blend filter class\n   * @class fabric.Image.filter.BlendImage\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @example\n   * var filter = new fabric.Image.filters.BlendColor({\n   *  color: '#000',\n   *  mode: 'multiply'\n   * });\n   *\n   * var filter = new fabric.Image.filters.BlendImage({\n   *  image: fabricImageObject,\n   *  mode: 'multiply',\n   *  alpha: 0.5\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   */\n\n  filters.BlendImage = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.BlendImage.prototype */ {\n    type: 'BlendImage',\n\n    /**\n     * Color to make the blend operation with. default to a reddish color since black or white\n     * gives always strong result.\n     **/\n    image: null,\n\n    /**\n     * Blend mode for the filter (one of \"multiply\", \"mask\")\n     * @type String\n     * @default\n     **/\n    mode: 'multiply',\n\n    /**\n     * alpha value. represent the strength of the blend image operation.\n     * not implemented.\n     **/\n    alpha: 1,\n\n    vertexSource: 'attribute vec2 aPosition;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'varying vec2 vTexCoord2;\\n' +\n      'uniform mat3 uTransformMatrix;\\n' +\n      'void main() {\\n' +\n        'vTexCoord = aPosition;\\n' +\n        'vTexCoord2 = (uTransformMatrix * vec3(aPosition, 1.0)).xy;\\n' +\n        'gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);\\n' +\n      '}',\n\n    /**\n     * Fragment source for the Multiply program\n     */\n    fragmentSource: {\n      multiply: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform sampler2D uImage;\\n' +\n        'uniform vec4 uColor;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'varying vec2 vTexCoord2;\\n' +\n        'void main() {\\n' +\n          'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n          'vec4 color2 = texture2D(uImage, vTexCoord2);\\n' +\n          'color.rgba *= color2.rgba;\\n' +\n          'gl_FragColor = color;\\n' +\n        '}',\n      mask: 'precision highp float;\\n' +\n        'uniform sampler2D uTexture;\\n' +\n        'uniform sampler2D uImage;\\n' +\n        'uniform vec4 uColor;\\n' +\n        'varying vec2 vTexCoord;\\n' +\n        'varying vec2 vTexCoord2;\\n' +\n        'void main() {\\n' +\n          'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n          'vec4 color2 = texture2D(uImage, vTexCoord2);\\n' +\n          'color.a = color2.a;\\n' +\n          'gl_FragColor = color;\\n' +\n        '}',\n    },\n\n    /**\n     * Retrieves the cached shader.\n     * @param {Object} options\n     * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n     * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n     */\n    retrieveShader: function(options) {\n      var cacheKey = this.type + '_' + this.mode;\n      var shaderSource = this.fragmentSource[this.mode];\n      if (!options.programCache.hasOwnProperty(cacheKey)) {\n        options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n      }\n      return options.programCache[cacheKey];\n    },\n\n    applyToWebGL: function(options) {\n      // load texture to blend.\n      var gl = options.context,\n          texture = this.createTexture(options.filterBackend, this.image);\n      this.bindAdditionalTexture(gl, texture, gl.TEXTURE1);\n      this.callSuper('applyToWebGL', options);\n      this.unbindAdditionalTexture(gl, gl.TEXTURE1);\n    },\n\n    createTexture: function(backend, image) {\n      return backend.getCachedTexture(image.cacheKey, image._element);\n    },\n\n    /**\n     * Calculate a transformMatrix to adapt the image to blend over\n     * @param {Object} options\n     * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n     * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n     */\n    calculateMatrix: function() {\n      var image = this.image,\n          width = image._element.width,\n          height = image._element.height;\n      return [\n        1 / image.scaleX, 0, 0,\n        0, 1 / image.scaleY, 0,\n        -image.left / width, -image.top / height, 1\n      ];\n    },\n\n    /**\n     * Apply the Blend operation to a Uint8ClampedArray representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          resources = options.filterBackend.resources,\n          data = imageData.data, iLen = data.length,\n          width = imageData.width,\n          height = imageData.height,\n          tr, tg, tb, ta,\n          r, g, b, a,\n          canvas1, context, image = this.image, blendData;\n\n      if (!resources.blendImage) {\n        resources.blendImage = fabric.util.createCanvasElement();\n      }\n      canvas1 = resources.blendImage;\n      context = canvas1.getContext('2d');\n      if (canvas1.width !== width || canvas1.height !== height) {\n        canvas1.width = width;\n        canvas1.height = height;\n      }\n      else {\n        context.clearRect(0, 0, width, height);\n      }\n      context.setTransform(image.scaleX, 0, 0, image.scaleY, image.left, image.top);\n      context.drawImage(image._element, 0, 0, width, height);\n      blendData = context.getImageData(0, 0, width, height).data;\n      for (var i = 0; i < iLen; i += 4) {\n\n        r = data[i];\n        g = data[i + 1];\n        b = data[i + 2];\n        a = data[i + 3];\n\n        tr = blendData[i];\n        tg = blendData[i + 1];\n        tb = blendData[i + 2];\n        ta = blendData[i + 3];\n\n        switch (this.mode) {\n          case 'multiply':\n            data[i] = r * tr / 255;\n            data[i + 1] = g * tg / 255;\n            data[i + 2] = b * tb / 255;\n            data[i + 3] = a * ta / 255;\n            break;\n          case 'mask':\n            data[i + 3] = ta;\n            break;\n        }\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uTransformMatrix: gl.getUniformLocation(program, 'uTransformMatrix'),\n        uImage: gl.getUniformLocation(program, 'uImage'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      var matrix = this.calculateMatrix();\n      gl.uniform1i(uniformLocations.uImage, 1); // texture unit 1.\n      gl.uniformMatrix3fv(uniformLocations.uTransformMatrix, false, matrix);\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return {\n        type: this.type,\n        image: this.image && this.image.toObject(),\n        mode: this.mode,\n        alpha: this.alpha\n      };\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} callback to be invoked after filter creation\n   * @return {fabric.Image.filters.BlendImage} Instance of fabric.Image.filters.BlendImage\n   */\n  fabric.Image.filters.BlendImage.fromObject = function(object, callback) {\n    fabric.Image.fromObject(object.image, function(image) {\n      var options = fabric.util.object.clone(object);\n      options.image = image;\n      callback(new fabric.Image.filters.BlendImage(options));\n    });\n  };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }), pow = Math.pow, floor = Math.floor,\n      sqrt = Math.sqrt, abs = Math.abs, round = Math.round, sin = Math.sin,\n      ceil = Math.ceil,\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Resize image filter class\n   * @class fabric.Image.filters.Resize\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Resize();\n   * object.filters.push(filter);\n   * object.applyFilters(canvas.renderAll.bind(canvas));\n   */\n  filters.Resize = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Resize.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Resize',\n\n    /**\n     * Resize type\n     * for webgl resizeType is just lanczos, for canvas2d can be:\n     * bilinear, hermite, sliceHack, lanczos.\n     * @param {String} resizeType\n     * @default\n     */\n    resizeType: 'hermite',\n\n    /**\n     * Scale factor for resizing, x axis\n     * @param {Number} scaleX\n     * @default\n     */\n    scaleX: 1,\n\n    /**\n     * Scale factor for resizing, y axis\n     * @param {Number} scaleY\n     * @default\n     */\n    scaleY: 1,\n\n    /**\n     * LanczosLobes parameter for lanczos filter, valid for resizeType lanczos\n     * @param {Number} lanczosLobes\n     * @default\n     */\n    lanczosLobes: 3,\n\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uDelta: gl.getUniformLocation(program, 'uDelta'),\n        uTaps: gl.getUniformLocation(program, 'uTaps'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform2fv(uniformLocations.uDelta, this.horizontal ? [1 / this.width, 0] : [0, 1 / this.height]);\n      gl.uniform1fv(uniformLocations.uTaps, this.taps);\n    },\n\n    /**\n     * Retrieves the cached shader.\n     * @param {Object} options\n     * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n     * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n     */\n    retrieveShader: function(options) {\n      var filterWindow = this.getFilterWindow(), cacheKey = this.type + '_' + filterWindow;\n      if (!options.programCache.hasOwnProperty(cacheKey)) {\n        var fragmentShader = this.generateShader(filterWindow);\n        options.programCache[cacheKey] = this.createProgram(options.context, fragmentShader);\n      }\n      return options.programCache[cacheKey];\n    },\n\n    getFilterWindow: function() {\n      var scale = this.tempScale;\n      return Math.ceil(this.lanczosLobes / scale);\n    },\n\n    getTaps: function() {\n      var lobeFunction = this.lanczosCreate(this.lanczosLobes), scale = this.tempScale,\n          filterWindow = this.getFilterWindow(), taps = new Array(filterWindow);\n      for (var i = 1; i <= filterWindow; i++) {\n        taps[i - 1] = lobeFunction(i * scale);\n      }\n      return taps;\n    },\n\n    /**\n     * Generate vertex and shader sources from the necessary steps numbers\n     * @param {Number} filterWindow\n     */\n    generateShader: function(filterWindow) {\n      var offsets = new Array(filterWindow),\n          fragmentShader = this.fragmentSourceTOP, filterWindow;\n\n      for (var i = 1; i <= filterWindow; i++) {\n        offsets[i - 1] = i + '.0 * uDelta';\n      }\n\n      fragmentShader += 'uniform float uTaps[' + filterWindow + '];\\n';\n      fragmentShader += 'void main() {\\n';\n      fragmentShader += '  vec4 color = texture2D(uTexture, vTexCoord);\\n';\n      fragmentShader += '  float sum = 1.0;\\n';\n\n      offsets.forEach(function(offset, i) {\n        fragmentShader += '  color += texture2D(uTexture, vTexCoord + ' + offset + ') * uTaps[' + i + '];\\n';\n        fragmentShader += '  color += texture2D(uTexture, vTexCoord - ' + offset + ') * uTaps[' + i + '];\\n';\n        fragmentShader += '  sum += 2.0 * uTaps[' + i + '];\\n';\n      });\n      fragmentShader += '  gl_FragColor = color / sum;\\n';\n      fragmentShader += '}';\n      return fragmentShader;\n    },\n\n    fragmentSourceTOP: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform vec2 uDelta;\\n' +\n      'varying vec2 vTexCoord;\\n',\n\n    /**\n     * Apply the resize filter to the image\n     * Determines whether to use WebGL or Canvas2D based on the options.webgl flag.\n     *\n     * @param {Object} options\n     * @param {Number} options.passes The number of filters remaining to be executed\n     * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n     * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n     * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n     * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n     * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n     */\n    applyTo: function(options) {\n      if (options.webgl) {\n        options.passes++;\n        this.width = options.sourceWidth;\n        this.horizontal = true;\n        this.dW = Math.round(this.width * this.scaleX);\n        this.dH = options.sourceHeight;\n        this.tempScale = this.dW / this.width;\n        this.taps = this.getTaps();\n        options.destinationWidth = this.dW;\n        this._setupFrameBuffer(options);\n        this.applyToWebGL(options);\n        this._swapTextures(options);\n        options.sourceWidth = options.destinationWidth;\n\n        this.height = options.sourceHeight;\n        this.horizontal = false;\n        this.dH = Math.round(this.height * this.scaleY);\n        this.tempScale = this.dH / this.height;\n        this.taps = this.getTaps();\n        options.destinationHeight = this.dH;\n        this._setupFrameBuffer(options);\n        this.applyToWebGL(options);\n        this._swapTextures(options);\n        options.sourceHeight = options.destinationHeight;\n      }\n      else {\n        this.applyTo2d(options);\n      }\n    },\n\n    isNeutralState: function() {\n      return this.scaleX === 1 && this.scaleY === 1;\n    },\n\n    lanczosCreate: function(lobes) {\n      return function(x) {\n        if (x >= lobes || x <= -lobes) {\n          return 0.0;\n        }\n        if (x < 1.19209290E-07 && x > -1.19209290E-07) {\n          return 1.0;\n        }\n        x *= Math.PI;\n        var xx = x / lobes;\n        return (sin(x) / x) * sin(xx) / xx;\n      };\n    },\n\n    /**\n     * Applies filter to canvas element\n     * @memberOf fabric.Image.filters.Resize.prototype\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} scaleX\n     * @param {Number} scaleY\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData,\n          scaleX = this.scaleX,\n          scaleY = this.scaleY;\n\n      this.rcpScaleX = 1 / scaleX;\n      this.rcpScaleY = 1 / scaleY;\n\n      var oW = imageData.width, oH = imageData.height,\n          dW = round(oW * scaleX), dH = round(oH * scaleY),\n          newData;\n\n      if (this.resizeType === 'sliceHack') {\n        newData = this.sliceByTwo(options, oW, oH, dW, dH);\n      }\n      else if (this.resizeType === 'hermite') {\n        newData = this.hermiteFastResize(options, oW, oH, dW, dH);\n      }\n      else if (this.resizeType === 'bilinear') {\n        newData = this.bilinearFiltering(options, oW, oH, dW, dH);\n      }\n      else if (this.resizeType === 'lanczos') {\n        newData = this.lanczosResize(options, oW, oH, dW, dH);\n      }\n      options.imageData = newData;\n    },\n\n    /**\n     * Filter sliceByTwo\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    sliceByTwo: function(options, oW, oH, dW, dH) {\n      var imageData = options.imageData,\n          mult = 0.5, doneW = false, doneH = false, stepW = oW * mult,\n          stepH = oH * mult, resources = fabric.filterBackend.resources,\n          tmpCanvas, ctx, sX = 0, sY = 0, dX = oW, dY = 0;\n      if (!resources.sliceByTwo) {\n        resources.sliceByTwo = document.createElement('canvas');\n      }\n      tmpCanvas = resources.sliceByTwo;\n      if (tmpCanvas.width < oW * 1.5 || tmpCanvas.height < oH) {\n        tmpCanvas.width = oW * 1.5;\n        tmpCanvas.height = oH;\n      }\n      ctx = tmpCanvas.getContext('2d');\n      ctx.clearRect(0, 0, oW * 1.5, oH);\n      ctx.putImageData(imageData, 0, 0);\n\n      dW = floor(dW);\n      dH = floor(dH);\n\n      while (!doneW || !doneH) {\n        oW = stepW;\n        oH = stepH;\n        if (dW < floor(stepW * mult)) {\n          stepW = floor(stepW * mult);\n        }\n        else {\n          stepW = dW;\n          doneW = true;\n        }\n        if (dH < floor(stepH * mult)) {\n          stepH = floor(stepH * mult);\n        }\n        else {\n          stepH = dH;\n          doneH = true;\n        }\n        ctx.drawImage(tmpCanvas, sX, sY, oW, oH, dX, dY, stepW, stepH);\n        sX = dX;\n        sY = dY;\n        dY += stepH;\n      }\n      return ctx.getImageData(sX, sY, dW, dH);\n    },\n\n    /**\n     * Filter lanczosResize\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    lanczosResize: function(options, oW, oH, dW, dH) {\n\n      function process(u) {\n        var v, i, weight, idx, a, red, green,\n            blue, alpha, fX, fY;\n        center.x = (u + 0.5) * ratioX;\n        icenter.x = floor(center.x);\n        for (v = 0; v < dH; v++) {\n          center.y = (v + 0.5) * ratioY;\n          icenter.y = floor(center.y);\n          a = 0; red = 0; green = 0; blue = 0; alpha = 0;\n          for (i = icenter.x - range2X; i <= icenter.x + range2X; i++) {\n            if (i < 0 || i >= oW) {\n              continue;\n            }\n            fX = floor(1000 * abs(i - center.x));\n            if (!cacheLanc[fX]) {\n              cacheLanc[fX] = { };\n            }\n            for (var j = icenter.y - range2Y; j <= icenter.y + range2Y; j++) {\n              if (j < 0 || j >= oH) {\n                continue;\n              }\n              fY = floor(1000 * abs(j - center.y));\n              if (!cacheLanc[fX][fY]) {\n                cacheLanc[fX][fY] = lanczos(sqrt(pow(fX * rcpRatioX, 2) + pow(fY * rcpRatioY, 2)) / 1000);\n              }\n              weight = cacheLanc[fX][fY];\n              if (weight > 0) {\n                idx = (j * oW + i) * 4;\n                a += weight;\n                red += weight * srcData[idx];\n                green += weight * srcData[idx + 1];\n                blue += weight * srcData[idx + 2];\n                alpha += weight * srcData[idx + 3];\n              }\n            }\n          }\n          idx = (v * dW + u) * 4;\n          destData[idx] = red / a;\n          destData[idx + 1] = green / a;\n          destData[idx + 2] = blue / a;\n          destData[idx + 3] = alpha / a;\n        }\n\n        if (++u < dW) {\n          return process(u);\n        }\n        else {\n          return destImg;\n        }\n      }\n\n      var srcData = options.imageData.data,\n          destImg = options.ctx.createImageData(dW, dH),\n          destData = destImg.data,\n          lanczos = this.lanczosCreate(this.lanczosLobes),\n          ratioX = this.rcpScaleX, ratioY = this.rcpScaleY,\n          rcpRatioX = 2 / this.rcpScaleX, rcpRatioY = 2 / this.rcpScaleY,\n          range2X = ceil(ratioX * this.lanczosLobes / 2),\n          range2Y = ceil(ratioY * this.lanczosLobes / 2),\n          cacheLanc = { }, center = { }, icenter = { };\n\n      return process(0);\n    },\n\n    /**\n     * bilinearFiltering\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    bilinearFiltering: function(options, oW, oH, dW, dH) {\n      var a, b, c, d, x, y, i, j, xDiff, yDiff, chnl,\n          color, offset = 0, origPix, ratioX = this.rcpScaleX,\n          ratioY = this.rcpScaleY,\n          w4 = 4 * (oW - 1), img = options.imageData,\n          pixels = img.data, destImage = options.ctx.createImageData(dW, dH),\n          destPixels = destImage.data;\n      for (i = 0; i < dH; i++) {\n        for (j = 0; j < dW; j++) {\n          x = floor(ratioX * j);\n          y = floor(ratioY * i);\n          xDiff = ratioX * j - x;\n          yDiff = ratioY * i - y;\n          origPix = 4 * (y * oW + x);\n\n          for (chnl = 0; chnl < 4; chnl++) {\n            a = pixels[origPix + chnl];\n            b = pixels[origPix + 4 + chnl];\n            c = pixels[origPix + w4 + chnl];\n            d = pixels[origPix + w4 + 4 + chnl];\n            color = a * (1 - xDiff) * (1 - yDiff) + b * xDiff * (1 - yDiff) +\n                    c * yDiff * (1 - xDiff) + d * xDiff * yDiff;\n            destPixels[offset++] = color;\n          }\n        }\n      }\n      return destImage;\n    },\n\n    /**\n     * hermiteFastResize\n     * @param {Object} canvasEl Canvas element to apply filter to\n     * @param {Number} oW Original Width\n     * @param {Number} oH Original Height\n     * @param {Number} dW Destination Width\n     * @param {Number} dH Destination Height\n     * @returns {ImageData}\n     */\n    hermiteFastResize: function(options, oW, oH, dW, dH) {\n      var ratioW = this.rcpScaleX, ratioH = this.rcpScaleY,\n          ratioWHalf = ceil(ratioW / 2),\n          ratioHHalf = ceil(ratioH / 2),\n          img = options.imageData, data = img.data,\n          img2 = options.ctx.createImageData(dW, dH), data2 = img2.data;\n      for (var j = 0; j < dH; j++) {\n        for (var i = 0; i < dW; i++) {\n          var x2 = (i + j * dW) * 4, weight = 0, weights = 0, weightsAlpha = 0,\n              gxR = 0, gxG = 0, gxB = 0, gxA = 0, centerY = (j + 0.5) * ratioH;\n          for (var yy = floor(j * ratioH); yy < (j + 1) * ratioH; yy++) {\n            var dy = abs(centerY - (yy + 0.5)) / ratioHHalf,\n                centerX = (i + 0.5) * ratioW, w0 = dy * dy;\n            for (var xx = floor(i * ratioW); xx < (i + 1) * ratioW; xx++) {\n              var dx = abs(centerX - (xx + 0.5)) / ratioWHalf,\n                  w = sqrt(w0 + dx * dx);\n              /* eslint-disable max-depth */\n              if (w > 1 && w < -1) {\n                continue;\n              }\n              //hermite filter\n              weight = 2 * w * w * w - 3 * w * w + 1;\n              if (weight > 0) {\n                dx = 4 * (xx + yy * oW);\n                //alpha\n                gxA += weight * data[dx + 3];\n                weightsAlpha += weight;\n                //colors\n                if (data[dx + 3] < 255) {\n                  weight = weight * data[dx + 3] / 250;\n                }\n                gxR += weight * data[dx];\n                gxG += weight * data[dx + 1];\n                gxB += weight * data[dx + 2];\n                weights += weight;\n              }\n              /* eslint-enable max-depth */\n            }\n          }\n          data2[x2] = gxR / weights;\n          data2[x2 + 1] = gxG / weights;\n          data2[x2 + 2] = gxB / weights;\n          data2[x2 + 3] = gxA / weightsAlpha;\n        }\n      }\n      return img2;\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function() {\n      return {\n        type: this.type,\n        scaleX: this.scaleX,\n        scaleY: this.scaleY,\n        resizeType: this.resizeType,\n        lanczosLobes: this.lanczosLobes\n      };\n    }\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Resize} Instance of fabric.Image.filters.Resize\n   */\n  fabric.Image.filters.Resize.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Contrast filter class\n   * @class fabric.Image.filters.Contrast\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Contrast#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Contrast({\n   *   contrast: 0.25\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.Contrast = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Contrast.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Contrast',\n\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform float uContrast;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'float contrastF = 1.015 * (uContrast + 1.0) / (1.0 * (1.015 - uContrast));\\n' +\n        'color.rgb = contrastF * (color.rgb - 0.5) + 0.5;\\n' +\n        'gl_FragColor = color;\\n' +\n      '}',\n\n    /**\n     * contrast value, range from -1 to 1.\n     * @param {Number} contrast\n     * @default 0\n     */\n    contrast: 0,\n\n    mainParameter: 'contrast',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Contrast.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.contrast=0] Value to contrast the image up (-1...1)\n     */\n\n    /**\n      * Apply the Contrast operation to a Uint8Array representing the pixels of an image.\n      *\n      * @param {Object} options\n      * @param {ImageData} options.imageData The Uint8Array to be filtered.\n      */\n    applyTo2d: function(options) {\n      if (this.contrast === 0) {\n        return;\n      }\n      var imageData = options.imageData, i, len,\n          data = imageData.data, len = data.length,\n          contrast = Math.floor(this.contrast * 255),\n          contrastF = 259 * (contrast + 255) / (255 * (259 - contrast));\n\n      for (i = 0; i < len; i += 4) {\n        data[i] = contrastF * (data[i] - 128) + 128;\n        data[i + 1] = contrastF * (data[i + 1] - 128) + 128;\n        data[i + 2] = contrastF * (data[i + 2] - 128) + 128;\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uContrast: gl.getUniformLocation(program, 'uContrast'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1f(uniformLocations.uContrast, this.contrast);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Contrast} Instance of fabric.Image.filters.Contrast\n   */\n  fabric.Image.filters.Contrast.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Saturate filter class\n   * @class fabric.Image.filters.Saturation\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Saturation#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Saturation({\n   *   saturation: 1\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.Saturation = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Saturation.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Saturation',\n\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform float uSaturation;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'float rgMax = max(color.r, color.g);\\n' +\n        'float rgbMax = max(rgMax, color.b);\\n' +\n        'color.r += rgbMax != color.r ? (rgbMax - color.r) * uSaturation : 0.00;\\n' +\n        'color.g += rgbMax != color.g ? (rgbMax - color.g) * uSaturation : 0.00;\\n' +\n        'color.b += rgbMax != color.b ? (rgbMax - color.b) * uSaturation : 0.00;\\n' +\n        'gl_FragColor = color;\\n' +\n      '}',\n\n    /**\n     * Saturation value, from -1 to 1.\n     * Increases/decreases the color saturation.\n     * A value of 0 has no effect.\n     * \n     * @param {Number} saturation\n     * @default\n     */\n    saturation: 0,\n\n    mainParameter: 'saturation',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Saturate.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.saturate=0] Value to saturate the image (-1...1)\n     */\n\n    /**\n     * Apply the Saturation operation to a Uint8ClampedArray representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n     */\n    applyTo2d: function(options) {\n      if (this.saturation === 0) {\n        return;\n      }\n      var imageData = options.imageData,\n          data = imageData.data, len = data.length,\n          adjust = -this.saturation, i, max;\n\n      for (i = 0; i < len; i += 4) {\n        max = Math.max(data[i], data[i + 1], data[i + 2]);\n        data[i] += max !== data[i] ? (max - data[i]) * adjust : 0;\n        data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * adjust : 0;\n        data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * adjust : 0;\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uSaturation: gl.getUniformLocation(program, 'uSaturation'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1f(uniformLocations.uSaturation, -this.saturation);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Saturation} Instance of fabric.Image.filters.Saturate\n   */\n  fabric.Image.filters.Saturation.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Vibrance filter class\n   * @class fabric.Image.filters.Vibrance\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Vibrance#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Vibrance({\n   *   vibrance: 1\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.Vibrance = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Vibrance.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Vibrance',\n\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform float uVibrance;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'float max = max(color.r, max(color.g, color.b));\\n' +\n        'float avg = (color.r + color.g + color.b) / 3.0;\\n' +\n        'float amt = (abs(max - avg) * 2.0) * uVibrance;\\n' +\n        'color.r += max != color.r ? (max - color.r) * amt : 0.00;\\n' +\n        'color.g += max != color.g ? (max - color.g) * amt : 0.00;\\n' +\n        'color.b += max != color.b ? (max - color.b) * amt : 0.00;\\n' +\n        'gl_FragColor = color;\\n' +\n      '}',\n\n    /**\n     * Vibrance value, from -1 to 1.\n     * Increases/decreases the saturation of more muted colors with less effect on saturated colors.\n     * A value of 0 has no effect.\n     * \n     * @param {Number} vibrance\n     * @default\n     */\n    vibrance: 0,\n\n    mainParameter: 'vibrance',\n\n    /**\n     * Constructor\n     * @memberOf fabric.Image.filters.Vibrance.prototype\n     * @param {Object} [options] Options object\n     * @param {Number} [options.vibrance=0] Vibrance value for the image (between -1 and 1)\n     */\n\n    /**\n     * Apply the Vibrance operation to a Uint8ClampedArray representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n     */\n    applyTo2d: function(options) {\n      if (this.vibrance === 0) {\n        return;\n      }\n      var imageData = options.imageData,\n          data = imageData.data, len = data.length,\n          adjust = -this.vibrance, i, max, avg, amt;\n\n      for (i = 0; i < len; i += 4) {\n        max = Math.max(data[i], data[i + 1], data[i + 2]);\n        avg = (data[i] + data[i + 1] + data[i + 2]) / 3;\n        amt = ((Math.abs(max - avg) * 2 / 255) * adjust);\n        data[i] += max !== data[i] ? (max - data[i]) * amt : 0;\n        data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * amt : 0;\n        data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * amt : 0;\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uVibrance: gl.getUniformLocation(program, 'uVibrance'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform1f(uniformLocations.uVibrance, -this.vibrance);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Vibrance} Instance of fabric.Image.filters.Vibrance\n   */\n  fabric.Image.filters.Vibrance.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Blur filter class\n   * @class fabric.Image.filters.Blur\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Blur#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Blur({\n   *   blur: 0.5\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   * canvas.renderAll();\n   */\n  filters.Blur = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blur.prototype */ {\n\n    type: 'Blur',\n\n    /*\n'gl_FragColor = vec4(0.0);',\n'gl_FragColor += texture2D(texture, vTexCoord + -7 * uDelta)*0.0044299121055113265;',\n'gl_FragColor += texture2D(texture, vTexCoord + -6 * uDelta)*0.00895781211794;',\n'gl_FragColor += texture2D(texture, vTexCoord + -5 * uDelta)*0.0215963866053;',\n'gl_FragColor += texture2D(texture, vTexCoord + -4 * uDelta)*0.0443683338718;',\n'gl_FragColor += texture2D(texture, vTexCoord + -3 * uDelta)*0.0776744219933;',\n'gl_FragColor += texture2D(texture, vTexCoord + -2 * uDelta)*0.115876621105;',\n'gl_FragColor += texture2D(texture, vTexCoord + -1 * uDelta)*0.147308056121;',\n'gl_FragColor += texture2D(texture, vTexCoord              )*0.159576912161;',\n'gl_FragColor += texture2D(texture, vTexCoord + 1 * uDelta)*0.147308056121;',\n'gl_FragColor += texture2D(texture, vTexCoord + 2 * uDelta)*0.115876621105;',\n'gl_FragColor += texture2D(texture, vTexCoord + 3 * uDelta)*0.0776744219933;',\n'gl_FragColor += texture2D(texture, vTexCoord + 4 * uDelta)*0.0443683338718;',\n'gl_FragColor += texture2D(texture, vTexCoord + 5 * uDelta)*0.0215963866053;',\n'gl_FragColor += texture2D(texture, vTexCoord + 6 * uDelta)*0.00895781211794;',\n'gl_FragColor += texture2D(texture, vTexCoord + 7 * uDelta)*0.0044299121055113265;',\n*/\n\n    /* eslint-disable max-len */\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform vec2 uDelta;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'const float nSamples = 15.0;\\n' +\n      'vec3 v3offset = vec3(12.9898, 78.233, 151.7182);\\n' +\n      'float random(vec3 scale) {\\n' +\n        /* use the fragment position for a different seed per-pixel */\n        'return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453);\\n' +\n      '}\\n' +\n      'void main() {\\n' +\n        'vec4 color = vec4(0.0);\\n' +\n        'float total = 0.0;\\n' +\n        'float offset = random(v3offset);\\n' +\n        'for (float t = -nSamples; t <= nSamples; t++) {\\n' +\n          'float percent = (t + offset - 0.5) / nSamples;\\n' +\n          'float weight = 1.0 - abs(percent);\\n' +\n          'color += texture2D(uTexture, vTexCoord + uDelta * percent) * weight;\\n' +\n          'total += weight;\\n' +\n        '}\\n' +\n        'gl_FragColor = color / total;\\n' +\n      '}',\n    /* eslint-enable max-len */\n\n    /**\n     * blur value, in percentage of image dimensions.\n     * specific to keep the image blur constant at different resolutions\n     * range between 0 and 1.\n     * @type Number\n     * @default\n     */\n    blur: 0,\n\n    mainParameter: 'blur',\n\n    applyTo: function(options) {\n      if (options.webgl) {\n        // this aspectRatio is used to give the same blur to vertical and horizontal\n        this.aspectRatio = options.sourceWidth / options.sourceHeight;\n        options.passes++;\n        this._setupFrameBuffer(options);\n        this.horizontal = true;\n        this.applyToWebGL(options);\n        this._swapTextures(options);\n        this._setupFrameBuffer(options);\n        this.horizontal = false;\n        this.applyToWebGL(options);\n        this._swapTextures(options);\n      }\n      else {\n        this.applyTo2d(options);\n      }\n    },\n\n    applyTo2d: function(options) {\n      // paint canvasEl with current image data.\n      //options.ctx.putImageData(options.imageData, 0, 0);\n      options.imageData = this.simpleBlur(options);\n    },\n\n    simpleBlur: function(options) {\n      var resources = options.filterBackend.resources, canvas1, canvas2,\n          width = options.imageData.width,\n          height = options.imageData.height;\n\n      if (!resources.blurLayer1) {\n        resources.blurLayer1 = fabric.util.createCanvasElement();\n        resources.blurLayer2 = fabric.util.createCanvasElement();\n      }\n      canvas1 = resources.blurLayer1;\n      canvas2 = resources.blurLayer2;\n      if (canvas1.width !== width || canvas1.height !== height) {\n        canvas2.width = canvas1.width = width;\n        canvas2.height = canvas1.height = height;\n      }\n      var ctx1 = canvas1.getContext('2d'),\n          ctx2 = canvas2.getContext('2d'),\n          nSamples = 15,\n          random, percent, j, i,\n          blur = this.blur * 0.06 * 0.5;\n\n      // load first canvas\n      ctx1.putImageData(options.imageData, 0, 0);\n      ctx2.clearRect(0, 0, width, height);\n\n      for (i = -nSamples; i <= nSamples; i++) {\n        random = (Math.random() - 0.5) / 4;\n        percent = i / nSamples;\n        j = blur * percent * width + random;\n        ctx2.globalAlpha = 1 - Math.abs(percent);\n        ctx2.drawImage(canvas1, j, random);\n        ctx1.drawImage(canvas2, 0, 0);\n        ctx2.globalAlpha = 1;\n        ctx2.clearRect(0, 0, canvas2.width, canvas2.height);\n      }\n      for (i = -nSamples; i <= nSamples; i++) {\n        random = (Math.random() - 0.5) / 4;\n        percent = i / nSamples;\n        j = blur * percent * height + random;\n        ctx2.globalAlpha = 1 - Math.abs(percent);\n        ctx2.drawImage(canvas1, random, j);\n        ctx1.drawImage(canvas2, 0, 0);\n        ctx2.globalAlpha = 1;\n        ctx2.clearRect(0, 0, canvas2.width, canvas2.height);\n      }\n      options.ctx.drawImage(canvas1, 0, 0);\n      var newImageData = options.ctx.getImageData(0, 0, canvas1.width, canvas1.height);\n      ctx1.globalAlpha = 1;\n      ctx1.clearRect(0, 0, canvas1.width, canvas1.height);\n      return newImageData;\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        delta: gl.getUniformLocation(program, 'uDelta'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      var delta = this.chooseRightDelta();\n      gl.uniform2fv(uniformLocations.delta, delta);\n    },\n\n    /**\n     * choose right value of image percentage to blur with\n     * @returns {Array} a numeric array with delta values\n     */\n    chooseRightDelta: function() {\n      var blurScale = 1, delta = [0, 0], blur;\n      if (this.horizontal) {\n        if (this.aspectRatio > 1) {\n          // image is wide, i want to shrink radius horizontal\n          blurScale = 1 / this.aspectRatio;\n        }\n      }\n      else {\n        if (this.aspectRatio < 1) {\n          // image is tall, i want to shrink radius vertical\n          blurScale = this.aspectRatio;\n        }\n      }\n      blur = blurScale * this.blur * 0.12;\n      if (this.horizontal) {\n        delta[0] = blur;\n      }\n      else {\n        delta[1] = blur;\n      }\n      return delta;\n    },\n  });\n\n  /**\n   * Deserialize a JSON definition of a BlurFilter into a concrete instance.\n   */\n  filters.Blur.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * Gamma filter class\n   * @class fabric.Image.filters.Gamma\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.Gamma#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.Gamma({\n   *   gamma: [1, 0.5, 2.1]\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.Gamma = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Gamma.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'Gamma',\n\n    fragmentSource: 'precision highp float;\\n' +\n      'uniform sampler2D uTexture;\\n' +\n      'uniform vec3 uGamma;\\n' +\n      'varying vec2 vTexCoord;\\n' +\n      'void main() {\\n' +\n        'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n        'vec3 correction = (1.0 / uGamma);\\n' +\n        'color.r = pow(color.r, correction.r);\\n' +\n        'color.g = pow(color.g, correction.g);\\n' +\n        'color.b = pow(color.b, correction.b);\\n' +\n        'gl_FragColor = color;\\n' +\n        'gl_FragColor.rgb *= color.a;\\n' +\n      '}',\n\n    /**\n     * Gamma array value, from 0.01 to 2.2.\n     * @param {Array} gamma\n     * @default\n     */\n    gamma: [1, 1, 1],\n\n    /**\n     * Describe the property that is the filter parameter\n     * @param {String} m\n     * @default\n     */\n    mainParameter: 'gamma',\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     */\n    initialize: function(options) {\n      this.gamma = [1, 1, 1];\n      filters.BaseFilter.prototype.initialize.call(this, options);\n    },\n\n    /**\n     * Apply the Gamma operation to a Uint8Array representing the pixels of an image.\n     *\n     * @param {Object} options\n     * @param {ImageData} options.imageData The Uint8Array to be filtered.\n     */\n    applyTo2d: function(options) {\n      var imageData = options.imageData, data = imageData.data,\n          gamma = this.gamma, len = data.length,\n          rInv = 1 / gamma[0], gInv = 1 / gamma[1],\n          bInv = 1 / gamma[2], i;\n\n      if (!this.rVals) {\n        // eslint-disable-next-line\n        this.rVals = new Uint8Array(256);\n        // eslint-disable-next-line\n        this.gVals = new Uint8Array(256);\n        // eslint-disable-next-line\n        this.bVals = new Uint8Array(256);\n      }\n\n      // This is an optimization - pre-compute a look-up table for each color channel\n      // instead of performing these pow calls for each pixel in the image.\n      for (i = 0, len = 256; i < len; i++) {\n        this.rVals[i] = Math.pow(i / 255, rInv) * 255;\n        this.gVals[i] = Math.pow(i / 255, gInv) * 255;\n        this.bVals[i] = Math.pow(i / 255, bInv) * 255;\n      }\n      for (i = 0, len = data.length; i < len; i += 4) {\n        data[i] = this.rVals[data[i]];\n        data[i + 1] = this.gVals[data[i + 1]];\n        data[i + 2] = this.bVals[data[i + 2]];\n      }\n    },\n\n    /**\n     * Return WebGL uniform locations for this filter's shader.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {WebGLShaderProgram} program This filter's compiled shader program.\n     */\n    getUniformLocations: function(gl, program) {\n      return {\n        uGamma: gl.getUniformLocation(program, 'uGamma'),\n      };\n    },\n\n    /**\n     * Send data from this filter to its shader program's uniforms.\n     *\n     * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n     * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n     */\n    sendUniformData: function(gl, uniformLocations) {\n      gl.uniform3fv(uniformLocations.uGamma, this.gamma);\n    },\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.Gamma} Instance of fabric.Image.filters.Gamma\n   */\n  fabric.Image.filters.Gamma.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * A container class that knows how to apply a sequence of filters to an input image.\n   */\n  filters.Composed = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Composed.prototype */ {\n\n    type: 'Composed',\n\n    /**\n     * A non sparse array of filters to apply\n     */\n    subFilters: [],\n\n    /**\n     * Constructor\n     * @param {Object} [options] Options object\n     */\n    initialize: function(options) {\n      this.callSuper('initialize', options);\n      // create a new array instead mutating the prototype with push\n      this.subFilters = this.subFilters.slice(0);\n    },\n\n    /**\n     * Apply this container's filters to the input image provided.\n     *\n     * @param {Object} options\n     * @param {Number} options.passes The number of filters remaining to be applied.\n     */\n    applyTo: function(options) {\n      options.passes += this.subFilters.length - 1;\n      this.subFilters.forEach(function(filter) {\n        filter.applyTo(options);\n      });\n    },\n\n    /**\n     * Serialize this filter into JSON.\n     *\n     * @returns {Object} A JSON representation of this filter.\n     */\n    toObject: function() {\n      return fabric.util.object.extend(this.callSuper('toObject'), {\n        subFilters: this.subFilters.map(function(filter) { return filter.toObject(); }),\n      });\n    },\n\n    isNeutralState: function() {\n      return !this.subFilters.some(function(filter) { return !filter.isNeutralState(); });\n    }\n  });\n\n  /**\n   * Deserialize a JSON definition of a ComposedFilter into a concrete instance.\n   */\n  fabric.Image.filters.Composed.fromObject = function(object, callback) {\n    var filters = object.subFilters || [],\n        subFilters = filters.map(function(filter) {\n          return new fabric.Image.filters[filter.type](filter);\n        }),\n        instance = new fabric.Image.filters.Composed({ subFilters: subFilters });\n    callback && callback(instance);\n    return instance;\n  };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric  = global.fabric || (global.fabric = { }),\n      filters = fabric.Image.filters,\n      createClass = fabric.util.createClass;\n\n  /**\n   * HueRotation filter class\n   * @class fabric.Image.filters.HueRotation\n   * @memberOf fabric.Image.filters\n   * @extends fabric.Image.filters.BaseFilter\n   * @see {@link fabric.Image.filters.HueRotation#initialize} for constructor definition\n   * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n   * @example\n   * var filter = new fabric.Image.filters.HueRotation({\n   *   rotation: -0.5\n   * });\n   * object.filters.push(filter);\n   * object.applyFilters();\n   */\n  filters.HueRotation = createClass(filters.ColorMatrix, /** @lends fabric.Image.filters.HueRotation.prototype */ {\n\n    /**\n     * Filter type\n     * @param {String} type\n     * @default\n     */\n    type: 'HueRotation',\n\n    /**\n     * HueRotation value, from -1 to 1.\n     * the unit is radians\n     * @param {Number} myParameter\n     * @default\n     */\n    rotation: 0,\n\n    /**\n     * Describe the property that is the filter parameter\n     * @param {String} m\n     * @default\n     */\n    mainParameter: 'rotation',\n\n    calculateMatrix: function() {\n      var rad = this.rotation * Math.PI, cos = fabric.util.cos(rad), sin = fabric.util.sin(rad),\n          aThird = 1 / 3, aThirdSqtSin = Math.sqrt(aThird) * sin, OneMinusCos = 1 - cos;\n      this.matrix = [\n        1, 0, 0, 0, 0,\n        0, 1, 0, 0, 0,\n        0, 0, 1, 0, 0,\n        0, 0, 0, 1, 0\n      ];\n      this.matrix[0] = cos + OneMinusCos / 3;\n      this.matrix[1] = aThird * OneMinusCos - aThirdSqtSin;\n      this.matrix[2] = aThird * OneMinusCos + aThirdSqtSin;\n      this.matrix[5] = aThird * OneMinusCos + aThirdSqtSin;\n      this.matrix[6] = cos + aThird * OneMinusCos;\n      this.matrix[7] = aThird * OneMinusCos - aThirdSqtSin;\n      this.matrix[10] = aThird * OneMinusCos - aThirdSqtSin;\n      this.matrix[11] = aThird * OneMinusCos + aThirdSqtSin;\n      this.matrix[12] = cos + aThird * OneMinusCos;\n    },\n\n    /**\n     * HueRotation isNeutralState implementation\n     * Used only in image applyFilters to discard filters that will not have an effect\n     * on the image\n     * @param {Object} options\n     **/\n    isNeutralState: function(options) {\n      this.calculateMatrix();\n      return filters.BaseFilter.prototype.isNeutralState.call(this, options);\n    },\n\n    /**\n     * Apply this filter to the input image data provided.\n     *\n     * Determines whether to use WebGL or Canvas2D based on the options.webgl flag.\n     *\n     * @param {Object} options\n     * @param {Number} options.passes The number of filters remaining to be executed\n     * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n     * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n     * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n     * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n     * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n     */\n    applyTo: function(options) {\n      this.calculateMatrix();\n      filters.BaseFilter.prototype.applyTo.call(this, options);\n    },\n\n  });\n\n  /**\n   * Returns filter instance from an object representation\n   * @static\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] to be invoked after filter creation\n   * @return {fabric.Image.filters.HueRotation} Instance of fabric.Image.filters.HueRotation\n   */\n  fabric.Image.filters.HueRotation.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = { }),\n      clone = fabric.util.object.clone;\n\n  if (fabric.Text) {\n    fabric.warn('fabric.Text is already defined');\n    return;\n  }\n\n  var additionalProps =\n    ('fontFamily fontWeight fontSize text underline overline linethrough' +\n    ' textAlign fontStyle lineHeight textBackgroundColor charSpacing styles' +\n    ' direction path pathStartOffset pathSide pathAlign').split(' ');\n\n  /**\n   * Text class\n   * @class fabric.Text\n   * @extends fabric.Object\n   * @return {fabric.Text} thisArg\n   * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text}\n   * @see {@link fabric.Text#initialize} for constructor definition\n   */\n  fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ {\n\n    /**\n     * Properties which when set cause object to change dimensions\n     * @type Array\n     * @private\n     */\n    _dimensionAffectingProps: [\n      'fontSize',\n      'fontWeight',\n      'fontFamily',\n      'fontStyle',\n      'lineHeight',\n      'text',\n      'charSpacing',\n      'textAlign',\n      'styles',\n      'path',\n      'pathStartOffset',\n      'pathSide',\n      'pathAlign'\n    ],\n\n    /**\n     * @private\n     */\n    _reNewline: /\\r?\\n/,\n\n    /**\n     * Use this regular expression to filter for whitespaces that is not a new line.\n     * Mostly used when text is 'justify' aligned.\n     * @private\n     */\n    _reSpacesAndTabs: /[ \\t\\r]/g,\n\n    /**\n     * Use this regular expression to filter for whitespace that is not a new line.\n     * Mostly used when text is 'justify' aligned.\n     * @private\n     */\n    _reSpaceAndTab: /[ \\t\\r]/,\n\n    /**\n     * Use this regular expression to filter consecutive groups of non spaces.\n     * Mostly used when text is 'justify' aligned.\n     * @private\n     */\n    _reWords: /\\S+/g,\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type:                 'text',\n\n    /**\n     * Font size (in pixels)\n     * @type Number\n     * @default\n     */\n    fontSize:             40,\n\n    /**\n     * Font weight (e.g. bold, normal, 400, 600, 800)\n     * @type {(Number|String)}\n     * @default\n     */\n    fontWeight:           'normal',\n\n    /**\n     * Font family\n     * @type String\n     * @default\n     */\n    fontFamily:           'Times New Roman',\n\n    /**\n     * Text decoration underline.\n     * @type Boolean\n     * @default\n     */\n    underline:       false,\n\n    /**\n     * Text decoration overline.\n     * @type Boolean\n     * @default\n     */\n    overline:       false,\n\n    /**\n     * Text decoration linethrough.\n     * @type Boolean\n     * @default\n     */\n    linethrough:       false,\n\n    /**\n     * Text alignment. Possible values: \"left\", \"center\", \"right\", \"justify\",\n     * \"justify-left\", \"justify-center\" or \"justify-right\".\n     * @type String\n     * @default\n     */\n    textAlign:            'left',\n\n    /**\n     * Font style . Possible values: \"\", \"normal\", \"italic\" or \"oblique\".\n     * @type String\n     * @default\n     */\n    fontStyle:            'normal',\n\n    /**\n     * Line height\n     * @type Number\n     * @default\n     */\n    lineHeight:           1.16,\n\n    /**\n     * Superscript schema object (minimum overlap)\n     * @type {Object}\n     * @default\n     */\n    superscript: {\n      size:      0.60, // fontSize factor\n      baseline: -0.35  // baseline-shift factor (upwards)\n    },\n\n    /**\n     * Subscript schema object (minimum overlap)\n     * @type {Object}\n     * @default\n     */\n    subscript: {\n      size:      0.60, // fontSize factor\n      baseline:  0.11  // baseline-shift factor (downwards)\n    },\n\n    /**\n     * Background color of text lines\n     * @type String\n     * @default\n     */\n    textBackgroundColor:  '',\n\n    /**\n     * List of properties to consider when checking if\n     * state of an object is changed ({@link fabric.Object#hasStateChanged})\n     * as well as for history (undo/redo) purposes\n     * @type Array\n     */\n    stateProperties: fabric.Object.prototype.stateProperties.concat(additionalProps),\n\n    /**\n     * List of properties to consider when checking if cache needs refresh\n     * @type Array\n     */\n    cacheProperties: fabric.Object.prototype.cacheProperties.concat(additionalProps),\n\n    /**\n     * When defined, an object is rendered via stroke and this property specifies its color.\n     * <b>Backwards incompatibility note:</b> This property was named \"strokeStyle\" until v1.1.6\n     * @type String\n     * @default\n     */\n    stroke:               null,\n\n    /**\n     * Shadow object representing shadow of this shape.\n     * <b>Backwards incompatibility note:</b> This property was named \"textShadow\" (String) until v1.2.11\n     * @type fabric.Shadow\n     * @default\n     */\n    shadow:               null,\n\n    /**\n     * fabric.Path that the text should follow.\n     * since 4.6.0 the path will be drawn automatically.\n     * if you want to make the path visible, give it a stroke and strokeWidth or fill value\n     * if you want it to be hidden, assign visible = false to the path.\n     * This feature is in BETA, and SVG import/export is not yet supported.\n     * @type fabric.Path\n     * @example\n     * var textPath = new fabric.Text('Text on a path', {\n     *     top: 150,\n     *     left: 150,\n     *     textAlign: 'center',\n     *     charSpacing: -50,\n     *     path: new fabric.Path('M 0 0 C 50 -100 150 -100 200 0', {\n     *         strokeWidth: 1,\n     *         visible: false\n     *     }),\n     *     pathSide: 'left',\n     *     pathStartOffset: 0\n     * });\n     * @default\n     */\n    path:               null,\n\n    /**\n     * Offset amount for text path starting position\n     * Only used when text has a path\n     * @type Number\n     * @default\n     */\n    pathStartOffset:               0,\n\n    /**\n     * Which side of the path the text should be drawn on.\n     * Only used when text has a path\n     * @type {String} 'left|right'\n     * @default\n     */\n    pathSide:               'left',\n\n    /**\n     * How text is aligned to the path. This property determines\n     * the perpendicular position of each character relative to the path.\n     * (one of \"baseline\", \"center\", \"ascender\", \"descender\")\n     * This feature is in BETA, and its behavior may change\n     * @type String\n     * @default\n     */\n    pathAlign:               'baseline',\n\n    /**\n     * @private\n     */\n    _fontSizeFraction: 0.222,\n\n    /**\n     * @private\n     */\n    offsets: {\n      underline: 0.10,\n      linethrough: -0.315,\n      overline: -0.88\n    },\n\n    /**\n     * Text Line proportion to font Size (in pixels)\n     * @type Number\n     * @default\n     */\n    _fontSizeMult:             1.13,\n\n    /**\n     * additional space between characters\n     * expressed in thousands of em unit\n     * @type Number\n     * @default\n     */\n    charSpacing:             0,\n\n    /**\n     * Object containing character styles - top-level properties -> line numbers,\n     * 2nd-level properties - character numbers\n     * @type Object\n     * @default\n     */\n    styles: null,\n\n    /**\n     * Reference to a context to measure text char or couple of chars\n     * the cacheContext of the canvas will be used or a freshly created one if the object is not on canvas\n     * once created it will be referenced on fabric._measuringContext to avoid creating a canvas for every\n     * text object created.\n     * @type {CanvasRenderingContext2D}\n     * @default\n     */\n    _measuringContext: null,\n\n    /**\n     * Baseline shift, styles only, keep at 0 for the main text object\n     * @type {Number}\n     * @default\n     */\n    deltaY: 0,\n\n    /**\n     * WARNING: EXPERIMENTAL. NOT SUPPORTED YET\n     * determine the direction of the text.\n     * This has to be set manually together with textAlign and originX for proper\n     * experience.\n     * some interesting link for the future\n     * https://www.w3.org/International/questions/qa-bidi-unicode-controls\n     * @since 4.5.0\n     * @type {String} 'ltr|rtl'\n     * @default\n     */\n    direction: 'ltr',\n\n    /**\n     * Array of properties that define a style unit (of 'styles').\n     * @type {Array}\n     * @default\n     */\n    _styleProperties: [\n      'stroke',\n      'strokeWidth',\n      'fill',\n      'fontFamily',\n      'fontSize',\n      'fontWeight',\n      'fontStyle',\n      'underline',\n      'overline',\n      'linethrough',\n      'deltaY',\n      'textBackgroundColor',\n    ],\n\n    /**\n     * contains characters bounding boxes\n     */\n    __charBounds: [],\n\n    /**\n     * use this size when measuring text. To avoid IE11 rounding errors\n     * @type {Number}\n     * @default\n     * @readonly\n     * @private\n     */\n    CACHE_FONT_SIZE: 400,\n\n    /**\n     * contains the min text width to avoid getting 0\n     * @type {Number}\n     * @default\n     */\n    MIN_TEXT_WIDTH: 2,\n\n    /**\n     * Constructor\n     * @param {String} text Text string\n     * @param {Object} [options] Options object\n     * @return {fabric.Text} thisArg\n     */\n    initialize: function(text, options) {\n      this.styles = options ? (options.styles || { }) : { };\n      this.text = text;\n      this.__skipDimension = true;\n      this.callSuper('initialize', options);\n      if (this.path) {\n        this.setPathInfo();\n      }\n      this.__skipDimension = false;\n      this.initDimensions();\n      this.setCoords();\n      this.setupState({ propertySet: '_dimensionAffectingProps' });\n    },\n\n    /**\n     * If text has a path, it will add the extra information needed\n     * for path and text calculations\n     * @return {fabric.Text} thisArg\n     */\n    setPathInfo: function() {\n      var path = this.path;\n      if (path) {\n        path.segmentsInfo = fabric.util.getPathSegmentsInfo(path.path);\n      }\n    },\n\n    /**\n     * Return a context for measurement of text string.\n     * if created it gets stored for reuse\n     * this is for internal use, please do not use it\n     * @private\n     * @param {String} text Text string\n     * @param {Object} [options] Options object\n     * @return {fabric.Text} thisArg\n     */\n    getMeasuringContext: function() {\n      // if we did not return we have to measure something.\n      if (!fabric._measuringContext) {\n        fabric._measuringContext = this.canvas && this.canvas.contextCache ||\n          fabric.util.createCanvasElement().getContext('2d');\n      }\n      return fabric._measuringContext;\n    },\n\n    /**\n     * @private\n     * Divides text into lines of text and lines of graphemes.\n     */\n    _splitText: function() {\n      var newLines = this._splitTextIntoLines(this.text);\n      this.textLines = newLines.lines;\n      this._textLines = newLines.graphemeLines;\n      this._unwrappedTextLines = newLines._unwrappedLines;\n      this._text = newLines.graphemeText;\n      return newLines;\n    },\n\n    /**\n     * Initialize or update text dimensions.\n     * Updates this.width and this.height with the proper values.\n     * Does not return dimensions.\n     */\n    initDimensions: function() {\n      if (this.__skipDimension) {\n        return;\n      }\n      this._splitText();\n      this._clearCache();\n      if (this.path) {\n        // Add the space of a line around the path. This is an approximation\n        var additionalWidth = this.getHeightOfLine(0) * 1.1;\n        this.width = this.path.width + additionalWidth;\n        this.height = this.path.height + additionalWidth;\n      }\n      else {\n        this.width = this.calcTextWidth() || this.cursorWidth || this.MIN_TEXT_WIDTH;\n        this.height = this.calcTextHeight();\n      }\n      if (this.textAlign.indexOf('justify') !== -1) {\n        // once text is measured we need to make space fatter to make justified text.\n        this.enlargeSpaces();\n      }\n      this.saveState({ propertySet: '_dimensionAffectingProps' });\n    },\n\n    /**\n     * Enlarge space boxes and shift the others\n     */\n    enlargeSpaces: function() {\n      var diffSpace, currentLineWidth, numberOfSpaces, accumulatedSpace, line, charBound, spaces;\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        if (this.textAlign !== 'justify' && (i === len - 1 || this.isEndOfWrapping(i))) {\n          continue;\n        }\n        accumulatedSpace = 0;\n        line = this._textLines[i];\n        currentLineWidth = this.getLineWidth(i);\n        if (currentLineWidth < this.width && (spaces = this.textLines[i].match(this._reSpacesAndTabs))) {\n          numberOfSpaces = spaces.length;\n          diffSpace = (this.width - currentLineWidth) / numberOfSpaces;\n          for (var j = 0, jlen = line.length; j <= jlen; j++) {\n            charBound = this.__charBounds[i][j];\n            if (this._reSpaceAndTab.test(line[j])) {\n              charBound.width += diffSpace;\n              charBound.kernedWidth += diffSpace;\n              charBound.left += accumulatedSpace;\n              accumulatedSpace += diffSpace;\n            }\n            else {\n              charBound.left += accumulatedSpace;\n            }\n          }\n        }\n      }\n    },\n\n    /**\n     * Detect if the text line is ended with an hard break\n     * text and itext do not have wrapping, return false\n     * @return {Boolean}\n     */\n    isEndOfWrapping: function(lineIndex) {\n      return lineIndex === this._textLines.length - 1;\n    },\n\n    /**\n     * Detect if a line has a linebreak and so we need to account for it when moving\n     * and counting style.\n     * It return always for text and Itext.\n     * @return Number\n     */\n    missingNewlineOffset: function() {\n      return 1;\n    },\n\n    /**\n     * Returns string representation of an instance\n     * @return {String} String representation of text object\n     */\n    toString: function() {\n      return '#<fabric.Text (' + this.complexity() +\n        '): { \"text\": \"' + this.text + '\", \"fontFamily\": \"' + this.fontFamily + '\" }>';\n    },\n\n    /**\n     * Return the dimension and the zoom level needed to create a cache canvas\n     * big enough to host the object to be cached.\n     * @private\n     * @param {Object} dim.x width of object to be cached\n     * @param {Object} dim.y height of object to be cached\n     * @return {Object}.width width of canvas\n     * @return {Object}.height height of canvas\n     * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n     * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n     */\n    _getCacheCanvasDimensions: function() {\n      var dims = this.callSuper('_getCacheCanvasDimensions');\n      var fontSize = this.fontSize;\n      dims.width += fontSize * dims.zoomX;\n      dims.height += fontSize * dims.zoomY;\n      return dims;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      var path = this.path;\n      path && !path.isNotVisible() && path._render(ctx);\n      this._setTextStyles(ctx);\n      this._renderTextLinesBackground(ctx);\n      this._renderTextDecoration(ctx, 'underline');\n      this._renderText(ctx);\n      this._renderTextDecoration(ctx, 'overline');\n      this._renderTextDecoration(ctx, 'linethrough');\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderText: function(ctx) {\n      if (this.paintFirst === 'stroke') {\n        this._renderTextStroke(ctx);\n        this._renderTextFill(ctx);\n      }\n      else {\n        this._renderTextFill(ctx);\n        this._renderTextStroke(ctx);\n      }\n    },\n\n    /**\n     * Set the font parameter of the context with the object properties or with charStyle\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Object} [charStyle] object with font style properties\n     * @param {String} [charStyle.fontFamily] Font Family\n     * @param {Number} [charStyle.fontSize] Font size in pixels. ( without px suffix )\n     * @param {String} [charStyle.fontWeight] Font weight\n     * @param {String} [charStyle.fontStyle] Font style (italic|normal)\n     */\n    _setTextStyles: function(ctx, charStyle, forMeasuring) {\n      ctx.textBaseline = 'alphabetical';\n      if (this.path) {\n        switch (this.pathAlign) {\n          case 'center':\n            ctx.textBaseline = 'middle';\n            break;\n          case 'ascender':\n            ctx.textBaseline = 'top';\n            break;\n          case 'descender':\n            ctx.textBaseline = 'bottom';\n            break;\n        }\n      }\n      ctx.font = this._getFontDeclaration(charStyle, forMeasuring);\n    },\n\n    /**\n     * calculate and return the text Width measuring each line.\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @return {Number} Maximum width of fabric.Text object\n     */\n    calcTextWidth: function() {\n      var maxWidth = this.getLineWidth(0);\n\n      for (var i = 1, len = this._textLines.length; i < len; i++) {\n        var currentLineWidth = this.getLineWidth(i);\n        if (currentLineWidth > maxWidth) {\n          maxWidth = currentLineWidth;\n        }\n      }\n      return maxWidth;\n    },\n\n    /**\n     * @private\n     * @param {String} method Method name (\"fillText\" or \"strokeText\")\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} line Text to render\n     * @param {Number} left Left position of text\n     * @param {Number} top Top position of text\n     * @param {Number} lineIndex Index of a line in a text\n     */\n    _renderTextLine: function(method, ctx, line, left, top, lineIndex) {\n      this._renderChars(method, ctx, line, left, top, lineIndex);\n    },\n\n    /**\n     * Renders the text background for lines, taking care of style\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextLinesBackground: function(ctx) {\n      if (!this.textBackgroundColor && !this.styleHas('textBackgroundColor')) {\n        return;\n      }\n      var heightOfLine,\n          lineLeftOffset, originalFill = ctx.fillStyle,\n          line, lastColor,\n          leftOffset = this._getLeftOffset(),\n          lineTopOffset = this._getTopOffset(),\n          boxStart = 0, boxWidth = 0, charBox, currentColor, path = this.path,\n          drawStart;\n\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        heightOfLine = this.getHeightOfLine(i);\n        if (!this.textBackgroundColor && !this.styleHas('textBackgroundColor', i)) {\n          lineTopOffset += heightOfLine;\n          continue;\n        }\n        line = this._textLines[i];\n        lineLeftOffset = this._getLineLeftOffset(i);\n        boxWidth = 0;\n        boxStart = 0;\n        lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor');\n        for (var j = 0, jlen = line.length; j < jlen; j++) {\n          charBox = this.__charBounds[i][j];\n          currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');\n          if (path) {\n            ctx.save();\n            ctx.translate(charBox.renderLeft, charBox.renderTop);\n            ctx.rotate(charBox.angle);\n            ctx.fillStyle = currentColor;\n            currentColor && ctx.fillRect(\n              -charBox.width / 2,\n              -heightOfLine / this.lineHeight * (1 - this._fontSizeFraction),\n              charBox.width,\n              heightOfLine / this.lineHeight\n            );\n            ctx.restore();\n          }\n          else if (currentColor !== lastColor) {\n            drawStart = leftOffset + lineLeftOffset + boxStart;\n            if (this.direction === 'rtl') {\n              drawStart = this.width - drawStart - boxWidth;\n            }\n            ctx.fillStyle = lastColor;\n            lastColor && ctx.fillRect(\n              drawStart,\n              lineTopOffset,\n              boxWidth,\n              heightOfLine / this.lineHeight\n            );\n            boxStart = charBox.left;\n            boxWidth = charBox.width;\n            lastColor = currentColor;\n          }\n          else {\n            boxWidth += charBox.kernedWidth;\n          }\n        }\n        if (currentColor && !path) {\n          drawStart = leftOffset + lineLeftOffset + boxStart;\n          if (this.direction === 'rtl') {\n            drawStart = this.width - drawStart - boxWidth;\n          }\n          ctx.fillStyle = currentColor;\n          ctx.fillRect(\n            drawStart,\n            lineTopOffset,\n            boxWidth,\n            heightOfLine / this.lineHeight\n          );\n        }\n        lineTopOffset += heightOfLine;\n      }\n      ctx.fillStyle = originalFill;\n      // if there is text background color no\n      // other shadows should be casted\n      this._removeShadow(ctx);\n    },\n\n    /**\n     * @private\n     * @param {Object} decl style declaration for cache\n     * @param {String} decl.fontFamily fontFamily\n     * @param {String} decl.fontStyle fontStyle\n     * @param {String} decl.fontWeight fontWeight\n     * @return {Object} reference to cache\n     */\n    getFontCache: function(decl) {\n      var fontFamily = decl.fontFamily.toLowerCase();\n      if (!fabric.charWidthsCache[fontFamily]) {\n        fabric.charWidthsCache[fontFamily] = { };\n      }\n      var cache = fabric.charWidthsCache[fontFamily],\n          cacheProp = decl.fontStyle.toLowerCase() + '_' + (decl.fontWeight + '').toLowerCase();\n      if (!cache[cacheProp]) {\n        cache[cacheProp] = { };\n      }\n      return cache[cacheProp];\n    },\n\n    /**\n     * measure and return the width of a single character.\n     * possibly overridden to accommodate different measure logic or\n     * to hook some external lib for character measurement\n     * @private\n     * @param {String} _char, char to be measured\n     * @param {Object} charStyle style of char to be measured\n     * @param {String} [previousChar] previous char\n     * @param {Object} [prevCharStyle] style of previous char\n     */\n    _measureChar: function(_char, charStyle, previousChar, prevCharStyle) {\n      // first i try to return from cache\n      var fontCache = this.getFontCache(charStyle), fontDeclaration = this._getFontDeclaration(charStyle),\n          previousFontDeclaration = this._getFontDeclaration(prevCharStyle), couple = previousChar + _char,\n          stylesAreEqual = fontDeclaration === previousFontDeclaration, width, coupleWidth, previousWidth,\n          fontMultiplier = charStyle.fontSize / this.CACHE_FONT_SIZE, kernedWidth;\n\n      if (previousChar && fontCache[previousChar] !== undefined) {\n        previousWidth = fontCache[previousChar];\n      }\n      if (fontCache[_char] !== undefined) {\n        kernedWidth = width = fontCache[_char];\n      }\n      if (stylesAreEqual && fontCache[couple] !== undefined) {\n        coupleWidth = fontCache[couple];\n        kernedWidth = coupleWidth - previousWidth;\n      }\n      if (width === undefined || previousWidth === undefined || coupleWidth === undefined) {\n        var ctx = this.getMeasuringContext();\n        // send a TRUE to specify measuring font size CACHE_FONT_SIZE\n        this._setTextStyles(ctx, charStyle, true);\n      }\n      if (width === undefined) {\n        kernedWidth = width = ctx.measureText(_char).width;\n        fontCache[_char] = width;\n      }\n      if (previousWidth === undefined && stylesAreEqual && previousChar) {\n        previousWidth = ctx.measureText(previousChar).width;\n        fontCache[previousChar] = previousWidth;\n      }\n      if (stylesAreEqual && coupleWidth === undefined) {\n        // we can measure the kerning couple and subtract the width of the previous character\n        coupleWidth = ctx.measureText(couple).width;\n        fontCache[couple] = coupleWidth;\n        kernedWidth = coupleWidth - previousWidth;\n      }\n      return { width: width * fontMultiplier, kernedWidth: kernedWidth * fontMultiplier };\n    },\n\n    /**\n     * Computes height of character at given position\n     * @param {Number} line the line index number\n     * @param {Number} _char the character index number\n     * @return {Number} fontSize of the character\n     */\n    getHeightOfChar: function(line, _char) {\n      return this.getValueOfPropertyAt(line, _char, 'fontSize');\n    },\n\n    /**\n     * measure a text line measuring all characters.\n     * @param {Number} lineIndex line number\n     * @return {Number} Line width\n     */\n    measureLine: function(lineIndex) {\n      var lineInfo = this._measureLine(lineIndex);\n      if (this.charSpacing !== 0) {\n        lineInfo.width -= this._getWidthOfCharSpacing();\n      }\n      if (lineInfo.width < 0) {\n        lineInfo.width = 0;\n      }\n      return lineInfo;\n    },\n\n    /**\n     * measure every grapheme of a line, populating __charBounds\n     * @param {Number} lineIndex\n     * @return {Object} object.width total width of characters\n     * @return {Object} object.widthOfSpaces length of chars that match this._reSpacesAndTabs\n     */\n    _measureLine: function(lineIndex) {\n      var width = 0, i, grapheme, line = this._textLines[lineIndex], prevGrapheme,\n          graphemeInfo, numOfSpaces = 0, lineBounds = new Array(line.length),\n          positionInPath = 0, startingPoint, totalPathLength, path = this.path,\n          reverse = this.pathSide === 'right';\n\n      this.__charBounds[lineIndex] = lineBounds;\n      for (i = 0; i < line.length; i++) {\n        grapheme = line[i];\n        graphemeInfo = this._getGraphemeBox(grapheme, lineIndex, i, prevGrapheme);\n        lineBounds[i] = graphemeInfo;\n        width += graphemeInfo.kernedWidth;\n        prevGrapheme = grapheme;\n      }\n      // this latest bound box represent the last character of the line\n      // to simplify cursor handling in interactive mode.\n      lineBounds[i] = {\n        left: graphemeInfo ? graphemeInfo.left + graphemeInfo.width : 0,\n        width: 0,\n        kernedWidth: 0,\n        height: this.fontSize\n      };\n      if (path) {\n        totalPathLength = path.segmentsInfo[path.segmentsInfo.length - 1].length;\n        startingPoint = fabric.util.getPointOnPath(path.path, 0, path.segmentsInfo);\n        startingPoint.x += path.pathOffset.x;\n        startingPoint.y += path.pathOffset.y;\n        switch (this.textAlign) {\n          case 'left':\n            positionInPath = reverse ? (totalPathLength - width) : 0;\n            break;\n          case 'center':\n            positionInPath = (totalPathLength - width) / 2;\n            break;\n          case 'right':\n            positionInPath = reverse ? 0 : (totalPathLength - width);\n            break;\n          //todo - add support for justify\n        }\n        positionInPath += this.pathStartOffset * (reverse ? -1 : 1);\n        for (i = reverse ? line.length - 1 : 0;\n          reverse ? i >= 0 : i < line.length;\n          reverse ? i-- : i++) {\n          graphemeInfo = lineBounds[i];\n          if (positionInPath > totalPathLength) {\n            positionInPath %= totalPathLength;\n          }\n          else if (positionInPath < 0) {\n            positionInPath += totalPathLength;\n          }\n          // it would probably much faster to send all the grapheme position for a line\n          // and calculate path position/angle at once.\n          this._setGraphemeOnPath(positionInPath, graphemeInfo, startingPoint);\n          positionInPath += graphemeInfo.kernedWidth;\n        }\n      }\n      return { width: width, numOfSpaces: numOfSpaces };\n    },\n\n    /**\n     * Calculate the angle  and the left,top position of the char that follow a path.\n     * It appends it to graphemeInfo to be reused later at rendering\n     * @private\n     * @param {Number} positionInPath to be measured\n     * @param {Object} graphemeInfo current grapheme box information\n     * @param {Object} startingPoint position of the point\n     */\n    _setGraphemeOnPath: function(positionInPath, graphemeInfo, startingPoint) {\n      var centerPosition = positionInPath + graphemeInfo.kernedWidth / 2,\n          path = this.path;\n\n      // we are at currentPositionOnPath. we want to know what point on the path is.\n      var info = fabric.util.getPointOnPath(path.path, centerPosition, path.segmentsInfo);\n      graphemeInfo.renderLeft = info.x - startingPoint.x;\n      graphemeInfo.renderTop = info.y - startingPoint.y;\n      graphemeInfo.angle = info.angle + (this.pathSide ===  'right' ? Math.PI : 0);\n    },\n\n    /**\n     * Measure and return the info of a single grapheme.\n     * needs the the info of previous graphemes already filled\n     * @private\n     * @param {String} grapheme to be measured\n     * @param {Number} lineIndex index of the line where the char is\n     * @param {Number} charIndex position in the line\n     * @param {String} [prevGrapheme] character preceding the one to be measured\n     */\n    _getGraphemeBox: function(grapheme, lineIndex, charIndex, prevGrapheme, skipLeft) {\n      var style = this.getCompleteStyleDeclaration(lineIndex, charIndex),\n          prevStyle = prevGrapheme ? this.getCompleteStyleDeclaration(lineIndex, charIndex - 1) : { },\n          info = this._measureChar(grapheme, style, prevGrapheme, prevStyle),\n          kernedWidth = info.kernedWidth,\n          width = info.width, charSpacing;\n\n      if (this.charSpacing !== 0) {\n        charSpacing = this._getWidthOfCharSpacing();\n        width += charSpacing;\n        kernedWidth += charSpacing;\n      }\n\n      var box = {\n        width: width,\n        left: 0,\n        height: style.fontSize,\n        kernedWidth: kernedWidth,\n        deltaY: style.deltaY,\n      };\n      if (charIndex > 0 && !skipLeft) {\n        var previousBox = this.__charBounds[lineIndex][charIndex - 1];\n        box.left = previousBox.left + previousBox.width + info.kernedWidth - info.width;\n      }\n      return box;\n    },\n\n    /**\n     * Calculate height of line at 'lineIndex'\n     * @param {Number} lineIndex index of line to calculate\n     * @return {Number}\n     */\n    getHeightOfLine: function(lineIndex) {\n      if (this.__lineHeights[lineIndex]) {\n        return this.__lineHeights[lineIndex];\n      }\n\n      var line = this._textLines[lineIndex],\n          // char 0 is measured before the line cycle because it nneds to char\n          // emptylines\n          maxHeight = this.getHeightOfChar(lineIndex, 0);\n      for (var i = 1, len = line.length; i < len; i++) {\n        maxHeight = Math.max(this.getHeightOfChar(lineIndex, i), maxHeight);\n      }\n\n      return this.__lineHeights[lineIndex] = maxHeight * this.lineHeight * this._fontSizeMult;\n    },\n\n    /**\n     * Calculate text box height\n     */\n    calcTextHeight: function() {\n      var lineHeight, height = 0;\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        lineHeight = this.getHeightOfLine(i);\n        height += (i === len - 1 ? lineHeight / this.lineHeight : lineHeight);\n      }\n      return height;\n    },\n\n    /**\n     * @private\n     * @return {Number} Left offset\n     */\n    _getLeftOffset: function() {\n      return this.direction === 'ltr' ? -this.width / 2 : this.width / 2;\n    },\n\n    /**\n     * @private\n     * @return {Number} Top offset\n     */\n    _getTopOffset: function() {\n      return -this.height / 2;\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {String} method Method name (\"fillText\" or \"strokeText\")\n     */\n    _renderTextCommon: function(ctx, method) {\n      ctx.save();\n      var lineHeights = 0, left = this._getLeftOffset(), top = this._getTopOffset();\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        var heightOfLine = this.getHeightOfLine(i),\n            maxHeight = heightOfLine / this.lineHeight,\n            leftOffset = this._getLineLeftOffset(i);\n        this._renderTextLine(\n          method,\n          ctx,\n          this._textLines[i],\n          left + leftOffset,\n          top + lineHeights + maxHeight,\n          i\n        );\n        lineHeights += heightOfLine;\n      }\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextFill: function(ctx) {\n      if (!this.fill && !this.styleHas('fill')) {\n        return;\n      }\n\n      this._renderTextCommon(ctx, 'fillText');\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextStroke: function(ctx) {\n      if ((!this.stroke || this.strokeWidth === 0) && this.isEmptyStyles()) {\n        return;\n      }\n\n      if (this.shadow && !this.shadow.affectStroke) {\n        this._removeShadow(ctx);\n      }\n\n      ctx.save();\n      this._setLineDash(ctx, this.strokeDashArray);\n      ctx.beginPath();\n      this._renderTextCommon(ctx, 'strokeText');\n      ctx.closePath();\n      ctx.restore();\n    },\n\n    /**\n     * @private\n     * @param {String} method fillText or strokeText.\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Array} line Content of the line, splitted in an array by grapheme\n     * @param {Number} left\n     * @param {Number} top\n     * @param {Number} lineIndex\n     */\n    _renderChars: function(method, ctx, line, left, top, lineIndex) {\n      // set proper line offset\n      var lineHeight = this.getHeightOfLine(lineIndex),\n          isJustify = this.textAlign.indexOf('justify') !== -1,\n          actualStyle,\n          nextStyle,\n          charsToRender = '',\n          charBox,\n          boxWidth = 0,\n          timeToRender,\n          path = this.path,\n          shortCut = !isJustify && this.charSpacing === 0 && this.isEmptyStyles(lineIndex) && !path,\n          isLtr = this.direction === 'ltr', sign = this.direction === 'ltr' ? 1 : -1,\n          drawingLeft, currentDirection = ctx.canvas.getAttribute('dir');\n      ctx.save();\n      if (currentDirection !== this.direction) {\n        ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');\n        ctx.direction = isLtr ? 'ltr' : 'rtl';\n        ctx.textAlign = isLtr ? 'left' : 'right';\n      }\n      top -= lineHeight * this._fontSizeFraction / this.lineHeight;\n      if (shortCut) {\n        // render all the line in one pass without checking\n        // drawingLeft = isLtr ? left : left - this.getLineWidth(lineIndex);\n        this._renderChar(method, ctx, lineIndex, 0, line.join(''), left, top, lineHeight);\n        ctx.restore();\n        return;\n      }\n      for (var i = 0, len = line.length - 1; i <= len; i++) {\n        timeToRender = i === len || this.charSpacing || path;\n        charsToRender += line[i];\n        charBox = this.__charBounds[lineIndex][i];\n        if (boxWidth === 0) {\n          left += sign * (charBox.kernedWidth - charBox.width);\n          boxWidth += charBox.width;\n        }\n        else {\n          boxWidth += charBox.kernedWidth;\n        }\n        if (isJustify && !timeToRender) {\n          if (this._reSpaceAndTab.test(line[i])) {\n            timeToRender = true;\n          }\n        }\n        if (!timeToRender) {\n          // if we have charSpacing, we render char by char\n          actualStyle = actualStyle || this.getCompleteStyleDeclaration(lineIndex, i);\n          nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1);\n          timeToRender = fabric.util.hasStyleChanged(actualStyle, nextStyle, false);\n        }\n        if (timeToRender) {\n          if (path) {\n            ctx.save();\n            ctx.translate(charBox.renderLeft, charBox.renderTop);\n            ctx.rotate(charBox.angle);\n            this._renderChar(method, ctx, lineIndex, i, charsToRender, -boxWidth / 2, 0, lineHeight);\n            ctx.restore();\n          }\n          else {\n            drawingLeft = left;\n            this._renderChar(method, ctx, lineIndex, i, charsToRender, drawingLeft, top, lineHeight);\n          }\n          charsToRender = '';\n          actualStyle = nextStyle;\n          left += sign * boxWidth;\n          boxWidth = 0;\n        }\n      }\n      ctx.restore();\n    },\n\n    /**\n     * This function try to patch the missing gradientTransform on canvas gradients.\n     * transforming a context to transform the gradient, is going to transform the stroke too.\n     * we want to transform the gradient but not the stroke operation, so we create\n     * a transformed gradient on a pattern and then we use the pattern instead of the gradient.\n     * this method has drawbacks: is slow, is in low resolution, needs a patch for when the size\n     * is limited.\n     * @private\n     * @param {fabric.Gradient} filler a fabric gradient instance\n     * @return {CanvasPattern} a pattern to use as fill/stroke style\n     */\n    _applyPatternGradientTransformText: function(filler) {\n      var pCanvas = fabric.util.createCanvasElement(), pCtx,\n          // TODO: verify compatibility with strokeUniform\n          width = this.width + this.strokeWidth, height = this.height + this.strokeWidth;\n      pCanvas.width = width;\n      pCanvas.height = height;\n      pCtx = pCanvas.getContext('2d');\n      pCtx.beginPath(); pCtx.moveTo(0, 0); pCtx.lineTo(width, 0); pCtx.lineTo(width, height);\n      pCtx.lineTo(0, height); pCtx.closePath();\n      pCtx.translate(width / 2, height / 2);\n      pCtx.fillStyle = filler.toLive(pCtx);\n      this._applyPatternGradientTransform(pCtx, filler);\n      pCtx.fill();\n      return pCtx.createPattern(pCanvas, 'no-repeat');\n    },\n\n    handleFiller: function(ctx, property, filler) {\n      var offsetX, offsetY;\n      if (filler.toLive) {\n        if (filler.gradientUnits === 'percentage' || filler.gradientTransform || filler.patternTransform) {\n          // need to transform gradient in a pattern.\n          // this is a slow process. If you are hitting this codepath, and the object\n          // is not using caching, you should consider switching it on.\n          // we need a canvas as big as the current object caching canvas.\n          offsetX = -this.width / 2;\n          offsetY = -this.height / 2;\n          ctx.translate(offsetX, offsetY);\n          ctx[property] = this._applyPatternGradientTransformText(filler);\n          return { offsetX: offsetX, offsetY: offsetY };\n        }\n        else {\n          // is a simple gradient or pattern\n          ctx[property] = filler.toLive(ctx, this);\n          return this._applyPatternGradientTransform(ctx, filler);\n        }\n      }\n      else {\n        // is a color\n        ctx[property] = filler;\n      }\n      return { offsetX: 0, offsetY: 0 };\n    },\n\n    _setStrokeStyles: function(ctx, decl) {\n      ctx.lineWidth = decl.strokeWidth;\n      ctx.lineCap = this.strokeLineCap;\n      ctx.lineDashOffset = this.strokeDashOffset;\n      ctx.lineJoin = this.strokeLineJoin;\n      ctx.miterLimit = this.strokeMiterLimit;\n      return this.handleFiller(ctx, 'strokeStyle', decl.stroke);\n    },\n\n    _setFillStyles: function(ctx, decl) {\n      return this.handleFiller(ctx, 'fillStyle', decl.fill);\n    },\n\n    /**\n     * @private\n     * @param {String} method\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {String} _char\n     * @param {Number} left Left coordinate\n     * @param {Number} top Top coordinate\n     * @param {Number} lineHeight Height of the line\n     */\n    _renderChar: function(method, ctx, lineIndex, charIndex, _char, left, top) {\n      var decl = this._getStyleDeclaration(lineIndex, charIndex),\n          fullDecl = this.getCompleteStyleDeclaration(lineIndex, charIndex),\n          shouldFill = method === 'fillText' && fullDecl.fill,\n          shouldStroke = method === 'strokeText' && fullDecl.stroke && fullDecl.strokeWidth,\n          fillOffsets, strokeOffsets;\n\n      if (!shouldStroke && !shouldFill) {\n        return;\n      }\n      ctx.save();\n\n      shouldFill && (fillOffsets = this._setFillStyles(ctx, fullDecl));\n      shouldStroke && (strokeOffsets = this._setStrokeStyles(ctx, fullDecl));\n\n      ctx.font = this._getFontDeclaration(fullDecl);\n\n\n      if (decl && decl.textBackgroundColor) {\n        this._removeShadow(ctx);\n      }\n      if (decl && decl.deltaY) {\n        top += decl.deltaY;\n      }\n      shouldFill && ctx.fillText(_char, left - fillOffsets.offsetX, top - fillOffsets.offsetY);\n      shouldStroke && ctx.strokeText(_char, left - strokeOffsets.offsetX, top - strokeOffsets.offsetY);\n      ctx.restore();\n    },\n\n    /**\n     * Turns the character into a 'superior figure' (i.e. 'superscript')\n     * @param {Number} start selection start\n     * @param {Number} end selection end\n     * @returns {fabric.Text} thisArg\n     * @chainable\n     */\n    setSuperscript: function(start, end) {\n      return this._setScript(start, end, this.superscript);\n    },\n\n    /**\n     * Turns the character into an 'inferior figure' (i.e. 'subscript')\n     * @param {Number} start selection start\n     * @param {Number} end selection end\n     * @returns {fabric.Text} thisArg\n     * @chainable\n     */\n    setSubscript: function(start, end) {\n      return this._setScript(start, end, this.subscript);\n    },\n\n    /**\n     * Applies 'schema' at given position\n     * @private\n     * @param {Number} start selection start\n     * @param {Number} end selection end\n     * @param {Number} schema\n     * @returns {fabric.Text} thisArg\n     * @chainable\n     */\n    _setScript: function(start, end, schema) {\n      var loc = this.get2DCursorLocation(start, true),\n          fontSize = this.getValueOfPropertyAt(loc.lineIndex, loc.charIndex, 'fontSize'),\n          dy = this.getValueOfPropertyAt(loc.lineIndex, loc.charIndex, 'deltaY'),\n          style = { fontSize: fontSize * schema.size, deltaY: dy + fontSize * schema.baseline };\n      this.setSelectionStyles(style, start, end);\n      return this;\n    },\n\n    /**\n     * @private\n     * @param {Number} lineIndex index text line\n     * @return {Number} Line left offset\n     */\n    _getLineLeftOffset: function(lineIndex) {\n      var lineWidth = this.getLineWidth(lineIndex),\n          lineDiff = this.width - lineWidth, textAlign = this.textAlign, direction = this.direction,\n          isEndOfWrapping, leftOffset = 0, isEndOfWrapping = this.isEndOfWrapping(lineIndex);\n      if (textAlign === 'justify'\n        || (textAlign === 'justify-center' && !isEndOfWrapping)\n        || (textAlign === 'justify-right' && !isEndOfWrapping)\n        || (textAlign === 'justify-left' && !isEndOfWrapping)\n      ) {\n        return 0;\n      }\n      if (textAlign === 'center') {\n        leftOffset = lineDiff / 2;\n      }\n      if (textAlign === 'right') {\n        leftOffset = lineDiff;\n      }\n      if (textAlign === 'justify-center') {\n        leftOffset = lineDiff / 2;\n      }\n      if (textAlign === 'justify-right') {\n        leftOffset = lineDiff;\n      }\n      if (direction === 'rtl') {\n        leftOffset -= lineDiff;\n      }\n      return leftOffset;\n    },\n\n    /**\n     * @private\n     */\n    _clearCache: function() {\n      this.__lineWidths = [];\n      this.__lineHeights = [];\n      this.__charBounds = [];\n    },\n\n    /**\n     * @private\n     */\n    _shouldClearDimensionCache: function() {\n      var shouldClear = this._forceClearCache;\n      shouldClear || (shouldClear = this.hasStateChanged('_dimensionAffectingProps'));\n      if (shouldClear) {\n        this.dirty = true;\n        this._forceClearCache = false;\n      }\n      return shouldClear;\n    },\n\n    /**\n     * Measure a single line given its index. Used to calculate the initial\n     * text bounding box. The values are calculated and stored in __lineWidths cache.\n     * @private\n     * @param {Number} lineIndex line number\n     * @return {Number} Line width\n     */\n    getLineWidth: function(lineIndex) {\n      if (this.__lineWidths[lineIndex] !== undefined) {\n        return this.__lineWidths[lineIndex];\n      }\n\n      var lineInfo = this.measureLine(lineIndex);\n      var width = lineInfo.width;\n      this.__lineWidths[lineIndex] = width;\n      return width;\n    },\n\n    _getWidthOfCharSpacing: function() {\n      if (this.charSpacing !== 0) {\n        return this.fontSize * this.charSpacing / 1000;\n      }\n      return 0;\n    },\n\n    /**\n     * Retrieves the value of property at given character position\n     * @param {Number} lineIndex the line number\n     * @param {Number} charIndex the character number\n     * @param {String} property the property name\n     * @returns the value of 'property'\n     */\n    getValueOfPropertyAt: function(lineIndex, charIndex, property) {\n      var charStyle = this._getStyleDeclaration(lineIndex, charIndex);\n      if (charStyle && typeof charStyle[property] !== 'undefined') {\n        return charStyle[property];\n      }\n      return this[property];\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _renderTextDecoration: function(ctx, type) {\n      if (!this[type] && !this.styleHas(type)) {\n        return;\n      }\n      ctx.save();\n      // if type is overline or linethrough we shouldn't cast shadow\n      if (type === 'overline' || type === 'linethrough') {\n        this._removeShadow(ctx);\n      }\n      var heightOfLine, size, _size,\n          lineLeftOffset, dy, _dy,\n          line, lastDecoration,\n          leftOffset = this._getLeftOffset(),\n          topOffset = this._getTopOffset(), top,\n          boxStart, boxWidth, charBox, currentDecoration,\n          maxHeight, currentFill, lastFill, path = this.path,\n          charSpacing = this._getWidthOfCharSpacing(),\n          offsetY = this.offsets[type];\n\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        heightOfLine = this.getHeightOfLine(i);\n        if (!this[type] && !this.styleHas(type, i)) {\n          topOffset += heightOfLine;\n          continue;\n        }\n        line = this._textLines[i];\n        maxHeight = heightOfLine / this.lineHeight;\n        lineLeftOffset = this._getLineLeftOffset(i);\n        boxStart = 0;\n        boxWidth = 0;\n        lastDecoration = this.getValueOfPropertyAt(i, 0, type);\n        lastFill = this.getValueOfPropertyAt(i, 0, 'fill');\n        top = topOffset + maxHeight * (1 - this._fontSizeFraction);\n        size = this.getHeightOfChar(i, 0);\n        dy = this.getValueOfPropertyAt(i, 0, 'deltaY');\n        for (var j = 0, jlen = line.length; j < jlen; j++) {\n          charBox = this.__charBounds[i][j];\n          currentDecoration = this.getValueOfPropertyAt(i, j, type);\n          currentFill = this.getValueOfPropertyAt(i, j, 'fill');\n          _size = this.getHeightOfChar(i, j);\n          _dy = this.getValueOfPropertyAt(i, j, 'deltaY');\n          if (path && currentDecoration && currentFill) {\n            ctx.save();\n            ctx.fillStyle = lastFill;\n            ctx.translate(charBox.renderLeft, charBox.renderTop);\n            ctx.rotate(charBox.angle);\n            ctx.fillRect(\n              -charBox.kernedWidth / 2,\n              offsetY * _size + _dy,\n              charBox.kernedWidth,\n              this.fontSize / 15\n            );\n            ctx.restore();\n          }\n          else if (\n            (currentDecoration !== lastDecoration || currentFill !== lastFill || _size !== size || _dy !== dy)\n            && boxWidth > 0\n          ) {\n            var drawStart = leftOffset + lineLeftOffset + boxStart;\n            if (this.direction === 'rtl') {\n              drawStart = this.width - drawStart - boxWidth;\n            }\n            if (lastDecoration && lastFill) {\n              ctx.fillStyle = lastFill;\n              ctx.fillRect(\n                drawStart,\n                top + offsetY * size + dy,\n                boxWidth,\n                this.fontSize / 15\n              );\n            }\n            boxStart = charBox.left;\n            boxWidth = charBox.width;\n            lastDecoration = currentDecoration;\n            lastFill = currentFill;\n            size = _size;\n            dy = _dy;\n          }\n          else {\n            boxWidth += charBox.kernedWidth;\n          }\n        }\n        var drawStart = leftOffset + lineLeftOffset + boxStart;\n        if (this.direction === 'rtl') {\n          drawStart = this.width - drawStart - boxWidth;\n        }\n        ctx.fillStyle = currentFill;\n        currentDecoration && currentFill && ctx.fillRect(\n          drawStart,\n          top + offsetY * size + dy,\n          boxWidth - charSpacing,\n          this.fontSize / 15\n        );\n        topOffset += heightOfLine;\n      }\n      ctx.restore();\n    },\n\n    /**\n     * return font declaration string for canvas context\n     * @param {Object} [styleObject] object\n     * @returns {String} font declaration formatted for canvas context.\n     */\n    _getFontDeclaration: function(styleObject, forMeasuring) {\n      var style = styleObject || this, family = this.fontFamily,\n          fontIsGeneric = fabric.Text.genericFonts.indexOf(family.toLowerCase()) > -1;\n      var fontFamily = family === undefined ||\n      family.indexOf('\\'') > -1 || family.indexOf(',') > -1 ||\n      family.indexOf('\"') > -1 || fontIsGeneric\n        ? style.fontFamily : '\"' + style.fontFamily + '\"';\n      return [\n        // node-canvas needs \"weight style\", while browsers need \"style weight\"\n        // verify if this can be fixed in JSDOM\n        (fabric.isLikelyNode ? style.fontWeight : style.fontStyle),\n        (fabric.isLikelyNode ? style.fontStyle : style.fontWeight),\n        forMeasuring ? this.CACHE_FONT_SIZE + 'px' : style.fontSize + 'px',\n        fontFamily\n      ].join(' ');\n    },\n\n    /**\n     * Renders text instance on a specified context\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    render: function(ctx) {\n      // do not render if object is not visible\n      if (!this.visible) {\n        return;\n      }\n      if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) {\n        return;\n      }\n      if (this._shouldClearDimensionCache()) {\n        this.initDimensions();\n      }\n      this.callSuper('render', ctx);\n    },\n\n    /**\n     * Returns the text as an array of lines.\n     * @param {String} text text to split\n     * @returns {Array} Lines in the text\n     */\n    _splitTextIntoLines: function(text) {\n      var lines = text.split(this._reNewline),\n          newLines = new Array(lines.length),\n          newLine = ['\\n'],\n          newText = [];\n      for (var i = 0; i < lines.length; i++) {\n        newLines[i] = fabric.util.string.graphemeSplit(lines[i]);\n        newText = newText.concat(newLines[i], newLine);\n      }\n      newText.pop();\n      return { _unwrappedLines: newLines, lines: lines, graphemeText: newText, graphemeLines: newLines };\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} Object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      var allProperties = additionalProps.concat(propertiesToInclude);\n      var obj = this.callSuper('toObject', allProperties);\n      obj.styles = fabric.util.stylesToArray(this.styles, this.text);\n      if (obj.path) {\n        obj.path = this.path.toObject();\n      }\n      return obj;\n    },\n\n    /**\n     * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.\n     * @param {String|Object} key Property name or object (if object, iterate over the object properties)\n     * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)\n     * @return {fabric.Object} thisArg\n     * @chainable\n     */\n    set: function(key, value) {\n      this.callSuper('set', key, value);\n      var needsDims = false;\n      var isAddingPath = false;\n      if (typeof key === 'object') {\n        for (var _key in key) {\n          if (_key === 'path') {\n            this.setPathInfo();\n          }\n          needsDims = needsDims || this._dimensionAffectingProps.indexOf(_key) !== -1;\n          isAddingPath = isAddingPath || _key === 'path';\n        }\n      }\n      else {\n        needsDims = this._dimensionAffectingProps.indexOf(key) !== -1;\n        isAddingPath = key === 'path';\n      }\n      if (isAddingPath) {\n        this.setPathInfo();\n      }\n      if (needsDims) {\n        this.initDimensions();\n        this.setCoords();\n      }\n      return this;\n    },\n\n    /**\n     * Returns complexity of an instance\n     * @return {Number} complexity\n     */\n    complexity: function() {\n      return 1;\n    }\n  });\n\n  /* _FROM_SVG_START_ */\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Text.fromElement})\n   * @static\n   * @memberOf fabric.Text\n   * @see: http://www.w3.org/TR/SVG/text.html#TextElement\n   */\n  fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(\n    'x y dx dy font-family font-style font-weight font-size letter-spacing text-decoration text-anchor'.split(' '));\n\n  /**\n   * Default SVG font size\n   * @static\n   * @memberOf fabric.Text\n   */\n  fabric.Text.DEFAULT_SVG_FONT_SIZE = 16;\n\n  /**\n   * Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)\n   * @static\n   * @memberOf fabric.Text\n   * @param {SVGElement} element Element to parse\n   * @param {Function} callback callback function invoked after parsing\n   * @param {Object} [options] Options object\n   */\n  fabric.Text.fromElement = function(element, callback, options) {\n    if (!element) {\n      return callback(null);\n    }\n\n    var parsedAttributes = fabric.parseAttributes(element, fabric.Text.ATTRIBUTE_NAMES),\n        parsedAnchor = parsedAttributes.textAnchor || 'left';\n    options = fabric.util.object.extend((options ? clone(options) : { }), parsedAttributes);\n\n    options.top = options.top || 0;\n    options.left = options.left || 0;\n    if (parsedAttributes.textDecoration) {\n      var textDecoration = parsedAttributes.textDecoration;\n      if (textDecoration.indexOf('underline') !== -1) {\n        options.underline = true;\n      }\n      if (textDecoration.indexOf('overline') !== -1) {\n        options.overline = true;\n      }\n      if (textDecoration.indexOf('line-through') !== -1) {\n        options.linethrough = true;\n      }\n      delete options.textDecoration;\n    }\n    if ('dx' in parsedAttributes) {\n      options.left += parsedAttributes.dx;\n    }\n    if ('dy' in parsedAttributes) {\n      options.top += parsedAttributes.dy;\n    }\n    if (!('fontSize' in options)) {\n      options.fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;\n    }\n\n    var textContent = '';\n\n    // The XML is not properly parsed in IE9 so a workaround to get\n    // textContent is through firstChild.data. Another workaround would be\n    // to convert XML loaded from a file to be converted using DOMParser (same way loadSVGFromString() does)\n    if (!('textContent' in element)) {\n      if ('firstChild' in element && element.firstChild !== null) {\n        if ('data' in element.firstChild && element.firstChild.data !== null) {\n          textContent = element.firstChild.data;\n        }\n      }\n    }\n    else {\n      textContent = element.textContent;\n    }\n\n    textContent = textContent.replace(/^\\s+|\\s+$|\\n+/g, '').replace(/\\s+/g, ' ');\n    var originalStrokeWidth = options.strokeWidth;\n    options.strokeWidth = 0;\n\n    var text = new fabric.Text(textContent, options),\n        textHeightScaleFactor = text.getScaledHeight() / text.height,\n        lineHeightDiff = (text.height + text.strokeWidth) * text.lineHeight - text.height,\n        scaledDiff = lineHeightDiff * textHeightScaleFactor,\n        textHeight = text.getScaledHeight() + scaledDiff,\n        offX = 0;\n    /*\n      Adjust positioning:\n        x/y attributes in SVG correspond to the bottom-left corner of text bounding box\n        fabric output by default at top, left.\n    */\n    if (parsedAnchor === 'center') {\n      offX = text.getScaledWidth() / 2;\n    }\n    if (parsedAnchor === 'right') {\n      offX = text.getScaledWidth();\n    }\n    text.set({\n      left: text.left - offX,\n      top: text.top - (textHeight - text.fontSize * (0.07 + text._fontSizeFraction)) / text.lineHeight,\n      strokeWidth: typeof originalStrokeWidth !== 'undefined' ? originalStrokeWidth : 1,\n    });\n    callback(text);\n  };\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns fabric.Text instance from an object representation\n   * @static\n   * @memberOf fabric.Text\n   * @param {Object} object plain js Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Text instance is created\n   */\n  fabric.Text.fromObject = function(object, callback) {\n    var objectCopy = clone(object), path = object.path;\n    delete objectCopy.path;\n    return fabric.Object._fromObject('Text', objectCopy, function(textInstance) {\n      textInstance.styles = fabric.util.stylesFromArray(object.styles, object.text);\n      if (path) {\n        fabric.Object._fromObject('Path', path, function(pathInstance) {\n          textInstance.set('path', pathInstance);\n          callback(textInstance);\n        }, 'path');\n      }\n      else {\n        callback(textInstance);\n      }\n    }, 'text');\n  };\n\n  fabric.Text.genericFonts = ['sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'];\n\n  fabric.util.createAccessors && fabric.util.createAccessors(fabric.Text);\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n  fabric.util.object.extend(fabric.Text.prototype, /** @lends fabric.Text.prototype */ {\n    /**\n     * Returns true if object has no styling or no styling in a line\n     * @param {Number} lineIndex , lineIndex is on wrapped lines.\n     * @return {Boolean}\n     */\n    isEmptyStyles: function(lineIndex) {\n      if (!this.styles) {\n        return true;\n      }\n      if (typeof lineIndex !== 'undefined' && !this.styles[lineIndex]) {\n        return true;\n      }\n      var obj = typeof lineIndex === 'undefined' ? this.styles : { line: this.styles[lineIndex] };\n      for (var p1 in obj) {\n        for (var p2 in obj[p1]) {\n          // eslint-disable-next-line no-unused-vars\n          for (var p3 in obj[p1][p2]) {\n            return false;\n          }\n        }\n      }\n      return true;\n    },\n\n    /**\n     * Returns true if object has a style property or has it ina specified line\n     * This function is used to detect if a text will use a particular property or not.\n     * @param {String} property to check for\n     * @param {Number} lineIndex to check the style on\n     * @return {Boolean}\n     */\n    styleHas: function(property, lineIndex) {\n      if (!this.styles || !property || property === '') {\n        return false;\n      }\n      if (typeof lineIndex !== 'undefined' && !this.styles[lineIndex]) {\n        return false;\n      }\n      var obj = typeof lineIndex === 'undefined' ? this.styles : { 0: this.styles[lineIndex] };\n      // eslint-disable-next-line\n      for (var p1 in obj) {\n        // eslint-disable-next-line\n        for (var p2 in obj[p1]) {\n          if (typeof obj[p1][p2][property] !== 'undefined') {\n            return true;\n          }\n        }\n      }\n      return false;\n    },\n\n    /**\n     * Check if characters in a text have a value for a property\n     * whose value matches the textbox's value for that property.  If so,\n     * the character-level property is deleted.  If the character\n     * has no other properties, then it is also deleted.  Finally,\n     * if the line containing that character has no other characters\n     * then it also is deleted.\n     *\n     * @param {string} property The property to compare between characters and text.\n     */\n    cleanStyle: function(property) {\n      if (!this.styles || !property || property === '') {\n        return false;\n      }\n      var obj = this.styles, stylesCount = 0, letterCount, stylePropertyValue,\n          allStyleObjectPropertiesMatch = true, graphemeCount = 0, styleObject;\n      // eslint-disable-next-line\n      for (var p1 in obj) {\n        letterCount = 0;\n        // eslint-disable-next-line\n        for (var p2 in obj[p1]) {\n          var styleObject = obj[p1][p2],\n              stylePropertyHasBeenSet = styleObject.hasOwnProperty(property);\n\n          stylesCount++;\n\n          if (stylePropertyHasBeenSet) {\n            if (!stylePropertyValue) {\n              stylePropertyValue = styleObject[property];\n            }\n            else if (styleObject[property] !== stylePropertyValue) {\n              allStyleObjectPropertiesMatch = false;\n            }\n\n            if (styleObject[property] === this[property]) {\n              delete styleObject[property];\n            }\n          }\n          else {\n            allStyleObjectPropertiesMatch = false;\n          }\n\n          if (Object.keys(styleObject).length !== 0) {\n            letterCount++;\n          }\n          else {\n            delete obj[p1][p2];\n          }\n        }\n\n        if (letterCount === 0) {\n          delete obj[p1];\n        }\n      }\n      // if every grapheme has the same style set then\n      // delete those styles and set it on the parent\n      for (var i = 0; i < this._textLines.length; i++) {\n        graphemeCount += this._textLines[i].length;\n      }\n      if (allStyleObjectPropertiesMatch && stylesCount === graphemeCount) {\n        this[property] = stylePropertyValue;\n        this.removeStyle(property);\n      }\n    },\n\n    /**\n     * Remove a style property or properties from all individual character styles\n     * in a text object.  Deletes the character style object if it contains no other style\n     * props.  Deletes a line style object if it contains no other character styles.\n     *\n     * @param {String} props The property to remove from character styles.\n     */\n    removeStyle: function(property) {\n      if (!this.styles || !property || property === '') {\n        return;\n      }\n      var obj = this.styles, line, lineNum, charNum;\n      for (lineNum in obj) {\n        line = obj[lineNum];\n        for (charNum in line) {\n          delete line[charNum][property];\n          if (Object.keys(line[charNum]).length === 0) {\n            delete line[charNum];\n          }\n        }\n        if (Object.keys(line).length === 0) {\n          delete obj[lineNum];\n        }\n      }\n    },\n\n    /**\n     * @private\n     */\n    _extendStyles: function(index, styles) {\n      var loc = this.get2DCursorLocation(index);\n\n      if (!this._getLineStyle(loc.lineIndex)) {\n        this._setLineStyle(loc.lineIndex);\n      }\n\n      if (!this._getStyleDeclaration(loc.lineIndex, loc.charIndex)) {\n        this._setStyleDeclaration(loc.lineIndex, loc.charIndex, {});\n      }\n\n      fabric.util.object.extend(this._getStyleDeclaration(loc.lineIndex, loc.charIndex), styles);\n    },\n\n    /**\n     * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)\n     * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n     * @param {Boolean} [skipWrapping] consider the location for unwrapped lines. useful to manage styles.\n     */\n    get2DCursorLocation: function(selectionStart, skipWrapping) {\n      if (typeof selectionStart === 'undefined') {\n        selectionStart = this.selectionStart;\n      }\n      var lines = skipWrapping ? this._unwrappedTextLines : this._textLines,\n          len = lines.length;\n      for (var i = 0; i < len; i++) {\n        if (selectionStart <= lines[i].length) {\n          return {\n            lineIndex: i,\n            charIndex: selectionStart\n          };\n        }\n        selectionStart -= lines[i].length + this.missingNewlineOffset(i, skipWrapping);\n      }\n      return {\n        lineIndex: i - 1,\n        charIndex: lines[i - 1].length < selectionStart ? lines[i - 1].length : selectionStart\n      };\n    },\n\n    /**\n     * Gets style of a current selection/cursor (at the start position)\n     * if startIndex or endIndex are not provided, selectionStart or selectionEnd will be used.\n     * @param {Number} [startIndex] Start index to get styles at\n     * @param {Number} [endIndex] End index to get styles at, if not specified selectionEnd or startIndex + 1\n     * @param {Boolean} [complete] get full style or not\n     * @return {Array} styles an array with one, zero or more Style objects\n     */\n    getSelectionStyles: function(startIndex, endIndex, complete) {\n      if (typeof startIndex === 'undefined') {\n        startIndex = this.selectionStart || 0;\n      }\n      if (typeof endIndex === 'undefined') {\n        endIndex = this.selectionEnd || startIndex;\n      }\n      var styles = [];\n      for (var i = startIndex; i < endIndex; i++) {\n        styles.push(this.getStyleAtPosition(i, complete));\n      }\n      return styles;\n    },\n\n    /**\n     * Gets style of a current selection/cursor position\n     * @param {Number} position  to get styles at\n     * @param {Boolean} [complete] full style if true\n     * @return {Object} style Style object at a specified index\n     * @private\n     */\n    getStyleAtPosition: function(position, complete) {\n      var loc = this.get2DCursorLocation(position),\n          style = complete ? this.getCompleteStyleDeclaration(loc.lineIndex, loc.charIndex) :\n            this._getStyleDeclaration(loc.lineIndex, loc.charIndex);\n      return style || {};\n    },\n\n    /**\n     * Sets style of a current selection, if no selection exist, do not set anything.\n     * @param {Object} [styles] Styles object\n     * @param {Number} [startIndex] Start index to get styles at\n     * @param {Number} [endIndex] End index to get styles at, if not specified selectionEnd or startIndex + 1\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    setSelectionStyles: function(styles, startIndex, endIndex) {\n      if (typeof startIndex === 'undefined') {\n        startIndex = this.selectionStart || 0;\n      }\n      if (typeof endIndex === 'undefined') {\n        endIndex = this.selectionEnd || startIndex;\n      }\n      for (var i = startIndex; i < endIndex; i++) {\n        this._extendStyles(i, styles);\n      }\n      /* not included in _extendStyles to avoid clearing cache more than once */\n      this._forceClearCache = true;\n      return this;\n    },\n\n    /**\n     * get the reference, not a clone, of the style object for a given character\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @return {Object} style object\n     */\n    _getStyleDeclaration: function(lineIndex, charIndex) {\n      var lineStyle = this.styles && this.styles[lineIndex];\n      if (!lineStyle) {\n        return null;\n      }\n      return lineStyle[charIndex];\n    },\n\n    /**\n     * return a new object that contains all the style property for a character\n     * the object returned is newly created\n     * @param {Number} lineIndex of the line where the character is\n     * @param {Number} charIndex position of the character on the line\n     * @return {Object} style object\n     */\n    getCompleteStyleDeclaration: function(lineIndex, charIndex) {\n      var style = this._getStyleDeclaration(lineIndex, charIndex) || { },\n          styleObject = { }, prop;\n      for (var i = 0; i < this._styleProperties.length; i++) {\n        prop = this._styleProperties[i];\n        styleObject[prop] = typeof style[prop] === 'undefined' ? this[prop] : style[prop];\n      }\n      return styleObject;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {Object} style\n     * @private\n     */\n    _setStyleDeclaration: function(lineIndex, charIndex, style) {\n      this.styles[lineIndex][charIndex] = style;\n    },\n\n    /**\n     *\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @private\n     */\n    _deleteStyleDeclaration: function(lineIndex, charIndex) {\n      delete this.styles[lineIndex][charIndex];\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @return {Boolean} if the line exists or not\n     * @private\n     */\n    _getLineStyle: function(lineIndex) {\n      return !!this.styles[lineIndex];\n    },\n\n    /**\n     * Set the line style to an empty object so that is initialized\n     * @param {Number} lineIndex\n     * @private\n     */\n    _setLineStyle: function(lineIndex) {\n      this.styles[lineIndex] = {};\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @private\n     */\n    _deleteLineStyle: function(lineIndex) {\n      delete this.styles[lineIndex];\n    }\n  });\n})();\n\n\n(function() {\n\n  function parseDecoration(object) {\n    if (object.textDecoration) {\n      object.textDecoration.indexOf('underline') > -1 && (object.underline = true);\n      object.textDecoration.indexOf('line-through') > -1 && (object.linethrough = true);\n      object.textDecoration.indexOf('overline') > -1 && (object.overline = true);\n      delete object.textDecoration;\n    }\n  }\n\n  /**\n   * IText class (introduced in <b>v1.4</b>) Events are also fired with \"text:\"\n   * prefix when observing canvas.\n   * @class fabric.IText\n   * @extends fabric.Text\n   * @mixes fabric.Observable\n   *\n   * @fires changed\n   * @fires selection:changed\n   * @fires editing:entered\n   * @fires editing:exited\n   *\n   * @return {fabric.IText} thisArg\n   * @see {@link fabric.IText#initialize} for constructor definition\n   *\n   * <p>Supported key combinations:</p>\n   * <pre>\n   *   Move cursor:                    left, right, up, down\n   *   Select character:               shift + left, shift + right\n   *   Select text vertically:         shift + up, shift + down\n   *   Move cursor by word:            alt + left, alt + right\n   *   Select words:                   shift + alt + left, shift + alt + right\n   *   Move cursor to line start/end:  cmd + left, cmd + right or home, end\n   *   Select till start/end of line:  cmd + shift + left, cmd + shift + right or shift + home, shift + end\n   *   Jump to start/end of text:      cmd + up, cmd + down\n   *   Select till start/end of text:  cmd + shift + up, cmd + shift + down or shift + pgUp, shift + pgDown\n   *   Delete character:               backspace\n   *   Delete word:                    alt + backspace\n   *   Delete line:                    cmd + backspace\n   *   Forward delete:                 delete\n   *   Copy text:                      ctrl/cmd + c\n   *   Paste text:                     ctrl/cmd + v\n   *   Cut text:                       ctrl/cmd + x\n   *   Select entire text:             ctrl/cmd + a\n   *   Quit editing                    tab or esc\n   * </pre>\n   *\n   * <p>Supported mouse/touch combination</p>\n   * <pre>\n   *   Position cursor:                click/touch\n   *   Create selection:               click/touch & drag\n   *   Create selection:               click & shift + click\n   *   Select word:                    double click\n   *   Select line:                    triple click\n   * </pre>\n   */\n  fabric.IText = fabric.util.createClass(fabric.Text, fabric.Observable, /** @lends fabric.IText.prototype */ {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'i-text',\n\n    /**\n     * Index where text selection starts (or where cursor is when there is no selection)\n     * @type Number\n     * @default\n     */\n    selectionStart: 0,\n\n    /**\n     * Index where text selection ends\n     * @type Number\n     * @default\n     */\n    selectionEnd: 0,\n\n    /**\n     * Color of text selection\n     * @type String\n     * @default\n     */\n    selectionColor: 'rgba(17,119,255,0.3)',\n\n    /**\n     * Indicates whether text is in editing mode\n     * @type Boolean\n     * @default\n     */\n    isEditing: false,\n\n    /**\n     * Indicates whether a text can be edited\n     * @type Boolean\n     * @default\n     */\n    editable: true,\n\n    /**\n     * Border color of text object while it's in editing mode\n     * @type String\n     * @default\n     */\n    editingBorderColor: 'rgba(102,153,255,0.25)',\n\n    /**\n     * Width of cursor (in px)\n     * @type Number\n     * @default\n     */\n    cursorWidth: 2,\n\n    /**\n     * Color of text cursor color in editing mode.\n     * if not set (default) will take color from the text.\n     * if set to a color value that fabric can understand, it will\n     * be used instead of the color of the text at the current position.\n     * @type String\n     * @default\n     */\n    cursorColor: '',\n\n    /**\n     * Delay between cursor blink (in ms)\n     * @type Number\n     * @default\n     */\n    cursorDelay: 1000,\n\n    /**\n     * Duration of cursor fadein (in ms)\n     * @type Number\n     * @default\n     */\n    cursorDuration: 600,\n\n    /**\n     * Indicates whether internal text char widths can be cached\n     * @type Boolean\n     * @default\n     */\n    caching: true,\n\n    /**\n     * DOM container to append the hiddenTextarea.\n     * An alternative to attaching to the document.body.\n     * Useful to reduce laggish redraw of the full document.body tree and\n     * also with modals event capturing that won't let the textarea take focus.\n     * @type HTMLElement\n     * @default\n     */\n    hiddenTextareaContainer: null,\n\n    /**\n     * @private\n     */\n    _reSpace: /\\s|\\n/,\n\n    /**\n     * @private\n     */\n    _currentCursorOpacity: 0,\n\n    /**\n     * @private\n     */\n    _selectionDirection: null,\n\n    /**\n     * @private\n     */\n    _abortCursorAnimation: false,\n\n    /**\n     * @private\n     */\n    __widthOfSpace: [],\n\n    /**\n     * Helps determining when the text is in composition, so that the cursor\n     * rendering is altered.\n     */\n    inCompositionMode: false,\n\n    /**\n     * Constructor\n     * @param {String} text Text string\n     * @param {Object} [options] Options object\n     * @return {fabric.IText} thisArg\n     */\n    initialize: function(text, options) {\n      this.callSuper('initialize', text, options);\n      this.initBehavior();\n    },\n\n    /**\n     * Sets selection start (left boundary of a selection)\n     * @param {Number} index Index to set selection start to\n     */\n    setSelectionStart: function(index) {\n      index = Math.max(index, 0);\n      this._updateAndFire('selectionStart', index);\n    },\n\n    /**\n     * Sets selection end (right boundary of a selection)\n     * @param {Number} index Index to set selection end to\n     */\n    setSelectionEnd: function(index) {\n      index = Math.min(index, this.text.length);\n      this._updateAndFire('selectionEnd', index);\n    },\n\n    /**\n     * @private\n     * @param {String} property 'selectionStart' or 'selectionEnd'\n     * @param {Number} index new position of property\n     */\n    _updateAndFire: function(property, index) {\n      if (this[property] !== index) {\n        this._fireSelectionChanged();\n        this[property] = index;\n      }\n      this._updateTextarea();\n    },\n\n    /**\n     * Fires the even of selection changed\n     * @private\n     */\n    _fireSelectionChanged: function() {\n      this.fire('selection:changed');\n      this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n    },\n\n    /**\n     * Initialize text dimensions. Render all text on given context\n     * or on a offscreen canvas to get the text width with measureText.\n     * Updates this.width and this.height with the proper values.\n     * Does not return dimensions.\n     * @private\n     */\n    initDimensions: function() {\n      this.isEditing && this.initDelayedCursor();\n      this.clearContextTop();\n      this.callSuper('initDimensions');\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    render: function(ctx) {\n      this.clearContextTop();\n      this.callSuper('render', ctx);\n      // clear the cursorOffsetCache, so we ensure to calculate once per renderCursor\n      // the correct position but not at every cursor animation.\n      this.cursorOffsetCache = { };\n      this.renderCursorOrSelection();\n    },\n\n    /**\n     * @private\n     * @param {CanvasRenderingContext2D} ctx Context to render on\n     */\n    _render: function(ctx) {\n      this.callSuper('_render', ctx);\n    },\n\n    /**\n     * Prepare and clean the contextTop\n     */\n    clearContextTop: function(skipRestore) {\n      if (!this.isEditing || !this.canvas || !this.canvas.contextTop) {\n        return;\n      }\n      var ctx = this.canvas.contextTop, v = this.canvas.viewportTransform;\n      ctx.save();\n      ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n      this.transform(ctx);\n      this._clearTextArea(ctx);\n      skipRestore || ctx.restore();\n    },\n    /**\n     * Renders cursor or selection (depending on what exists)\n     * it does on the contextTop. If contextTop is not available, do nothing.\n     */\n    renderCursorOrSelection: function() {\n      if (!this.isEditing || !this.canvas || !this.canvas.contextTop) {\n        return;\n      }\n      var boundaries = this._getCursorBoundaries(),\n          ctx = this.canvas.contextTop;\n      this.clearContextTop(true);\n      if (this.selectionStart === this.selectionEnd) {\n        this.renderCursor(boundaries, ctx);\n      }\n      else {\n        this.renderSelection(boundaries, ctx);\n      }\n      ctx.restore();\n    },\n\n    _clearTextArea: function(ctx) {\n      // we add 4 pixel, to be sure to do not leave any pixel out\n      var width = this.width + 4, height = this.height + 4;\n      ctx.clearRect(-width / 2, -height / 2, width, height);\n    },\n\n    /**\n     * Returns cursor boundaries (left, top, leftOffset, topOffset)\n     * @private\n     * @param {Array} chars Array of characters\n     * @param {String} typeOfBoundaries\n     */\n    _getCursorBoundaries: function(position) {\n\n      // left/top are left/top of entire text box\n      // leftOffset/topOffset are offset from that left/top point of a text box\n\n      if (typeof position === 'undefined') {\n        position = this.selectionStart;\n      }\n\n      var left = this._getLeftOffset(),\n          top = this._getTopOffset(),\n          offsets = this._getCursorBoundariesOffsets(position);\n      return {\n        left: left,\n        top: top,\n        leftOffset: offsets.left,\n        topOffset: offsets.top\n      };\n    },\n\n    /**\n     * @private\n     */\n    _getCursorBoundariesOffsets: function(position) {\n      if (this.cursorOffsetCache && 'top' in this.cursorOffsetCache) {\n        return this.cursorOffsetCache;\n      }\n      var lineLeftOffset,\n          lineIndex,\n          charIndex,\n          topOffset = 0,\n          leftOffset = 0,\n          boundaries,\n          cursorPosition = this.get2DCursorLocation(position);\n      charIndex = cursorPosition.charIndex;\n      lineIndex = cursorPosition.lineIndex;\n      for (var i = 0; i < lineIndex; i++) {\n        topOffset += this.getHeightOfLine(i);\n      }\n      lineLeftOffset = this._getLineLeftOffset(lineIndex);\n      var bound = this.__charBounds[lineIndex][charIndex];\n      bound && (leftOffset = bound.left);\n      if (this.charSpacing !== 0 && charIndex === this._textLines[lineIndex].length) {\n        leftOffset -= this._getWidthOfCharSpacing();\n      }\n      boundaries = {\n        top: topOffset,\n        left: lineLeftOffset + (leftOffset > 0 ? leftOffset : 0),\n      };\n      if (this.direction === 'rtl') {\n        boundaries.left *= -1;\n      }\n      this.cursorOffsetCache = boundaries;\n      return this.cursorOffsetCache;\n    },\n\n    /**\n     * Renders cursor\n     * @param {Object} boundaries\n     * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n     */\n    renderCursor: function(boundaries, ctx) {\n      var cursorLocation = this.get2DCursorLocation(),\n          lineIndex = cursorLocation.lineIndex,\n          charIndex = cursorLocation.charIndex > 0 ? cursorLocation.charIndex - 1 : 0,\n          charHeight = this.getValueOfPropertyAt(lineIndex, charIndex, 'fontSize'),\n          multiplier = this.scaleX * this.canvas.getZoom(),\n          cursorWidth = this.cursorWidth / multiplier,\n          topOffset = boundaries.topOffset,\n          dy = this.getValueOfPropertyAt(lineIndex, charIndex, 'deltaY');\n      topOffset += (1 - this._fontSizeFraction) * this.getHeightOfLine(lineIndex) / this.lineHeight\n        - charHeight * (1 - this._fontSizeFraction);\n\n      if (this.inCompositionMode) {\n        this.renderSelection(boundaries, ctx);\n      }\n      ctx.fillStyle = this.cursorColor || this.getValueOfPropertyAt(lineIndex, charIndex, 'fill');\n      ctx.globalAlpha = this.__isMousedown ? 1 : this._currentCursorOpacity;\n      ctx.fillRect(\n        boundaries.left + boundaries.leftOffset - cursorWidth / 2,\n        topOffset + boundaries.top + dy,\n        cursorWidth,\n        charHeight);\n    },\n\n    /**\n     * Renders text selection\n     * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n     * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n     */\n    renderSelection: function(boundaries, ctx) {\n\n      var selectionStart = this.inCompositionMode ? this.hiddenTextarea.selectionStart : this.selectionStart,\n          selectionEnd = this.inCompositionMode ? this.hiddenTextarea.selectionEnd : this.selectionEnd,\n          isJustify = this.textAlign.indexOf('justify') !== -1,\n          start = this.get2DCursorLocation(selectionStart),\n          end = this.get2DCursorLocation(selectionEnd),\n          startLine = start.lineIndex,\n          endLine = end.lineIndex,\n          startChar = start.charIndex < 0 ? 0 : start.charIndex,\n          endChar = end.charIndex < 0 ? 0 : end.charIndex;\n\n      for (var i = startLine; i <= endLine; i++) {\n        var lineOffset = this._getLineLeftOffset(i) || 0,\n            lineHeight = this.getHeightOfLine(i),\n            realLineHeight = 0, boxStart = 0, boxEnd = 0;\n\n        if (i === startLine) {\n          boxStart = this.__charBounds[startLine][startChar].left;\n        }\n        if (i >= startLine && i < endLine) {\n          boxEnd = isJustify && !this.isEndOfWrapping(i) ? this.width : this.getLineWidth(i) || 5; // WTF is this 5?\n        }\n        else if (i === endLine) {\n          if (endChar === 0) {\n            boxEnd = this.__charBounds[endLine][endChar].left;\n          }\n          else {\n            var charSpacing = this._getWidthOfCharSpacing();\n            boxEnd = this.__charBounds[endLine][endChar - 1].left\n              + this.__charBounds[endLine][endChar - 1].width - charSpacing;\n          }\n        }\n        realLineHeight = lineHeight;\n        if (this.lineHeight < 1 || (i === endLine && this.lineHeight > 1)) {\n          lineHeight /= this.lineHeight;\n        }\n        var drawStart = boundaries.left + lineOffset + boxStart,\n            drawWidth = boxEnd - boxStart,\n            drawHeight = lineHeight, extraTop = 0;\n        if (this.inCompositionMode) {\n          ctx.fillStyle = this.compositionColor || 'black';\n          drawHeight = 1;\n          extraTop = lineHeight;\n        }\n        else {\n          ctx.fillStyle = this.selectionColor;\n        }\n        if (this.direction === 'rtl') {\n          drawStart = this.width - drawStart - drawWidth;\n        }\n        ctx.fillRect(\n          drawStart,\n          boundaries.top + boundaries.topOffset + extraTop,\n          drawWidth,\n          drawHeight);\n        boundaries.topOffset += realLineHeight;\n      }\n    },\n\n    /**\n     * High level function to know the height of the cursor.\n     * the currentChar is the one that precedes the cursor\n     * Returns fontSize of char at the current cursor\n     * Unused from the library, is for the end user\n     * @return {Number} Character font size\n     */\n    getCurrentCharFontSize: function() {\n      var cp = this._getCurrentCharIndex();\n      return this.getValueOfPropertyAt(cp.l, cp.c, 'fontSize');\n    },\n\n    /**\n     * High level function to know the color of the cursor.\n     * the currentChar is the one that precedes the cursor\n     * Returns color (fill) of char at the current cursor\n     * if the text object has a pattern or gradient for filler, it will return that.\n     * Unused by the library, is for the end user\n     * @return {String | fabric.Gradient | fabric.Pattern} Character color (fill)\n     */\n    getCurrentCharColor: function() {\n      var cp = this._getCurrentCharIndex();\n      return this.getValueOfPropertyAt(cp.l, cp.c, 'fill');\n    },\n\n    /**\n     * Returns the cursor position for the getCurrent.. functions\n     * @private\n     */\n    _getCurrentCharIndex: function() {\n      var cursorPosition = this.get2DCursorLocation(this.selectionStart, true),\n          charIndex = cursorPosition.charIndex > 0 ? cursorPosition.charIndex - 1 : 0;\n      return { l: cursorPosition.lineIndex, c: charIndex };\n    }\n  });\n\n  /**\n   * Returns fabric.IText instance from an object representation\n   * @static\n   * @memberOf fabric.IText\n   * @param {Object} object Object to create an instance from\n   * @param {function} [callback] invoked with new instance as argument\n   */\n  fabric.IText.fromObject = function(object, callback) {\n    var styles = fabric.util.stylesFromArray(object.styles, object.text);\n    //copy object to prevent mutation\n    var objCopy = Object.assign({}, object, { styles: styles });\n    delete objCopy.path;\n    parseDecoration(objCopy);\n    if (objCopy.styles) {\n      for (var i in objCopy.styles) {\n        for (var j in objCopy.styles[i]) {\n          parseDecoration(objCopy.styles[i][j]);\n        }\n      }\n    }\n    fabric.Object._fromObject('IText', objCopy, function(textInstance) {\n      if (object.path) {\n        fabric.Object._fromObject('Path', object.path, function(pathInstance) {\n          textInstance.set('path', pathInstance);\n          callback(textInstance);\n        }, 'path');\n      }\n      else {\n        callback(textInstance);\n      }\n    }, 'text');\n  };\n})();\n\n\n(function() {\n\n  var clone = fabric.util.object.clone;\n\n  fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n    /**\n     * Initializes all the interactive behavior of IText\n     */\n    initBehavior: function() {\n      this.initAddedHandler();\n      this.initRemovedHandler();\n      this.initCursorSelectionHandlers();\n      this.initDoubleClickSimulation();\n      this.mouseMoveHandler = this.mouseMoveHandler.bind(this);\n    },\n\n    onDeselect: function() {\n      this.isEditing && this.exitEditing();\n      this.selected = false;\n    },\n\n    /**\n     * Initializes \"added\" event handler\n     */\n    initAddedHandler: function() {\n      var _this = this;\n      this.on('added', function() {\n        var canvas = _this.canvas;\n        if (canvas) {\n          if (!canvas._hasITextHandlers) {\n            canvas._hasITextHandlers = true;\n            _this._initCanvasHandlers(canvas);\n          }\n          canvas._iTextInstances = canvas._iTextInstances || [];\n          canvas._iTextInstances.push(_this);\n        }\n      });\n    },\n\n    initRemovedHandler: function() {\n      var _this = this;\n      this.on('removed', function() {\n        var canvas = _this.canvas;\n        if (canvas) {\n          canvas._iTextInstances = canvas._iTextInstances || [];\n          fabric.util.removeFromArray(canvas._iTextInstances, _this);\n          if (canvas._iTextInstances.length === 0) {\n            canvas._hasITextHandlers = false;\n            _this._removeCanvasHandlers(canvas);\n          }\n        }\n      });\n    },\n\n    /**\n     * register canvas event to manage exiting on other instances\n     * @private\n     */\n    _initCanvasHandlers: function(canvas) {\n      canvas._mouseUpITextHandler = function() {\n        if (canvas._iTextInstances) {\n          canvas._iTextInstances.forEach(function(obj) {\n            obj.__isMousedown = false;\n          });\n        }\n      };\n      canvas.on('mouse:up', canvas._mouseUpITextHandler);\n    },\n\n    /**\n     * remove canvas event to manage exiting on other instances\n     * @private\n     */\n    _removeCanvasHandlers: function(canvas) {\n      canvas.off('mouse:up', canvas._mouseUpITextHandler);\n    },\n\n    /**\n     * @private\n     */\n    _tick: function() {\n      this._currentTickState = this._animateCursor(this, 1, this.cursorDuration, '_onTickComplete');\n    },\n\n    /**\n     * @private\n     */\n    _animateCursor: function(obj, targetOpacity, duration, completeMethod) {\n\n      var tickState;\n\n      tickState = {\n        isAborted: false,\n        abort: function() {\n          this.isAborted = true;\n        },\n      };\n\n      obj.animate('_currentCursorOpacity', targetOpacity, {\n        duration: duration,\n        onComplete: function() {\n          if (!tickState.isAborted) {\n            obj[completeMethod]();\n          }\n        },\n        onChange: function() {\n          // we do not want to animate a selection, only cursor\n          if (obj.canvas && obj.selectionStart === obj.selectionEnd) {\n            obj.renderCursorOrSelection();\n          }\n        },\n        abort: function() {\n          return tickState.isAborted;\n        }\n      });\n      return tickState;\n    },\n\n    /**\n     * @private\n     */\n    _onTickComplete: function() {\n\n      var _this = this;\n\n      if (this._cursorTimeout1) {\n        clearTimeout(this._cursorTimeout1);\n      }\n      this._cursorTimeout1 = setTimeout(function() {\n        _this._currentTickCompleteState = _this._animateCursor(_this, 0, this.cursorDuration / 2, '_tick');\n      }, 100);\n    },\n\n    /**\n     * Initializes delayed cursor\n     */\n    initDelayedCursor: function(restart) {\n      var _this = this,\n          delay = restart ? 0 : this.cursorDelay;\n\n      this.abortCursorAnimation();\n      this._currentCursorOpacity = 1;\n      this._cursorTimeout2 = setTimeout(function() {\n        _this._tick();\n      }, delay);\n    },\n\n    /**\n     * Aborts cursor animation and clears all timeouts\n     */\n    abortCursorAnimation: function() {\n      var shouldClear = this._currentTickState || this._currentTickCompleteState,\n          canvas = this.canvas;\n      this._currentTickState && this._currentTickState.abort();\n      this._currentTickCompleteState && this._currentTickCompleteState.abort();\n\n      clearTimeout(this._cursorTimeout1);\n      clearTimeout(this._cursorTimeout2);\n\n      this._currentCursorOpacity = 0;\n      // to clear just itext area we need to transform the context\n      // it may not be worth it\n      if (shouldClear && canvas) {\n        canvas.clearContext(canvas.contextTop || canvas.contextContainer);\n      }\n\n    },\n\n    /**\n     * Selects entire text\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    selectAll: function() {\n      this.selectionStart = 0;\n      this.selectionEnd = this._text.length;\n      this._fireSelectionChanged();\n      this._updateTextarea();\n      return this;\n    },\n\n    /**\n     * Returns selected text\n     * @return {String}\n     */\n    getSelectedText: function() {\n      return this._text.slice(this.selectionStart, this.selectionEnd).join('');\n    },\n\n    /**\n     * Find new selection index representing start of current word according to current selection index\n     * @param {Number} startFrom Current selection index\n     * @return {Number} New selection index\n     */\n    findWordBoundaryLeft: function(startFrom) {\n      var offset = 0, index = startFrom - 1;\n\n      // remove space before cursor first\n      if (this._reSpace.test(this._text[index])) {\n        while (this._reSpace.test(this._text[index])) {\n          offset++;\n          index--;\n        }\n      }\n      while (/\\S/.test(this._text[index]) && index > -1) {\n        offset++;\n        index--;\n      }\n\n      return startFrom - offset;\n    },\n\n    /**\n     * Find new selection index representing end of current word according to current selection index\n     * @param {Number} startFrom Current selection index\n     * @return {Number} New selection index\n     */\n    findWordBoundaryRight: function(startFrom) {\n      var offset = 0, index = startFrom;\n\n      // remove space after cursor first\n      if (this._reSpace.test(this._text[index])) {\n        while (this._reSpace.test(this._text[index])) {\n          offset++;\n          index++;\n        }\n      }\n      while (/\\S/.test(this._text[index]) && index < this._text.length) {\n        offset++;\n        index++;\n      }\n\n      return startFrom + offset;\n    },\n\n    /**\n     * Find new selection index representing start of current line according to current selection index\n     * @param {Number} startFrom Current selection index\n     * @return {Number} New selection index\n     */\n    findLineBoundaryLeft: function(startFrom) {\n      var offset = 0, index = startFrom - 1;\n\n      while (!/\\n/.test(this._text[index]) && index > -1) {\n        offset++;\n        index--;\n      }\n\n      return startFrom - offset;\n    },\n\n    /**\n     * Find new selection index representing end of current line according to current selection index\n     * @param {Number} startFrom Current selection index\n     * @return {Number} New selection index\n     */\n    findLineBoundaryRight: function(startFrom) {\n      var offset = 0, index = startFrom;\n\n      while (!/\\n/.test(this._text[index]) && index < this._text.length) {\n        offset++;\n        index++;\n      }\n\n      return startFrom + offset;\n    },\n\n    /**\n     * Finds index corresponding to beginning or end of a word\n     * @param {Number} selectionStart Index of a character\n     * @param {Number} direction 1 or -1\n     * @return {Number} Index of the beginning or end of a word\n     */\n    searchWordBoundary: function(selectionStart, direction) {\n      var text = this._text,\n          index     = this._reSpace.test(text[selectionStart]) ? selectionStart - 1 : selectionStart,\n          _char     = text[index],\n          // wrong\n          reNonWord = fabric.reNonWord;\n\n      while (!reNonWord.test(_char) && index > 0 && index < text.length) {\n        index += direction;\n        _char = text[index];\n      }\n      if (reNonWord.test(_char)) {\n        index += direction === 1 ? 0 : 1;\n      }\n      return index;\n    },\n\n    /**\n     * Selects a word based on the index\n     * @param {Number} selectionStart Index of a character\n     */\n    selectWord: function(selectionStart) {\n      selectionStart = selectionStart || this.selectionStart;\n      var newSelectionStart = this.searchWordBoundary(selectionStart, -1), /* search backwards */\n          newSelectionEnd = this.searchWordBoundary(selectionStart, 1); /* search forward */\n\n      this.selectionStart = newSelectionStart;\n      this.selectionEnd = newSelectionEnd;\n      this._fireSelectionChanged();\n      this._updateTextarea();\n      this.renderCursorOrSelection();\n    },\n\n    /**\n     * Selects a line based on the index\n     * @param {Number} selectionStart Index of a character\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    selectLine: function(selectionStart) {\n      selectionStart = selectionStart || this.selectionStart;\n      var newSelectionStart = this.findLineBoundaryLeft(selectionStart),\n          newSelectionEnd = this.findLineBoundaryRight(selectionStart);\n\n      this.selectionStart = newSelectionStart;\n      this.selectionEnd = newSelectionEnd;\n      this._fireSelectionChanged();\n      this._updateTextarea();\n      return this;\n    },\n\n    /**\n     * Enters editing state\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    enterEditing: function(e) {\n      if (this.isEditing || !this.editable) {\n        return;\n      }\n\n      if (this.canvas) {\n        this.canvas.calcOffset();\n        this.exitEditingOnOthers(this.canvas);\n      }\n\n      this.isEditing = true;\n\n      this.initHiddenTextarea(e);\n      this.hiddenTextarea.focus();\n      this.hiddenTextarea.value = this.text;\n      this._updateTextarea();\n      this._saveEditingProps();\n      this._setEditingProps();\n      this._textBeforeEdit = this.text;\n\n      this._tick();\n      this.fire('editing:entered');\n      this._fireSelectionChanged();\n      if (!this.canvas) {\n        return this;\n      }\n      this.canvas.fire('text:editing:entered', { target: this });\n      this.initMouseMoveHandler();\n      this.canvas.requestRenderAll();\n      return this;\n    },\n\n    exitEditingOnOthers: function(canvas) {\n      if (canvas._iTextInstances) {\n        canvas._iTextInstances.forEach(function(obj) {\n          obj.selected = false;\n          if (obj.isEditing) {\n            obj.exitEditing();\n          }\n        });\n      }\n    },\n\n    /**\n     * Initializes \"mousemove\" event handler\n     */\n    initMouseMoveHandler: function() {\n      this.canvas.on('mouse:move', this.mouseMoveHandler);\n    },\n\n    /**\n     * @private\n     */\n    mouseMoveHandler: function(options) {\n      if (!this.__isMousedown || !this.isEditing) {\n        return;\n      }\n\n      // regain focus\n      document.activeElement !== this.hiddenTextarea && this.hiddenTextarea.focus();\n\n      var newSelectionStart = this.getSelectionStartFromPointer(options.e),\n          currentStart = this.selectionStart,\n          currentEnd = this.selectionEnd;\n      if (\n        (newSelectionStart !== this.__selectionStartOnMouseDown || currentStart === currentEnd)\n        &&\n        (currentStart === newSelectionStart || currentEnd === newSelectionStart)\n      ) {\n        return;\n      }\n      if (newSelectionStart > this.__selectionStartOnMouseDown) {\n        this.selectionStart = this.__selectionStartOnMouseDown;\n        this.selectionEnd = newSelectionStart;\n      }\n      else {\n        this.selectionStart = newSelectionStart;\n        this.selectionEnd = this.__selectionStartOnMouseDown;\n      }\n      if (this.selectionStart !== currentStart || this.selectionEnd !== currentEnd) {\n        this.restartCursorIfNeeded();\n        this._fireSelectionChanged();\n        this._updateTextarea();\n        this.renderCursorOrSelection();\n      }\n    },\n\n    /**\n     * @private\n     */\n    _setEditingProps: function() {\n      this.hoverCursor = 'text';\n\n      if (this.canvas) {\n        this.canvas.defaultCursor = this.canvas.moveCursor = 'text';\n      }\n\n      this.borderColor = this.editingBorderColor;\n      this.hasControls = this.selectable = false;\n      this.lockMovementX = this.lockMovementY = true;\n    },\n\n    /**\n     * convert from textarea to grapheme indexes\n     */\n    fromStringToGraphemeSelection: function(start, end, text) {\n      var smallerTextStart = text.slice(0, start),\n          graphemeStart = fabric.util.string.graphemeSplit(smallerTextStart).length;\n      if (start === end) {\n        return { selectionStart: graphemeStart, selectionEnd: graphemeStart };\n      }\n      var smallerTextEnd = text.slice(start, end),\n          graphemeEnd = fabric.util.string.graphemeSplit(smallerTextEnd).length;\n      return { selectionStart: graphemeStart, selectionEnd: graphemeStart + graphemeEnd };\n    },\n\n    /**\n     * convert from fabric to textarea values\n     */\n    fromGraphemeToStringSelection: function(start, end, _text) {\n      var smallerTextStart = _text.slice(0, start),\n          graphemeStart = smallerTextStart.join('').length;\n      if (start === end) {\n        return { selectionStart: graphemeStart, selectionEnd: graphemeStart };\n      }\n      var smallerTextEnd = _text.slice(start, end),\n          graphemeEnd = smallerTextEnd.join('').length;\n      return { selectionStart: graphemeStart, selectionEnd: graphemeStart + graphemeEnd };\n    },\n\n    /**\n     * @private\n     */\n    _updateTextarea: function() {\n      this.cursorOffsetCache = { };\n      if (!this.hiddenTextarea) {\n        return;\n      }\n      if (!this.inCompositionMode) {\n        var newSelection = this.fromGraphemeToStringSelection(this.selectionStart, this.selectionEnd, this._text);\n        this.hiddenTextarea.selectionStart = newSelection.selectionStart;\n        this.hiddenTextarea.selectionEnd = newSelection.selectionEnd;\n      }\n      this.updateTextareaPosition();\n    },\n\n    /**\n     * @private\n     */\n    updateFromTextArea: function() {\n      if (!this.hiddenTextarea) {\n        return;\n      }\n      this.cursorOffsetCache = { };\n      this.text = this.hiddenTextarea.value;\n      if (this._shouldClearDimensionCache()) {\n        this.initDimensions();\n        this.setCoords();\n      }\n      var newSelection = this.fromStringToGraphemeSelection(\n        this.hiddenTextarea.selectionStart, this.hiddenTextarea.selectionEnd, this.hiddenTextarea.value);\n      this.selectionEnd = this.selectionStart = newSelection.selectionEnd;\n      if (!this.inCompositionMode) {\n        this.selectionStart = newSelection.selectionStart;\n      }\n      this.updateTextareaPosition();\n    },\n\n    /**\n     * @private\n     */\n    updateTextareaPosition: function() {\n      if (this.selectionStart === this.selectionEnd) {\n        var style = this._calcTextareaPosition();\n        this.hiddenTextarea.style.left = style.left;\n        this.hiddenTextarea.style.top = style.top;\n      }\n    },\n\n    /**\n     * @private\n     * @return {Object} style contains style for hiddenTextarea\n     */\n    _calcTextareaPosition: function() {\n      if (!this.canvas) {\n        return { x: 1, y: 1 };\n      }\n      var desiredPosition = this.inCompositionMode ? this.compositionStart : this.selectionStart,\n          boundaries = this._getCursorBoundaries(desiredPosition),\n          cursorLocation = this.get2DCursorLocation(desiredPosition),\n          lineIndex = cursorLocation.lineIndex,\n          charIndex = cursorLocation.charIndex,\n          charHeight = this.getValueOfPropertyAt(lineIndex, charIndex, 'fontSize') * this.lineHeight,\n          leftOffset = boundaries.leftOffset,\n          m = this.calcTransformMatrix(),\n          p = {\n            x: boundaries.left + leftOffset,\n            y: boundaries.top + boundaries.topOffset + charHeight\n          },\n          retinaScaling = this.canvas.getRetinaScaling(),\n          upperCanvas = this.canvas.upperCanvasEl,\n          upperCanvasWidth = upperCanvas.width / retinaScaling,\n          upperCanvasHeight = upperCanvas.height / retinaScaling,\n          maxWidth = upperCanvasWidth - charHeight,\n          maxHeight = upperCanvasHeight - charHeight,\n          scaleX = upperCanvas.clientWidth / upperCanvasWidth,\n          scaleY = upperCanvas.clientHeight / upperCanvasHeight;\n\n      p = fabric.util.transformPoint(p, m);\n      p = fabric.util.transformPoint(p, this.canvas.viewportTransform);\n      p.x *= scaleX;\n      p.y *= scaleY;\n      if (p.x < 0) {\n        p.x = 0;\n      }\n      if (p.x > maxWidth) {\n        p.x = maxWidth;\n      }\n      if (p.y < 0) {\n        p.y = 0;\n      }\n      if (p.y > maxHeight) {\n        p.y = maxHeight;\n      }\n\n      // add canvas offset on document\n      p.x += this.canvas._offset.left;\n      p.y += this.canvas._offset.top;\n\n      return { left: p.x + 'px', top: p.y + 'px', fontSize: charHeight + 'px', charHeight: charHeight };\n    },\n\n    /**\n     * @private\n     */\n    _saveEditingProps: function() {\n      this._savedProps = {\n        hasControls: this.hasControls,\n        borderColor: this.borderColor,\n        lockMovementX: this.lockMovementX,\n        lockMovementY: this.lockMovementY,\n        hoverCursor: this.hoverCursor,\n        selectable: this.selectable,\n        defaultCursor: this.canvas && this.canvas.defaultCursor,\n        moveCursor: this.canvas && this.canvas.moveCursor\n      };\n    },\n\n    /**\n     * @private\n     */\n    _restoreEditingProps: function() {\n      if (!this._savedProps) {\n        return;\n      }\n\n      this.hoverCursor = this._savedProps.hoverCursor;\n      this.hasControls = this._savedProps.hasControls;\n      this.borderColor = this._savedProps.borderColor;\n      this.selectable = this._savedProps.selectable;\n      this.lockMovementX = this._savedProps.lockMovementX;\n      this.lockMovementY = this._savedProps.lockMovementY;\n\n      if (this.canvas) {\n        this.canvas.defaultCursor = this._savedProps.defaultCursor;\n        this.canvas.moveCursor = this._savedProps.moveCursor;\n      }\n    },\n\n    /**\n     * Exits from editing state\n     * @return {fabric.IText} thisArg\n     * @chainable\n     */\n    exitEditing: function() {\n      var isTextChanged = (this._textBeforeEdit !== this.text);\n      var hiddenTextarea = this.hiddenTextarea;\n      this.selected = false;\n      this.isEditing = false;\n\n      this.selectionEnd = this.selectionStart;\n\n      if (hiddenTextarea) {\n        hiddenTextarea.blur && hiddenTextarea.blur();\n        hiddenTextarea.parentNode && hiddenTextarea.parentNode.removeChild(hiddenTextarea);\n      }\n      this.hiddenTextarea = null;\n      this.abortCursorAnimation();\n      this._restoreEditingProps();\n      this._currentCursorOpacity = 0;\n      if (this._shouldClearDimensionCache()) {\n        this.initDimensions();\n        this.setCoords();\n      }\n      this.fire('editing:exited');\n      isTextChanged && this.fire('modified');\n      if (this.canvas) {\n        this.canvas.off('mouse:move', this.mouseMoveHandler);\n        this.canvas.fire('text:editing:exited', { target: this });\n        isTextChanged && this.canvas.fire('object:modified', { target: this });\n      }\n      return this;\n    },\n\n    /**\n     * @private\n     */\n    _removeExtraneousStyles: function() {\n      for (var prop in this.styles) {\n        if (!this._textLines[prop]) {\n          delete this.styles[prop];\n        }\n      }\n    },\n\n    /**\n     * remove and reflow a style block from start to end.\n     * @param {Number} start linear start position for removal (included in removal)\n     * @param {Number} end linear end position for removal ( excluded from removal )\n     */\n    removeStyleFromTo: function(start, end) {\n      var cursorStart = this.get2DCursorLocation(start, true),\n          cursorEnd = this.get2DCursorLocation(end, true),\n          lineStart = cursorStart.lineIndex,\n          charStart = cursorStart.charIndex,\n          lineEnd = cursorEnd.lineIndex,\n          charEnd = cursorEnd.charIndex,\n          i, styleObj;\n      if (lineStart !== lineEnd) {\n        // step1 remove the trailing of lineStart\n        if (this.styles[lineStart]) {\n          for (i = charStart; i < this._unwrappedTextLines[lineStart].length; i++) {\n            delete this.styles[lineStart][i];\n          }\n        }\n        // step2 move the trailing of lineEnd to lineStart if needed\n        if (this.styles[lineEnd]) {\n          for (i = charEnd; i < this._unwrappedTextLines[lineEnd].length; i++) {\n            styleObj = this.styles[lineEnd][i];\n            if (styleObj) {\n              this.styles[lineStart] || (this.styles[lineStart] = { });\n              this.styles[lineStart][charStart + i - charEnd] = styleObj;\n            }\n          }\n        }\n        // step3 detects lines will be completely removed.\n        for (i = lineStart + 1; i <= lineEnd; i++) {\n          delete this.styles[i];\n        }\n        // step4 shift remaining lines.\n        this.shiftLineStyles(lineEnd, lineStart - lineEnd);\n      }\n      else {\n        // remove and shift left on the same line\n        if (this.styles[lineStart]) {\n          styleObj = this.styles[lineStart];\n          var diff = charEnd - charStart, numericChar, _char;\n          for (i = charStart; i < charEnd; i++) {\n            delete styleObj[i];\n          }\n          for (_char in this.styles[lineStart]) {\n            numericChar = parseInt(_char, 10);\n            if (numericChar >= charEnd) {\n              styleObj[numericChar - diff] = styleObj[_char];\n              delete styleObj[_char];\n            }\n          }\n        }\n      }\n    },\n\n    /**\n     * Shifts line styles up or down\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} offset Can any number?\n     */\n    shiftLineStyles: function(lineIndex, offset) {\n      // shift all line styles by offset upward or downward\n      // do not clone deep. we need new array, not new style objects\n      var clonedStyles = clone(this.styles);\n      for (var line in this.styles) {\n        var numericLine = parseInt(line, 10);\n        if (numericLine > lineIndex) {\n          this.styles[numericLine + offset] = clonedStyles[numericLine];\n          if (!clonedStyles[numericLine - offset]) {\n            delete this.styles[numericLine];\n          }\n        }\n      }\n    },\n\n    restartCursorIfNeeded: function() {\n      if (!this._currentTickState || this._currentTickState.isAborted\n        || !this._currentTickCompleteState || this._currentTickCompleteState.isAborted\n      ) {\n        this.initDelayedCursor();\n      }\n    },\n\n    /**\n     * Handle insertion of more consecutive style lines for when one or more\n     * newlines gets added to the text. Since current style needs to be shifted\n     * first we shift the current style of the number lines needed, then we add\n     * new lines from the last to the first.\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} charIndex Index of a char\n     * @param {Number} qty number of lines to add\n     * @param {Array} copiedStyle Array of objects styles\n     */\n    insertNewlineStyleObject: function(lineIndex, charIndex, qty, copiedStyle) {\n      var currentCharStyle,\n          newLineStyles = {},\n          someStyleIsCarryingOver = false,\n          originalLineLength = this._unwrappedTextLines[lineIndex].length,\n          isEndOfLine = originalLineLength === charIndex;\n\n      qty || (qty = 1);\n      this.shiftLineStyles(lineIndex, qty);\n      if (this.styles[lineIndex]) {\n        currentCharStyle = this.styles[lineIndex][charIndex === 0 ? charIndex : charIndex - 1];\n      }\n      // we clone styles of all chars\n      // after cursor onto the current line\n      for (var index in this.styles[lineIndex]) {\n        var numIndex = parseInt(index, 10);\n        if (numIndex >= charIndex) {\n          someStyleIsCarryingOver = true;\n          newLineStyles[numIndex - charIndex] = this.styles[lineIndex][index];\n          // remove lines from the previous line since they're on a new line now\n          if (!(isEndOfLine && charIndex === 0)) {\n            delete this.styles[lineIndex][index];\n          }\n        }\n      }\n      var styleCarriedOver = false;\n      if (someStyleIsCarryingOver && !isEndOfLine) {\n        // if is end of line, the extra style we copied\n        // is probably not something we want\n        this.styles[lineIndex + qty] = newLineStyles;\n        styleCarriedOver = true;\n      }\n      if (styleCarriedOver || originalLineLength > charIndex) {\n        // skip the last line of since we already prepared it\n        // or contains text without style that we don't want to style\n        // just because it changed lines\n        qty--;\n      }\n      // for the all the lines or all the other lines\n      // we clone current char style onto the next (otherwise empty) line\n      while (qty > 0) {\n        if (copiedStyle && copiedStyle[qty - 1]) {\n          this.styles[lineIndex + qty] = { 0: clone(copiedStyle[qty - 1]) };\n        }\n        else if (currentCharStyle) {\n          this.styles[lineIndex + qty] = { 0: clone(currentCharStyle) };\n        }\n        else {\n          delete this.styles[lineIndex + qty];\n        }\n        qty--;\n      }\n      this._forceClearCache = true;\n    },\n\n    /**\n     * Inserts style object for a given line/char index\n     * @param {Number} lineIndex Index of a line\n     * @param {Number} charIndex Index of a char\n     * @param {Number} quantity number Style object to insert, if given\n     * @param {Array} copiedStyle array of style objects\n     */\n    insertCharStyleObject: function(lineIndex, charIndex, quantity, copiedStyle) {\n      if (!this.styles) {\n        this.styles = {};\n      }\n      var currentLineStyles       = this.styles[lineIndex],\n          currentLineStylesCloned = currentLineStyles ? clone(currentLineStyles) : {};\n\n      quantity || (quantity = 1);\n      // shift all char styles by quantity forward\n      // 0,1,2,3 -> (charIndex=2) -> 0,1,3,4 -> (insert 2) -> 0,1,2,3,4\n      for (var index in currentLineStylesCloned) {\n        var numericIndex = parseInt(index, 10);\n        if (numericIndex >= charIndex) {\n          currentLineStyles[numericIndex + quantity] = currentLineStylesCloned[numericIndex];\n          // only delete the style if there was nothing moved there\n          if (!currentLineStylesCloned[numericIndex - quantity]) {\n            delete currentLineStyles[numericIndex];\n          }\n        }\n      }\n      this._forceClearCache = true;\n      if (copiedStyle) {\n        while (quantity--) {\n          if (!Object.keys(copiedStyle[quantity]).length) {\n            continue;\n          }\n          if (!this.styles[lineIndex]) {\n            this.styles[lineIndex] = {};\n          }\n          this.styles[lineIndex][charIndex + quantity] = clone(copiedStyle[quantity]);\n        }\n        return;\n      }\n      if (!currentLineStyles) {\n        return;\n      }\n      var newStyle = currentLineStyles[charIndex ? charIndex - 1 : 1];\n      while (newStyle && quantity--) {\n        this.styles[lineIndex][charIndex + quantity] = clone(newStyle);\n      }\n    },\n\n    /**\n     * Inserts style object(s)\n     * @param {Array} insertedText Characters at the location where style is inserted\n     * @param {Number} start cursor index for inserting style\n     * @param {Array} [copiedStyle] array of style objects to insert.\n     */\n    insertNewStyleBlock: function(insertedText, start, copiedStyle) {\n      var cursorLoc = this.get2DCursorLocation(start, true),\n          addedLines = [0], linesLength = 0;\n      // get an array of how many char per lines are being added.\n      for (var i = 0; i < insertedText.length; i++) {\n        if (insertedText[i] === '\\n') {\n          linesLength++;\n          addedLines[linesLength] = 0;\n        }\n        else {\n          addedLines[linesLength]++;\n        }\n      }\n      // for the first line copy the style from the current char position.\n      if (addedLines[0] > 0) {\n        this.insertCharStyleObject(cursorLoc.lineIndex, cursorLoc.charIndex, addedLines[0], copiedStyle);\n        copiedStyle = copiedStyle && copiedStyle.slice(addedLines[0] + 1);\n      }\n      linesLength && this.insertNewlineStyleObject(\n        cursorLoc.lineIndex, cursorLoc.charIndex + addedLines[0], linesLength);\n      for (var i = 1; i < linesLength; i++) {\n        if (addedLines[i] > 0) {\n          this.insertCharStyleObject(cursorLoc.lineIndex + i, 0, addedLines[i], copiedStyle);\n        }\n        else if (copiedStyle) {\n          // this test is required in order to close #6841\n          // when a pasted buffer begins with a newline then\n          // this.styles[cursorLoc.lineIndex + i] and copiedStyle[0]\n          // may be undefined for some reason\n          if (this.styles[cursorLoc.lineIndex + i] && copiedStyle[0]) {\n            this.styles[cursorLoc.lineIndex + i][0] = copiedStyle[0];\n          }\n        }\n        copiedStyle = copiedStyle && copiedStyle.slice(addedLines[i] + 1);\n      }\n      // we use i outside the loop to get it like linesLength\n      if (addedLines[i] > 0) {\n        this.insertCharStyleObject(cursorLoc.lineIndex + i, 0, addedLines[i], copiedStyle);\n      }\n    },\n\n    /**\n     * Set the selectionStart and selectionEnd according to the new position of cursor\n     * mimic the key - mouse navigation when shift is pressed.\n     */\n    setSelectionStartEndWithShift: function(start, end, newSelection) {\n      if (newSelection <= start) {\n        if (end === start) {\n          this._selectionDirection = 'left';\n        }\n        else if (this._selectionDirection === 'right') {\n          this._selectionDirection = 'left';\n          this.selectionEnd = start;\n        }\n        this.selectionStart = newSelection;\n      }\n      else if (newSelection > start && newSelection < end) {\n        if (this._selectionDirection === 'right') {\n          this.selectionEnd = newSelection;\n        }\n        else {\n          this.selectionStart = newSelection;\n        }\n      }\n      else {\n        // newSelection is > selection start and end\n        if (end === start) {\n          this._selectionDirection = 'right';\n        }\n        else if (this._selectionDirection === 'left') {\n          this._selectionDirection = 'right';\n          this.selectionStart = end;\n        }\n        this.selectionEnd = newSelection;\n      }\n    },\n\n    setSelectionInBoundaries: function() {\n      var length = this.text.length;\n      if (this.selectionStart > length) {\n        this.selectionStart = length;\n      }\n      else if (this.selectionStart < 0) {\n        this.selectionStart = 0;\n      }\n      if (this.selectionEnd > length) {\n        this.selectionEnd = length;\n      }\n      else if (this.selectionEnd < 0) {\n        this.selectionEnd = 0;\n      }\n    }\n  });\n})();\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n  /**\n   * Initializes \"dbclick\" event handler\n   */\n  initDoubleClickSimulation: function() {\n\n    // for double click\n    this.__lastClickTime = +new Date();\n\n    // for triple click\n    this.__lastLastClickTime = +new Date();\n\n    this.__lastPointer = { };\n\n    this.on('mousedown', this.onMouseDown);\n  },\n\n  /**\n   * Default event handler to simulate triple click\n   * @private\n   */\n  onMouseDown: function(options) {\n    if (!this.canvas) {\n      return;\n    }\n    this.__newClickTime = +new Date();\n    var newPointer = options.pointer;\n    if (this.isTripleClick(newPointer)) {\n      this.fire('tripleclick', options);\n      this._stopEvent(options.e);\n    }\n    this.__lastLastClickTime = this.__lastClickTime;\n    this.__lastClickTime = this.__newClickTime;\n    this.__lastPointer = newPointer;\n    this.__lastIsEditing = this.isEditing;\n    this.__lastSelected = this.selected;\n  },\n\n  isTripleClick: function(newPointer) {\n    return this.__newClickTime - this.__lastClickTime < 500 &&\n        this.__lastClickTime - this.__lastLastClickTime < 500 &&\n        this.__lastPointer.x === newPointer.x &&\n        this.__lastPointer.y === newPointer.y;\n  },\n\n  /**\n   * @private\n   */\n  _stopEvent: function(e) {\n    e.preventDefault && e.preventDefault();\n    e.stopPropagation && e.stopPropagation();\n  },\n\n  /**\n   * Initializes event handlers related to cursor or selection\n   */\n  initCursorSelectionHandlers: function() {\n    this.initMousedownHandler();\n    this.initMouseupHandler();\n    this.initClicks();\n  },\n\n  /**\n   * Default handler for double click, select a word\n   */\n  doubleClickHandler: function(options) {\n    if (!this.isEditing) {\n      return;\n    }\n    this.selectWord(this.getSelectionStartFromPointer(options.e));\n  },\n\n  /**\n   * Default handler for triple click, select a line\n   */\n  tripleClickHandler: function(options) {\n    if (!this.isEditing) {\n      return;\n    }\n    this.selectLine(this.getSelectionStartFromPointer(options.e));\n  },\n\n  /**\n   * Initializes double and triple click event handlers\n   */\n  initClicks: function() {\n    this.on('mousedblclick', this.doubleClickHandler);\n    this.on('tripleclick', this.tripleClickHandler);\n  },\n\n  /**\n   * Default event handler for the basic functionalities needed on _mouseDown\n   * can be overridden to do something different.\n   * Scope of this implementation is: find the click position, set selectionStart\n   * find selectionEnd, initialize the drawing of either cursor or selection area\n   * initializing a mousedDown on a text area will cancel fabricjs knowledge of\n   * current compositionMode. It will be set to false.\n   */\n  _mouseDownHandler: function(options) {\n    if (!this.canvas || !this.editable || (options.e.button && options.e.button !== 1)) {\n      return;\n    }\n\n    this.__isMousedown = true;\n\n    if (this.selected) {\n      this.inCompositionMode = false;\n      this.setCursorByClick(options.e);\n    }\n\n    if (this.isEditing) {\n      this.__selectionStartOnMouseDown = this.selectionStart;\n      if (this.selectionStart === this.selectionEnd) {\n        this.abortCursorAnimation();\n      }\n      this.renderCursorOrSelection();\n    }\n  },\n\n  /**\n   * Default event handler for the basic functionalities needed on mousedown:before\n   * can be overridden to do something different.\n   * Scope of this implementation is: verify the object is already selected when mousing down\n   */\n  _mouseDownHandlerBefore: function(options) {\n    if (!this.canvas || !this.editable || (options.e.button && options.e.button !== 1)) {\n      return;\n    }\n    // we want to avoid that an object that was selected and then becomes unselectable,\n    // may trigger editing mode in some way.\n    this.selected = this === this.canvas._activeObject;\n  },\n\n  /**\n   * Initializes \"mousedown\" event handler\n   */\n  initMousedownHandler: function() {\n    this.on('mousedown', this._mouseDownHandler);\n    this.on('mousedown:before', this._mouseDownHandlerBefore);\n  },\n\n  /**\n   * Initializes \"mouseup\" event handler\n   */\n  initMouseupHandler: function() {\n    this.on('mouseup', this.mouseUpHandler);\n  },\n\n  /**\n   * standard handler for mouse up, overridable\n   * @private\n   */\n  mouseUpHandler: function(options) {\n    this.__isMousedown = false;\n    if (!this.editable || this.group ||\n      (options.transform && options.transform.actionPerformed) ||\n      (options.e.button && options.e.button !== 1)) {\n      return;\n    }\n\n    if (this.canvas) {\n      var currentActive = this.canvas._activeObject;\n      if (currentActive && currentActive !== this) {\n        // avoid running this logic when there is an active object\n        // this because is possible with shift click and fast clicks,\n        // to rapidly deselect and reselect this object and trigger an enterEdit\n        return;\n      }\n    }\n\n    if (this.__lastSelected && !this.__corner) {\n      this.selected = false;\n      this.__lastSelected = false;\n      this.enterEditing(options.e);\n      if (this.selectionStart === this.selectionEnd) {\n        this.initDelayedCursor(true);\n      }\n      else {\n        this.renderCursorOrSelection();\n      }\n    }\n    else {\n      this.selected = true;\n    }\n  },\n\n  /**\n   * Changes cursor location in a text depending on passed pointer (x/y) object\n   * @param {Event} e Event object\n   */\n  setCursorByClick: function(e) {\n    var newSelection = this.getSelectionStartFromPointer(e),\n        start = this.selectionStart, end = this.selectionEnd;\n    if (e.shiftKey) {\n      this.setSelectionStartEndWithShift(start, end, newSelection);\n    }\n    else {\n      this.selectionStart = newSelection;\n      this.selectionEnd = newSelection;\n    }\n    if (this.isEditing) {\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    }\n  },\n\n  /**\n   * Returns index of a character corresponding to where an object was clicked\n   * @param {Event} e Event object\n   * @return {Number} Index of a character\n   */\n  getSelectionStartFromPointer: function(e) {\n    var mouseOffset = this.getLocalPointer(e),\n        prevWidth = 0,\n        width = 0,\n        height = 0,\n        charIndex = 0,\n        lineIndex = 0,\n        lineLeftOffset,\n        line;\n    for (var i = 0, len = this._textLines.length; i < len; i++) {\n      if (height <= mouseOffset.y) {\n        height += this.getHeightOfLine(i) * this.scaleY;\n        lineIndex = i;\n        if (i > 0) {\n          charIndex += this._textLines[i - 1].length + this.missingNewlineOffset(i - 1);\n        }\n      }\n      else {\n        break;\n      }\n    }\n    lineLeftOffset = this._getLineLeftOffset(lineIndex);\n    width = lineLeftOffset * this.scaleX;\n    line = this._textLines[lineIndex];\n    // handling of RTL: in order to get things work correctly,\n    // we assume RTL writing is mirrored compared to LTR writing.\n    // so in position detection we mirror the X offset, and when is time\n    // of rendering it, we mirror it again.\n    if (this.direction === 'rtl') {\n      mouseOffset.x = this.width * this.scaleX - mouseOffset.x + width;\n    }\n    for (var j = 0, jlen = line.length; j < jlen; j++) {\n      prevWidth = width;\n      // i removed something about flipX here, check.\n      width += this.__charBounds[lineIndex][j].kernedWidth * this.scaleX;\n      if (width <= mouseOffset.x) {\n        charIndex++;\n      }\n      else {\n        break;\n      }\n    }\n    return this._getNewSelectionStartFromOffset(mouseOffset, prevWidth, width, charIndex, jlen);\n  },\n\n  /**\n   * @private\n   */\n  _getNewSelectionStartFromOffset: function(mouseOffset, prevWidth, width, index, jlen) {\n    // we need Math.abs because when width is after the last char, the offset is given as 1, while is 0\n    var distanceBtwLastCharAndCursor = mouseOffset.x - prevWidth,\n        distanceBtwNextCharAndCursor = width - mouseOffset.x,\n        offset = distanceBtwNextCharAndCursor > distanceBtwLastCharAndCursor ||\n          distanceBtwNextCharAndCursor < 0 ? 0 : 1,\n        newSelectionStart = index + offset;\n    // if object is horizontally flipped, mirror cursor location from the end\n    if (this.flipX) {\n      newSelectionStart = jlen - newSelectionStart;\n    }\n\n    if (newSelectionStart > this._text.length) {\n      newSelectionStart = this._text.length;\n    }\n\n    return newSelectionStart;\n  }\n});\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n  /**\n   * Initializes hidden textarea (needed to bring up keyboard in iOS)\n   */\n  initHiddenTextarea: function() {\n    this.hiddenTextarea = fabric.document.createElement('textarea');\n    this.hiddenTextarea.setAttribute('autocapitalize', 'off');\n    this.hiddenTextarea.setAttribute('autocorrect', 'off');\n    this.hiddenTextarea.setAttribute('autocomplete', 'off');\n    this.hiddenTextarea.setAttribute('spellcheck', 'false');\n    this.hiddenTextarea.setAttribute('data-fabric-hiddentextarea', '');\n    this.hiddenTextarea.setAttribute('wrap', 'off');\n    var style = this._calcTextareaPosition();\n    // line-height: 1px; was removed from the style to fix this:\n    // https://bugs.chromium.org/p/chromium/issues/detail?id=870966\n    this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top +\n    '; left: ' + style.left + '; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px;' +\n    ' padding-top: ' + style.fontSize + ';';\n\n    if (this.hiddenTextareaContainer) {\n      this.hiddenTextareaContainer.appendChild(this.hiddenTextarea);\n    }\n    else {\n      fabric.document.body.appendChild(this.hiddenTextarea);\n    }\n\n    fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'input', this.onInput.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'cut', this.copy.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'compositionstart', this.onCompositionStart.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'compositionupdate', this.onCompositionUpdate.bind(this));\n    fabric.util.addListener(this.hiddenTextarea, 'compositionend', this.onCompositionEnd.bind(this));\n\n    if (!this._clickHandlerInitialized && this.canvas) {\n      fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.onClick.bind(this));\n      this._clickHandlerInitialized = true;\n    }\n  },\n\n  /**\n   * For functionalities on keyDown\n   * Map a special key to a function of the instance/prototype\n   * If you need different behaviour for ESC or TAB or arrows, you have to change\n   * this map setting the name of a function that you build on the fabric.Itext or\n   * your prototype.\n   * the map change will affect all Instances unless you need for only some text Instances\n   * in that case you have to clone this object and assign your Instance.\n   * this.keysMap = fabric.util.object.clone(this.keysMap);\n   * The function must be in fabric.Itext.prototype.myFunction And will receive event as args[0]\n   */\n  keysMap: {\n    9:  'exitEditing',\n    27: 'exitEditing',\n    33: 'moveCursorUp',\n    34: 'moveCursorDown',\n    35: 'moveCursorRight',\n    36: 'moveCursorLeft',\n    37: 'moveCursorLeft',\n    38: 'moveCursorUp',\n    39: 'moveCursorRight',\n    40: 'moveCursorDown',\n  },\n\n  keysMapRtl: {\n    9:  'exitEditing',\n    27: 'exitEditing',\n    33: 'moveCursorUp',\n    34: 'moveCursorDown',\n    35: 'moveCursorLeft',\n    36: 'moveCursorRight',\n    37: 'moveCursorRight',\n    38: 'moveCursorUp',\n    39: 'moveCursorLeft',\n    40: 'moveCursorDown',\n  },\n\n  /**\n   * For functionalities on keyUp + ctrl || cmd\n   */\n  ctrlKeysMapUp: {\n    67: 'copy',\n    88: 'cut'\n  },\n\n  /**\n   * For functionalities on keyDown + ctrl || cmd\n   */\n  ctrlKeysMapDown: {\n    65: 'selectAll'\n  },\n\n  onClick: function() {\n    // No need to trigger click event here, focus is enough to have the keyboard appear on Android\n    this.hiddenTextarea && this.hiddenTextarea.focus();\n  },\n\n  /**\n   * Handles keydown event\n   * only used for arrows and combination of modifier keys.\n   * @param {Event} e Event object\n   */\n  onKeyDown: function(e) {\n    if (!this.isEditing) {\n      return;\n    }\n    var keyMap = this.direction === 'rtl' ? this.keysMapRtl : this.keysMap;\n    if (e.keyCode in keyMap) {\n      this[keyMap[e.keyCode]](e);\n    }\n    else if ((e.keyCode in this.ctrlKeysMapDown) && (e.ctrlKey || e.metaKey)) {\n      this[this.ctrlKeysMapDown[e.keyCode]](e);\n    }\n    else {\n      return;\n    }\n    e.stopImmediatePropagation();\n    e.preventDefault();\n    if (e.keyCode >= 33 && e.keyCode <= 40) {\n      // if i press an arrow key just update selection\n      this.inCompositionMode = false;\n      this.clearContextTop();\n      this.renderCursorOrSelection();\n    }\n    else {\n      this.canvas && this.canvas.requestRenderAll();\n    }\n  },\n\n  /**\n   * Handles keyup event\n   * We handle KeyUp because ie11 and edge have difficulties copy/pasting\n   * if a copy/cut event fired, keyup is dismissed\n   * @param {Event} e Event object\n   */\n  onKeyUp: function(e) {\n    if (!this.isEditing || this._copyDone || this.inCompositionMode) {\n      this._copyDone = false;\n      return;\n    }\n    if ((e.keyCode in this.ctrlKeysMapUp) && (e.ctrlKey || e.metaKey)) {\n      this[this.ctrlKeysMapUp[e.keyCode]](e);\n    }\n    else {\n      return;\n    }\n    e.stopImmediatePropagation();\n    e.preventDefault();\n    this.canvas && this.canvas.requestRenderAll();\n  },\n\n  /**\n   * Handles onInput event\n   * @param {Event} e Event object\n   */\n  onInput: function(e) {\n    var fromPaste = this.fromPaste;\n    this.fromPaste = false;\n    e && e.stopPropagation();\n    if (!this.isEditing) {\n      return;\n    }\n    // decisions about style changes.\n    var nextText = this._splitTextIntoLines(this.hiddenTextarea.value).graphemeText,\n        charCount = this._text.length,\n        nextCharCount = nextText.length,\n        removedText, insertedText,\n        charDiff = nextCharCount - charCount,\n        selectionStart = this.selectionStart, selectionEnd = this.selectionEnd,\n        selection = selectionStart !== selectionEnd,\n        copiedStyle, removeFrom, removeTo;\n    if (this.hiddenTextarea.value === '') {\n      this.styles = { };\n      this.updateFromTextArea();\n      this.fire('changed');\n      if (this.canvas) {\n        this.canvas.fire('text:changed', { target: this });\n        this.canvas.requestRenderAll();\n      }\n      return;\n    }\n\n    var textareaSelection = this.fromStringToGraphemeSelection(\n      this.hiddenTextarea.selectionStart,\n      this.hiddenTextarea.selectionEnd,\n      this.hiddenTextarea.value\n    );\n    var backDelete = selectionStart > textareaSelection.selectionStart;\n\n    if (selection) {\n      removedText = this._text.slice(selectionStart, selectionEnd);\n      charDiff += selectionEnd - selectionStart;\n    }\n    else if (nextCharCount < charCount) {\n      if (backDelete) {\n        removedText = this._text.slice(selectionEnd + charDiff, selectionEnd);\n      }\n      else {\n        removedText = this._text.slice(selectionStart, selectionStart - charDiff);\n      }\n    }\n    insertedText = nextText.slice(textareaSelection.selectionEnd - charDiff, textareaSelection.selectionEnd);\n    if (removedText && removedText.length) {\n      if (insertedText.length) {\n        // let's copy some style before deleting.\n        // we want to copy the style before the cursor OR the style at the cursor if selection\n        // is bigger than 0.\n        copiedStyle = this.getSelectionStyles(selectionStart, selectionStart + 1, false);\n        // now duplicate the style one for each inserted text.\n        copiedStyle = insertedText.map(function() {\n          // this return an array of references, but that is fine since we are\n          // copying the style later.\n          return copiedStyle[0];\n        });\n      }\n      if (selection) {\n        removeFrom = selectionStart;\n        removeTo = selectionEnd;\n      }\n      else if (backDelete) {\n        // detect differences between forwardDelete and backDelete\n        removeFrom = selectionEnd - removedText.length;\n        removeTo = selectionEnd;\n      }\n      else {\n        removeFrom = selectionEnd;\n        removeTo = selectionEnd + removedText.length;\n      }\n      this.removeStyleFromTo(removeFrom, removeTo);\n    }\n    if (insertedText.length) {\n      if (fromPaste && insertedText.join('') === fabric.copiedText && !fabric.disableStyleCopyPaste) {\n        copiedStyle = fabric.copiedTextStyle;\n      }\n      this.insertNewStyleBlock(insertedText, selectionStart, copiedStyle);\n    }\n    this.updateFromTextArea();\n    this.fire('changed');\n    if (this.canvas) {\n      this.canvas.fire('text:changed', { target: this });\n      this.canvas.requestRenderAll();\n    }\n  },\n  /**\n   * Composition start\n   */\n  onCompositionStart: function() {\n    this.inCompositionMode = true;\n  },\n\n  /**\n   * Composition end\n   */\n  onCompositionEnd: function() {\n    this.inCompositionMode = false;\n  },\n\n  // /**\n  //  * Composition update\n  //  */\n  onCompositionUpdate: function(e) {\n    this.compositionStart = e.target.selectionStart;\n    this.compositionEnd = e.target.selectionEnd;\n    this.updateTextareaPosition();\n  },\n\n  /**\n   * Copies selected text\n   * @param {Event} e Event object\n   */\n  copy: function() {\n    if (this.selectionStart === this.selectionEnd) {\n      //do not cut-copy if no selection\n      return;\n    }\n\n    fabric.copiedText = this.getSelectedText();\n    if (!fabric.disableStyleCopyPaste) {\n      fabric.copiedTextStyle = this.getSelectionStyles(this.selectionStart, this.selectionEnd, true);\n    }\n    else {\n      fabric.copiedTextStyle = null;\n    }\n    this._copyDone = true;\n  },\n\n  /**\n   * Pastes text\n   * @param {Event} e Event object\n   */\n  paste: function() {\n    this.fromPaste = true;\n  },\n\n  /**\n   * @private\n   * @param {Event} e Event object\n   * @return {Object} Clipboard data object\n   */\n  _getClipboardData: function(e) {\n    return (e && e.clipboardData) || fabric.window.clipboardData;\n  },\n\n  /**\n   * Finds the width in pixels before the cursor on the same line\n   * @private\n   * @param {Number} lineIndex\n   * @param {Number} charIndex\n   * @return {Number} widthBeforeCursor width before cursor\n   */\n  _getWidthBeforeCursor: function(lineIndex, charIndex) {\n    var widthBeforeCursor = this._getLineLeftOffset(lineIndex), bound;\n\n    if (charIndex > 0) {\n      bound = this.__charBounds[lineIndex][charIndex - 1];\n      widthBeforeCursor += bound.left + bound.width;\n    }\n    return widthBeforeCursor;\n  },\n\n  /**\n   * Gets start offset of a selection\n   * @param {Event} e Event object\n   * @param {Boolean} isRight\n   * @return {Number}\n   */\n  getDownCursorOffset: function(e, isRight) {\n    var selectionProp = this._getSelectionForOffset(e, isRight),\n        cursorLocation = this.get2DCursorLocation(selectionProp),\n        lineIndex = cursorLocation.lineIndex;\n    // if on last line, down cursor goes to end of line\n    if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {\n      // move to the end of a text\n      return this._text.length - selectionProp;\n    }\n    var charIndex = cursorLocation.charIndex,\n        widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),\n        indexOnOtherLine = this._getIndexOnLine(lineIndex + 1, widthBeforeCursor),\n        textAfterCursor = this._textLines[lineIndex].slice(charIndex);\n    return textAfterCursor.length + indexOnOtherLine + 1 + this.missingNewlineOffset(lineIndex);\n  },\n\n  /**\n   * private\n   * Helps finding if the offset should be counted from Start or End\n   * @param {Event} e Event object\n   * @param {Boolean} isRight\n   * @return {Number}\n   */\n  _getSelectionForOffset: function(e, isRight) {\n    if (e.shiftKey && this.selectionStart !== this.selectionEnd && isRight) {\n      return this.selectionEnd;\n    }\n    else {\n      return this.selectionStart;\n    }\n  },\n\n  /**\n   * @param {Event} e Event object\n   * @param {Boolean} isRight\n   * @return {Number}\n   */\n  getUpCursorOffset: function(e, isRight) {\n    var selectionProp = this._getSelectionForOffset(e, isRight),\n        cursorLocation = this.get2DCursorLocation(selectionProp),\n        lineIndex = cursorLocation.lineIndex;\n    if (lineIndex === 0 || e.metaKey || e.keyCode === 33) {\n      // if on first line, up cursor goes to start of line\n      return -selectionProp;\n    }\n    var charIndex = cursorLocation.charIndex,\n        widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),\n        indexOnOtherLine = this._getIndexOnLine(lineIndex - 1, widthBeforeCursor),\n        textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex),\n        missingNewlineOffset = this.missingNewlineOffset(lineIndex - 1);\n    // return a negative offset\n    return -this._textLines[lineIndex - 1].length\n     + indexOnOtherLine - textBeforeCursor.length + (1 - missingNewlineOffset);\n  },\n\n  /**\n   * for a given width it founds the matching character.\n   * @private\n   */\n  _getIndexOnLine: function(lineIndex, width) {\n\n    var line = this._textLines[lineIndex],\n        lineLeftOffset = this._getLineLeftOffset(lineIndex),\n        widthOfCharsOnLine = lineLeftOffset,\n        indexOnLine = 0, charWidth, foundMatch;\n\n    for (var j = 0, jlen = line.length; j < jlen; j++) {\n      charWidth = this.__charBounds[lineIndex][j].width;\n      widthOfCharsOnLine += charWidth;\n      if (widthOfCharsOnLine > width) {\n        foundMatch = true;\n        var leftEdge = widthOfCharsOnLine - charWidth,\n            rightEdge = widthOfCharsOnLine,\n            offsetFromLeftEdge = Math.abs(leftEdge - width),\n            offsetFromRightEdge = Math.abs(rightEdge - width);\n\n        indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1);\n        break;\n      }\n    }\n\n    // reached end\n    if (!foundMatch) {\n      indexOnLine = line.length - 1;\n    }\n\n    return indexOnLine;\n  },\n\n\n  /**\n   * Moves cursor down\n   * @param {Event} e Event object\n   */\n  moveCursorDown: function(e) {\n    if (this.selectionStart >= this._text.length && this.selectionEnd >= this._text.length) {\n      return;\n    }\n    this._moveCursorUpOrDown('Down', e);\n  },\n\n  /**\n   * Moves cursor up\n   * @param {Event} e Event object\n   */\n  moveCursorUp: function(e) {\n    if (this.selectionStart === 0 && this.selectionEnd === 0) {\n      return;\n    }\n    this._moveCursorUpOrDown('Up', e);\n  },\n\n  /**\n   * Moves cursor up or down, fires the events\n   * @param {String} direction 'Up' or 'Down'\n   * @param {Event} e Event object\n   */\n  _moveCursorUpOrDown: function(direction, e) {\n    // getUpCursorOffset\n    // getDownCursorOffset\n    var action = 'get' + direction + 'CursorOffset',\n        offset = this[action](e, this._selectionDirection === 'right');\n    if (e.shiftKey) {\n      this.moveCursorWithShift(offset);\n    }\n    else {\n      this.moveCursorWithoutShift(offset);\n    }\n    if (offset !== 0) {\n      this.setSelectionInBoundaries();\n      this.abortCursorAnimation();\n      this._currentCursorOpacity = 1;\n      this.initDelayedCursor();\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    }\n  },\n\n  /**\n   * Moves cursor with shift\n   * @param {Number} offset\n   */\n  moveCursorWithShift: function(offset) {\n    var newSelection = this._selectionDirection === 'left'\n      ? this.selectionStart + offset\n      : this.selectionEnd + offset;\n    this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection);\n    return offset !== 0;\n  },\n\n  /**\n   * Moves cursor up without shift\n   * @param {Number} offset\n   */\n  moveCursorWithoutShift: function(offset) {\n    if (offset < 0) {\n      this.selectionStart += offset;\n      this.selectionEnd = this.selectionStart;\n    }\n    else {\n      this.selectionEnd += offset;\n      this.selectionStart = this.selectionEnd;\n    }\n    return offset !== 0;\n  },\n\n  /**\n   * Moves cursor left\n   * @param {Event} e Event object\n   */\n  moveCursorLeft: function(e) {\n    if (this.selectionStart === 0 && this.selectionEnd === 0) {\n      return;\n    }\n    this._moveCursorLeftOrRight('Left', e);\n  },\n\n  /**\n   * @private\n   * @return {Boolean} true if a change happened\n   */\n  _move: function(e, prop, direction) {\n    var newValue;\n    if (e.altKey) {\n      newValue = this['findWordBoundary' + direction](this[prop]);\n    }\n    else if (e.metaKey || e.keyCode === 35 ||  e.keyCode === 36 ) {\n      newValue = this['findLineBoundary' + direction](this[prop]);\n    }\n    else {\n      this[prop] += direction === 'Left' ? -1 : 1;\n      return true;\n    }\n    if (typeof newValue !== 'undefined' && this[prop] !== newValue) {\n      this[prop] = newValue;\n      return true;\n    }\n  },\n\n  /**\n   * @private\n   */\n  _moveLeft: function(e, prop) {\n    return this._move(e, prop, 'Left');\n  },\n\n  /**\n   * @private\n   */\n  _moveRight: function(e, prop) {\n    return this._move(e, prop, 'Right');\n  },\n\n  /**\n   * Moves cursor left without keeping selection\n   * @param {Event} e\n   */\n  moveCursorLeftWithoutShift: function(e) {\n    var change = true;\n    this._selectionDirection = 'left';\n\n    // only move cursor when there is no selection,\n    // otherwise we discard it, and leave cursor on same place\n    if (this.selectionEnd === this.selectionStart && this.selectionStart !== 0) {\n      change = this._moveLeft(e, 'selectionStart');\n\n    }\n    this.selectionEnd = this.selectionStart;\n    return change;\n  },\n\n  /**\n   * Moves cursor left while keeping selection\n   * @param {Event} e\n   */\n  moveCursorLeftWithShift: function(e) {\n    if (this._selectionDirection === 'right' && this.selectionStart !== this.selectionEnd) {\n      return this._moveLeft(e, 'selectionEnd');\n    }\n    else if (this.selectionStart !== 0){\n      this._selectionDirection = 'left';\n      return this._moveLeft(e, 'selectionStart');\n    }\n  },\n\n  /**\n   * Moves cursor right\n   * @param {Event} e Event object\n   */\n  moveCursorRight: function(e) {\n    if (this.selectionStart >= this._text.length && this.selectionEnd >= this._text.length) {\n      return;\n    }\n    this._moveCursorLeftOrRight('Right', e);\n  },\n\n  /**\n   * Moves cursor right or Left, fires event\n   * @param {String} direction 'Left', 'Right'\n   * @param {Event} e Event object\n   */\n  _moveCursorLeftOrRight: function(direction, e) {\n    var actionName = 'moveCursor' + direction + 'With';\n    this._currentCursorOpacity = 1;\n\n    if (e.shiftKey) {\n      actionName += 'Shift';\n    }\n    else {\n      actionName += 'outShift';\n    }\n    if (this[actionName](e)) {\n      this.abortCursorAnimation();\n      this.initDelayedCursor();\n      this._fireSelectionChanged();\n      this._updateTextarea();\n    }\n  },\n\n  /**\n   * Moves cursor right while keeping selection\n   * @param {Event} e\n   */\n  moveCursorRightWithShift: function(e) {\n    if (this._selectionDirection === 'left' && this.selectionStart !== this.selectionEnd) {\n      return this._moveRight(e, 'selectionStart');\n    }\n    else if (this.selectionEnd !== this._text.length) {\n      this._selectionDirection = 'right';\n      return this._moveRight(e, 'selectionEnd');\n    }\n  },\n\n  /**\n   * Moves cursor right without keeping selection\n   * @param {Event} e Event object\n   */\n  moveCursorRightWithoutShift: function(e) {\n    var changed = true;\n    this._selectionDirection = 'right';\n\n    if (this.selectionStart === this.selectionEnd) {\n      changed = this._moveRight(e, 'selectionStart');\n      this.selectionEnd = this.selectionStart;\n    }\n    else {\n      this.selectionStart = this.selectionEnd;\n    }\n    return changed;\n  },\n\n  /**\n   * Removes characters from start/end\n   * start/end ar per grapheme position in _text array.\n   *\n   * @param {Number} start\n   * @param {Number} end default to start + 1\n   */\n  removeChars: function(start, end) {\n    if (typeof end === 'undefined') {\n      end = start + 1;\n    }\n    this.removeStyleFromTo(start, end);\n    this._text.splice(start, end - start);\n    this.text = this._text.join('');\n    this.set('dirty', true);\n    if (this._shouldClearDimensionCache()) {\n      this.initDimensions();\n      this.setCoords();\n    }\n    this._removeExtraneousStyles();\n  },\n\n  /**\n   * insert characters at start position, before start position.\n   * start  equal 1 it means the text get inserted between actual grapheme 0 and 1\n   * if style array is provided, it must be as the same length of text in graphemes\n   * if end is provided and is bigger than start, old text is replaced.\n   * start/end ar per grapheme position in _text array.\n   *\n   * @param {String} text text to insert\n   * @param {Array} style array of style objects\n   * @param {Number} start\n   * @param {Number} end default to start + 1\n   */\n  insertChars: function(text, style, start, end) {\n    if (typeof end === 'undefined') {\n      end = start;\n    }\n    if (end > start) {\n      this.removeStyleFromTo(start, end);\n    }\n    var graphemes = fabric.util.string.graphemeSplit(text);\n    this.insertNewStyleBlock(graphemes, start, style);\n    this._text = [].concat(this._text.slice(0, start), graphemes, this._text.slice(end));\n    this.text = this._text.join('');\n    this.set('dirty', true);\n    if (this._shouldClearDimensionCache()) {\n      this.initDimensions();\n      this.setCoords();\n    }\n    this._removeExtraneousStyles();\n  },\n\n});\n\n\n/* _TO_SVG_START_ */\n(function() {\n  var toFixed = fabric.util.toFixed,\n      radiansToDegrees = fabric.util.radiansToDegrees,\n      calcRotateMatrix = fabric.util.calcRotateMatrix,\n      transformPoint = fabric.util.transformPoint,\n      multipleSpacesRegex = /  +/g;\n\n  fabric.util.object.extend(fabric.Text.prototype, /** @lends fabric.Text.prototype */ {\n\n    /**\n     * Returns SVG representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    _toSVG: function() {\n      var offsets = this._getSVGLeftTopOffsets(),\n          textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);\n      return this._wrapSVGTextAndBg(textAndBg);\n    },\n\n    /**\n     * Returns svg representation of an instance\n     * @param {Function} [reviver] Method for further parsing of svg representation.\n     * @return {String} svg representation of an instance\n     */\n    toSVG: function(reviver) {\n      var textSvg = this._createBaseSVGMarkup(\n            this._toSVG(),\n            { reviver: reviver, noStyle: true, withShadow: true }\n          ),\n          path = this.path;\n\n      if (path) {\n        return (\n          textSvg +\n          path._createBaseSVGMarkup(path._toSVG(), {\n            reviver: reviver,\n            withShadow: true,\n          })\n        );\n      }\n      return textSvg;\n    },\n\n    /**\n     * @private\n     */\n    _getSVGLeftTopOffsets: function() {\n      return {\n        textLeft: -this.width / 2,\n        textTop: -this.height / 2,\n        lineTop: this.getHeightOfLine(0)\n      };\n    },\n\n    /**\n     * @private\n     */\n    _wrapSVGTextAndBg: function(textAndBg) {\n      var noShadow = true,\n          textDecoration = this.getSvgTextDecoration(this);\n      return [\n        textAndBg.textBgRects.join(''),\n        '\\t\\t<text xml:space=\"preserve\" ',\n        (this.fontFamily ? 'font-family=\"' + this.fontFamily.replace(/\"/g, '\\'') + '\" ' : ''),\n        (this.fontSize ? 'font-size=\"' + this.fontSize + '\" ' : ''),\n        (this.fontStyle ? 'font-style=\"' + this.fontStyle + '\" ' : ''),\n        (this.fontWeight ? 'font-weight=\"' + this.fontWeight + '\" ' : ''),\n        (textDecoration ? 'text-decoration=\"' + textDecoration + '\" ' : ''),\n        'style=\"', this.getSvgStyles(noShadow), '\"', this.addPaintOrder(), ' >',\n        textAndBg.textSpans.join(''),\n        '</text>\\n'\n      ];\n    },\n\n    /**\n     * @private\n     * @param {Number} textTopOffset Text top offset\n     * @param {Number} textLeftOffset Text left offset\n     * @return {Object}\n     */\n    _getSVGTextAndBg: function(textTopOffset, textLeftOffset) {\n      var textSpans = [],\n          textBgRects = [],\n          height = textTopOffset, lineOffset;\n      // bounding-box background\n      this._setSVGBg(textBgRects);\n\n      // text and text-background\n      for (var i = 0, len = this._textLines.length; i < len; i++) {\n        lineOffset = this._getLineLeftOffset(i);\n        if (this.textBackgroundColor || this.styleHas('textBackgroundColor', i)) {\n          this._setSVGTextLineBg(textBgRects, i, textLeftOffset + lineOffset, height);\n        }\n        this._setSVGTextLineText(textSpans, i, textLeftOffset + lineOffset, height);\n        height += this.getHeightOfLine(i);\n      }\n\n      return {\n        textSpans: textSpans,\n        textBgRects: textBgRects\n      };\n    },\n\n    /**\n     * @private\n     */\n    _createTextCharSpan: function(_char, styleDecl, left, top, charBox) {\n      var shouldUseWhitespace = _char !== _char.trim() || _char.match(multipleSpacesRegex),\n          styleProps = this.getSvgSpanStyles(styleDecl, shouldUseWhitespace),\n          fillStyles = styleProps ? 'style=\"' + styleProps + '\"' : '',\n          dy = styleDecl.deltaY, dySpan = '',\n          NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n          angleAttr = '';\n      if (dy) {\n        dySpan = ' dy=\"' + toFixed(dy, NUM_FRACTION_DIGITS) + '\" ';\n      }\n      if (charBox.renderLeft !== undefined) {\n        var angle = charBox.angle;\n        angleAttr = ' rotate=\"' + toFixed(radiansToDegrees(angle), fabric.Object.NUM_FRACTION_DIGITS) + '\" ';\n        var wBy2 = charBox.width / 2,\n            m = calcRotateMatrix({ angle: radiansToDegrees(angle) });\n        m[4] = charBox.renderLeft;\n        m[5] = charBox.renderTop;\n        var renderPoint = transformPoint({ x: -wBy2, y: 0 }, m);\n        left = renderPoint.x;\n        top = renderPoint.y;\n      }\n      return [\n        '<tspan x=\"', toFixed(left, NUM_FRACTION_DIGITS), '\" y=\"',\n        toFixed(top, NUM_FRACTION_DIGITS), '\" ', dySpan,\n        fillStyles, angleAttr, '>',\n        fabric.util.string.escapeXml(_char),\n        '</tspan>'\n      ].join('');\n    },\n\n    _setSVGTextLineText: function(textSpans, lineIndex, textLeftOffset, textTopOffset) {\n      // set proper line offset\n      var lineHeight = this.getHeightOfLine(lineIndex),\n          isJustify = this.textAlign.indexOf('justify') !== -1,\n          actualStyle,\n          nextStyle,\n          charsToRender = '',\n          charBox, style,\n          boxWidth = 0,\n          line = this._textLines[lineIndex],\n          timeToRender;\n\n      textTopOffset += lineHeight * (1 - this._fontSizeFraction) / this.lineHeight;\n      for (var i = 0, len = line.length - 1; i <= len; i++) {\n        timeToRender = i === len || this.charSpacing || this.path;\n        charsToRender += line[i];\n        charBox = this.__charBounds[lineIndex][i];\n        if (boxWidth === 0) {\n          textLeftOffset += charBox.kernedWidth - charBox.width;\n          boxWidth += charBox.width;\n        }\n        else {\n          boxWidth += charBox.kernedWidth;\n        }\n        if (isJustify && !timeToRender) {\n          if (this._reSpaceAndTab.test(line[i])) {\n            timeToRender = true;\n          }\n        }\n        if (!timeToRender) {\n          // if we have charSpacing, we render char by char\n          actualStyle = actualStyle || this.getCompleteStyleDeclaration(lineIndex, i);\n          nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1);\n          timeToRender = fabric.util.hasStyleChanged(actualStyle, nextStyle, true);\n        }\n        if (timeToRender) {\n          style = this._getStyleDeclaration(lineIndex, i) || { };\n          textSpans.push(this._createTextCharSpan(charsToRender, style, textLeftOffset, textTopOffset, charBox));\n          charsToRender = '';\n          actualStyle = nextStyle;\n          textLeftOffset += boxWidth;\n          boxWidth = 0;\n        }\n      }\n    },\n\n    _pushTextBgRect: function(textBgRects, color, left, top, width, height) {\n      var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n      textBgRects.push(\n        '\\t\\t<rect ',\n        this._getFillAttributes(color),\n        ' x=\"',\n        toFixed(left, NUM_FRACTION_DIGITS),\n        '\" y=\"',\n        toFixed(top, NUM_FRACTION_DIGITS),\n        '\" width=\"',\n        toFixed(width, NUM_FRACTION_DIGITS),\n        '\" height=\"',\n        toFixed(height, NUM_FRACTION_DIGITS),\n        '\"></rect>\\n');\n    },\n\n    _setSVGTextLineBg: function(textBgRects, i, leftOffset, textTopOffset) {\n      var line = this._textLines[i],\n          heightOfLine = this.getHeightOfLine(i) / this.lineHeight,\n          boxWidth = 0,\n          boxStart = 0,\n          charBox, currentColor,\n          lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor');\n      for (var j = 0, jlen = line.length; j < jlen; j++) {\n        charBox = this.__charBounds[i][j];\n        currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');\n        if (currentColor !== lastColor) {\n          lastColor && this._pushTextBgRect(textBgRects, lastColor, leftOffset + boxStart,\n            textTopOffset, boxWidth, heightOfLine);\n          boxStart = charBox.left;\n          boxWidth = charBox.width;\n          lastColor = currentColor;\n        }\n        else {\n          boxWidth += charBox.kernedWidth;\n        }\n      }\n      currentColor && this._pushTextBgRect(textBgRects, currentColor, leftOffset + boxStart,\n        textTopOffset, boxWidth, heightOfLine);\n    },\n\n    /**\n     * Adobe Illustrator (at least CS5) is unable to render rgba()-based fill values\n     * we work around it by \"moving\" alpha channel into opacity attribute and setting fill's alpha to 1\n     *\n     * @private\n     * @param {*} value\n     * @return {String}\n     */\n    _getFillAttributes: function(value) {\n      var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : '';\n      if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) {\n        return 'fill=\"' + value + '\"';\n      }\n      return 'opacity=\"' + fillColor.getAlpha() + '\" fill=\"' + fillColor.setAlpha(1).toRgb() + '\"';\n    },\n\n    /**\n     * @private\n     */\n    _getSVGLineTopOffset: function(lineIndex) {\n      var lineTopOffset = 0, lastHeight = 0;\n      for (var j = 0; j < lineIndex; j++) {\n        lineTopOffset += this.getHeightOfLine(j);\n      }\n      lastHeight = this.getHeightOfLine(j);\n      return {\n        lineTop: lineTopOffset,\n        offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult)\n      };\n    },\n\n    /**\n     * Returns styles-string for svg-export\n     * @param {Boolean} skipShadow a boolean to skip shadow filter output\n     * @return {String}\n     */\n    getSvgStyles: function(skipShadow) {\n      var svgStyle = fabric.Object.prototype.getSvgStyles.call(this, skipShadow);\n      return svgStyle + ' white-space: pre;';\n    },\n  });\n})();\n/* _TO_SVG_END_ */\n\n\n(function(global) {\n\n  'use strict';\n\n  var fabric = global.fabric || (global.fabric = {});\n\n  /**\n   * Textbox class, based on IText, allows the user to resize the text rectangle\n   * and wraps lines automatically. Textboxes have their Y scaling locked, the\n   * user can only change width. Height is adjusted automatically based on the\n   * wrapping of lines.\n   * @class fabric.Textbox\n   * @extends fabric.IText\n   * @mixes fabric.Observable\n   * @return {fabric.Textbox} thisArg\n   * @see {@link fabric.Textbox#initialize} for constructor definition\n   */\n  fabric.Textbox = fabric.util.createClass(fabric.IText, fabric.Observable, {\n\n    /**\n     * Type of an object\n     * @type String\n     * @default\n     */\n    type: 'textbox',\n\n    /**\n     * Minimum width of textbox, in pixels.\n     * @type Number\n     * @default\n     */\n    minWidth: 20,\n\n    /**\n     * Minimum calculated width of a textbox, in pixels.\n     * fixed to 2 so that an empty textbox cannot go to 0\n     * and is still selectable without text.\n     * @type Number\n     * @default\n     */\n    dynamicMinWidth: 2,\n\n    /**\n     * Cached array of text wrapping.\n     * @type Array\n     */\n    __cachedLines: null,\n\n    /**\n     * Override standard Object class values\n     */\n    lockScalingFlip: true,\n\n    /**\n     * Override standard Object class values\n     * Textbox needs this on false\n     */\n    noScaleCache: false,\n\n    /**\n     * Properties which when set cause object to change dimensions\n     * @type Object\n     * @private\n     */\n    _dimensionAffectingProps: fabric.Text.prototype._dimensionAffectingProps.concat('width'),\n\n    /**\n     * Use this regular expression to split strings in breakable lines\n     * @private\n     */\n    _wordJoiners: /[ \\t\\r]/,\n\n    /**\n     * Use this boolean property in order to split strings that have no white space concept.\n     * this is a cheap way to help with chinese/japanese\n     * @type Boolean\n     * @since 2.6.0\n     */\n    splitByGrapheme: false,\n\n    /**\n     * Unlike superclass's version of this function, Textbox does not update\n     * its width.\n     * @private\n     * @override\n     */\n    initDimensions: function() {\n      if (this.__skipDimension) {\n        return;\n      }\n      this.isEditing && this.initDelayedCursor();\n      this.clearContextTop();\n      this._clearCache();\n      // clear dynamicMinWidth as it will be different after we re-wrap line\n      this.dynamicMinWidth = 0;\n      // wrap lines\n      this._styleMap = this._generateStyleMap(this._splitText());\n      // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap\n      if (this.dynamicMinWidth > this.width) {\n        this._set('width', this.dynamicMinWidth);\n      }\n      if (this.textAlign.indexOf('justify') !== -1) {\n        // once text is measured we need to make space fatter to make justified text.\n        this.enlargeSpaces();\n      }\n      // clear cache and re-calculate height\n      this.height = this.calcTextHeight();\n      this.saveState({ propertySet: '_dimensionAffectingProps' });\n    },\n\n    /**\n     * Generate an object that translates the style object so that it is\n     * broken up by visual lines (new lines and automatic wrapping).\n     * The original text styles object is broken up by actual lines (new lines only),\n     * which is only sufficient for Text / IText\n     * @private\n     */\n    _generateStyleMap: function(textInfo) {\n      var realLineCount     = 0,\n          realLineCharCount = 0,\n          charCount         = 0,\n          map               = {};\n\n      for (var i = 0; i < textInfo.graphemeLines.length; i++) {\n        if (textInfo.graphemeText[charCount] === '\\n' && i > 0) {\n          realLineCharCount = 0;\n          charCount++;\n          realLineCount++;\n        }\n        else if (!this.splitByGrapheme && this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) && i > 0) {\n          // this case deals with space's that are removed from end of lines when wrapping\n          realLineCharCount++;\n          charCount++;\n        }\n\n        map[i] = { line: realLineCount, offset: realLineCharCount };\n\n        charCount += textInfo.graphemeLines[i].length;\n        realLineCharCount += textInfo.graphemeLines[i].length;\n      }\n\n      return map;\n    },\n\n    /**\n     * Returns true if object has a style property or has it on a specified line\n     * @param {Number} lineIndex\n     * @return {Boolean}\n     */\n    styleHas: function(property, lineIndex) {\n      if (this._styleMap && !this.isWrapping) {\n        var map = this._styleMap[lineIndex];\n        if (map) {\n          lineIndex = map.line;\n        }\n      }\n      return fabric.Text.prototype.styleHas.call(this, property, lineIndex);\n    },\n\n    /**\n     * Returns true if object has no styling or no styling in a line\n     * @param {Number} lineIndex , lineIndex is on wrapped lines.\n     * @return {Boolean}\n     */\n    isEmptyStyles: function(lineIndex) {\n      if (!this.styles) {\n        return true;\n      }\n      var offset = 0, nextLineIndex = lineIndex + 1, nextOffset, obj, shouldLimit = false,\n          map = this._styleMap[lineIndex], mapNextLine = this._styleMap[lineIndex + 1];\n      if (map) {\n        lineIndex = map.line;\n        offset = map.offset;\n      }\n      if (mapNextLine) {\n        nextLineIndex = mapNextLine.line;\n        shouldLimit = nextLineIndex === lineIndex;\n        nextOffset = mapNextLine.offset;\n      }\n      obj = typeof lineIndex === 'undefined' ? this.styles : { line: this.styles[lineIndex] };\n      for (var p1 in obj) {\n        for (var p2 in obj[p1]) {\n          if (p2 >= offset && (!shouldLimit || p2 < nextOffset)) {\n            // eslint-disable-next-line no-unused-vars\n            for (var p3 in obj[p1][p2]) {\n              return false;\n            }\n          }\n        }\n      }\n      return true;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @private\n     */\n    _getStyleDeclaration: function(lineIndex, charIndex) {\n      if (this._styleMap && !this.isWrapping) {\n        var map = this._styleMap[lineIndex];\n        if (!map) {\n          return null;\n        }\n        lineIndex = map.line;\n        charIndex = map.offset + charIndex;\n      }\n      return this.callSuper('_getStyleDeclaration', lineIndex, charIndex);\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @param {Object} style\n     * @private\n     */\n    _setStyleDeclaration: function(lineIndex, charIndex, style) {\n      var map = this._styleMap[lineIndex];\n      lineIndex = map.line;\n      charIndex = map.offset + charIndex;\n\n      this.styles[lineIndex][charIndex] = style;\n    },\n\n    /**\n     * @param {Number} lineIndex\n     * @param {Number} charIndex\n     * @private\n     */\n    _deleteStyleDeclaration: function(lineIndex, charIndex) {\n      var map = this._styleMap[lineIndex];\n      lineIndex = map.line;\n      charIndex = map.offset + charIndex;\n      delete this.styles[lineIndex][charIndex];\n    },\n\n    /**\n     * probably broken need a fix\n     * Returns the real style line that correspond to the wrapped lineIndex line\n     * Used just to verify if the line does exist or not.\n     * @param {Number} lineIndex\n     * @returns {Boolean} if the line exists or not\n     * @private\n     */\n    _getLineStyle: function(lineIndex) {\n      var map = this._styleMap[lineIndex];\n      return !!this.styles[map.line];\n    },\n\n    /**\n     * Set the line style to an empty object so that is initialized\n     * @param {Number} lineIndex\n     * @param {Object} style\n     * @private\n     */\n    _setLineStyle: function(lineIndex) {\n      var map = this._styleMap[lineIndex];\n      this.styles[map.line] = {};\n    },\n\n    /**\n     * Wraps text using the 'width' property of Textbox. First this function\n     * splits text on newlines, so we preserve newlines entered by the user.\n     * Then it wraps each line using the width of the Textbox by calling\n     * _wrapLine().\n     * @param {Array} lines The string array of text that is split into lines\n     * @param {Number} desiredWidth width you want to wrap to\n     * @returns {Array} Array of lines\n     */\n    _wrapText: function(lines, desiredWidth) {\n      var wrapped = [], i;\n      this.isWrapping = true;\n      for (i = 0; i < lines.length; i++) {\n        wrapped = wrapped.concat(this._wrapLine(lines[i], i, desiredWidth));\n      }\n      this.isWrapping = false;\n      return wrapped;\n    },\n\n    /**\n     * Helper function to measure a string of text, given its lineIndex and charIndex offset\n     * it gets called when charBounds are not available yet.\n     * @param {CanvasRenderingContext2D} ctx\n     * @param {String} text\n     * @param {number} lineIndex\n     * @param {number} charOffset\n     * @returns {number}\n     * @private\n     */\n    _measureWord: function(word, lineIndex, charOffset) {\n      var width = 0, prevGrapheme, skipLeft = true;\n      charOffset = charOffset || 0;\n      for (var i = 0, len = word.length; i < len; i++) {\n        var box = this._getGraphemeBox(word[i], lineIndex, i + charOffset, prevGrapheme, skipLeft);\n        width += box.kernedWidth;\n        prevGrapheme = word[i];\n      }\n      return width;\n    },\n\n    /**\n     * Wraps a line of text using the width of the Textbox and a context.\n     * @param {Array} line The grapheme array that represent the line\n     * @param {Number} lineIndex\n     * @param {Number} desiredWidth width you want to wrap the line to\n     * @param {Number} reservedSpace space to remove from wrapping for custom functionalities\n     * @returns {Array} Array of line(s) into which the given text is wrapped\n     * to.\n     */\n    _wrapLine: function(_line, lineIndex, desiredWidth, reservedSpace) {\n      var lineWidth = 0,\n          splitByGrapheme = this.splitByGrapheme,\n          graphemeLines = [],\n          line = [],\n          // spaces in different languages?\n          words = splitByGrapheme ? fabric.util.string.graphemeSplit(_line) : _line.split(this._wordJoiners),\n          word = '',\n          offset = 0,\n          infix = splitByGrapheme ? '' : ' ',\n          wordWidth = 0,\n          infixWidth = 0,\n          largestWordWidth = 0,\n          lineJustStarted = true,\n          additionalSpace = this._getWidthOfCharSpacing(),\n          reservedSpace = reservedSpace || 0;\n      // fix a difference between split and graphemeSplit\n      if (words.length === 0) {\n        words.push([]);\n      }\n      desiredWidth -= reservedSpace;\n      for (var i = 0; i < words.length; i++) {\n        // if using splitByGrapheme words are already in graphemes.\n        word = splitByGrapheme ? words[i] : fabric.util.string.graphemeSplit(words[i]);\n        wordWidth = this._measureWord(word, lineIndex, offset);\n        offset += word.length;\n\n        lineWidth += infixWidth + wordWidth - additionalSpace;\n        if (lineWidth > desiredWidth && !lineJustStarted) {\n          graphemeLines.push(line);\n          line = [];\n          lineWidth = wordWidth;\n          lineJustStarted = true;\n        }\n        else {\n          lineWidth += additionalSpace;\n        }\n\n        if (!lineJustStarted && !splitByGrapheme) {\n          line.push(infix);\n        }\n        line = line.concat(word);\n\n        infixWidth = splitByGrapheme ? 0 : this._measureWord([infix], lineIndex, offset);\n        offset++;\n        lineJustStarted = false;\n        // keep track of largest word\n        if (wordWidth > largestWordWidth) {\n          largestWordWidth = wordWidth;\n        }\n      }\n\n      i && graphemeLines.push(line);\n\n      if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {\n        this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;\n      }\n      return graphemeLines;\n    },\n\n    /**\n     * Detect if the text line is ended with an hard break\n     * text and itext do not have wrapping, return false\n     * @param {Number} lineIndex text to split\n     * @return {Boolean}\n     */\n    isEndOfWrapping: function(lineIndex) {\n      if (!this._styleMap[lineIndex + 1]) {\n        // is last line, return true;\n        return true;\n      }\n      if (this._styleMap[lineIndex + 1].line !== this._styleMap[lineIndex].line) {\n        // this is last line before a line break, return true;\n        return true;\n      }\n      return false;\n    },\n\n    /**\n     * Detect if a line has a linebreak and so we need to account for it when moving\n     * and counting style.\n     * This is important only for splitByGrapheme at the end of wrapping.\n     * If we are not wrapping the offset is always 1\n     * @return Number\n     */\n    missingNewlineOffset: function(lineIndex, skipWrapping) {\n      if (this.splitByGrapheme && !skipWrapping) {\n        return this.isEndOfWrapping(lineIndex) ? 1 : 0;\n      }\n      return 1;\n    },\n\n    /**\n    * Gets lines of text to render in the Textbox. This function calculates\n    * text wrapping on the fly every time it is called.\n    * @param {String} text text to split\n    * @returns {Array} Array of lines in the Textbox.\n    * @override\n    */\n    _splitTextIntoLines: function(text) {\n      var newText = fabric.Text.prototype._splitTextIntoLines.call(this, text),\n          graphemeLines = this._wrapText(newText.lines, this.width),\n          lines = new Array(graphemeLines.length);\n      for (var i = 0; i < graphemeLines.length; i++) {\n        lines[i] = graphemeLines[i].join('');\n      }\n      newText.lines = lines;\n      newText.graphemeLines = graphemeLines;\n      return newText;\n    },\n\n    getMinWidth: function() {\n      return Math.max(this.minWidth, this.dynamicMinWidth);\n    },\n\n    _removeExtraneousStyles: function() {\n      var linesToKeep = {};\n      for (var prop in this._styleMap) {\n        if (this._textLines[prop]) {\n          linesToKeep[this._styleMap[prop].line] = 1;\n        }\n      }\n      for (var prop in this.styles) {\n        if (!linesToKeep[prop]) {\n          delete this.styles[prop];\n        }\n      }\n    },\n\n    /**\n     * Returns object representation of an instance\n     * @method toObject\n     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n     * @return {Object} object representation of an instance\n     */\n    toObject: function(propertiesToInclude) {\n      return this.callSuper('toObject', ['minWidth', 'splitByGrapheme'].concat(propertiesToInclude));\n    }\n  });\n\n  /**\n   * Returns fabric.Textbox instance from an object representation\n   * @static\n   * @memberOf fabric.Textbox\n   * @param {Object} object Object to create an instance from\n   * @param {Function} [callback] Callback to invoke when an fabric.Textbox instance is created\n   */\n  fabric.Textbox.fromObject = function(object, callback) {\n    var styles = fabric.util.stylesFromArray(object.styles, object.text);\n    //copy object to prevent mutation\n    var objCopy = Object.assign({}, object, { styles: styles });\n    delete objCopy.path;\n    return fabric.Object._fromObject('Textbox', objCopy,  function(textInstance) {\n      if (object.path) {\n        fabric.Object._fromObject('Path', object.path, function(pathInstance) {\n          textInstance.set('path', pathInstance);\n          callback(textInstance);\n        }, 'path');\n      }\n      else {\n        callback(textInstance);\n      }\n    }, 'text');\n  };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n  var controlsUtils = fabric.controlsUtils,\n      scaleSkewStyleHandler = controlsUtils.scaleSkewCursorStyleHandler,\n      scaleStyleHandler = controlsUtils.scaleCursorStyleHandler,\n      scalingEqually = controlsUtils.scalingEqually,\n      scalingYOrSkewingX = controlsUtils.scalingYOrSkewingX,\n      scalingXOrSkewingY = controlsUtils.scalingXOrSkewingY,\n      scaleOrSkewActionName = controlsUtils.scaleOrSkewActionName,\n      objectControls = fabric.Object.prototype.controls;\n\n  objectControls.ml = new fabric.Control({\n    x: -0.5,\n    y: 0,\n    cursorStyleHandler: scaleSkewStyleHandler,\n    actionHandler: scalingXOrSkewingY,\n    getActionName: scaleOrSkewActionName,\n  });\n\n  objectControls.mr = new fabric.Control({\n    x: 0.5,\n    y: 0,\n    cursorStyleHandler: scaleSkewStyleHandler,\n    actionHandler: scalingXOrSkewingY,\n    getActionName: scaleOrSkewActionName,\n  });\n\n  objectControls.mb = new fabric.Control({\n    x: 0,\n    y: 0.5,\n    cursorStyleHandler: scaleSkewStyleHandler,\n    actionHandler: scalingYOrSkewingX,\n    getActionName: scaleOrSkewActionName,\n  });\n\n  objectControls.mt = new fabric.Control({\n    x: 0,\n    y: -0.5,\n    cursorStyleHandler: scaleSkewStyleHandler,\n    actionHandler: scalingYOrSkewingX,\n    getActionName: scaleOrSkewActionName,\n  });\n\n  objectControls.tl = new fabric.Control({\n    x: -0.5,\n    y: -0.5,\n    cursorStyleHandler: scaleStyleHandler,\n    actionHandler: scalingEqually\n  });\n\n  objectControls.tr = new fabric.Control({\n    x: 0.5,\n    y: -0.5,\n    cursorStyleHandler: scaleStyleHandler,\n    actionHandler: scalingEqually\n  });\n\n  objectControls.bl = new fabric.Control({\n    x: -0.5,\n    y: 0.5,\n    cursorStyleHandler: scaleStyleHandler,\n    actionHandler: scalingEqually\n  });\n\n  objectControls.br = new fabric.Control({\n    x: 0.5,\n    y: 0.5,\n    cursorStyleHandler: scaleStyleHandler,\n    actionHandler: scalingEqually\n  });\n\n  objectControls.mtr = new fabric.Control({\n    x: 0,\n    y: -0.5,\n    actionHandler: controlsUtils.rotationWithSnapping,\n    cursorStyleHandler: controlsUtils.rotationStyleHandler,\n    offsetY: -40,\n    withConnection: true,\n    actionName: 'rotate',\n  });\n\n  if (fabric.Textbox) {\n    // this is breaking the prototype inheritance, no time / ideas to fix it.\n    // is important to document that if you want to have all objects to have a\n    // specific custom control, you have to add it to Object prototype and to Textbox\n    // prototype. The controls are shared as references. So changes to control `tr`\n    // can still apply to all objects if needed.\n    var textBoxControls = fabric.Textbox.prototype.controls = { };\n\n    textBoxControls.mtr = objectControls.mtr;\n    textBoxControls.tr = objectControls.tr;\n    textBoxControls.br = objectControls.br;\n    textBoxControls.tl = objectControls.tl;\n    textBoxControls.bl = objectControls.bl;\n    textBoxControls.mt = objectControls.mt;\n    textBoxControls.mb = objectControls.mb;\n\n    textBoxControls.mr = new fabric.Control({\n      x: 0.5,\n      y: 0,\n      actionHandler: controlsUtils.changeWidth,\n      cursorStyleHandler: scaleSkewStyleHandler,\n      actionName: 'resizing',\n    });\n\n    textBoxControls.ml = new fabric.Control({\n      x: -0.5,\n      y: 0,\n      actionHandler: controlsUtils.changeWidth,\n      cursorStyleHandler: scaleSkewStyleHandler,\n      actionName: 'resizing',\n    });\n  }\n})();\n\n","import { useHistory, useLocation } from \"react-router-dom\";\nconst ReactRouter5Adapter = ({\n  children\n}) => {\n  const location = useLocation();\n  const history = useHistory();\n  const adapter = {\n    replace(location2) {\n      history.replace(location2.search || \"?\", location2.state);\n    },\n    push(location2) {\n      history.push(location2.search || \"?\", location2.state);\n    },\n    get location() {\n      return history.location;\n    }\n  };\n  return children(adapter);\n};\nexport {\n  ReactRouter5Adapter\n};\n"],"names":["global","sqrt","atan2","pow","PiBy180","PiBy2","couldUseAttachEvent","touchEvents","parseEl","supportsOpacity","supportsFilters","reOpacity","setOpacity","proto","min","max","degreesToRadians","originXOffset","originYOffset","clone","toFixed","radiansToDegrees","calcRotateMatrix","transformPoint","multipleSpacesRegex","fabric","version","exports","document","window","HTMLDocument","Document","implementation","createHTMLDocument","virtualWindow","JSDOM","decodeURIComponent","features","FetchExternalResources","resources","jsdomImplForWrapper","nodeCanvas","DOMParser","copyGLTo2DDrawImage","gl","pipelineState","glCanvas","canvas","targetCanvas","ctx","getContext","translate","height","scale","sourceY","drawImage","width","copyGLTo2DPutImageData","dWidth","destinationWidth","dHeight","destinationHeight","numBytes","u8","Uint8Array","this","imageBuffer","u8Clamped","Uint8ClampedArray","readPixels","RGBA","UNSIGNED_BYTE","imgData","ImageData","putImageData","isTouchSupported","navigator","maxTouchPoints","isLikelyNode","Buffer","SHARED_ATTRIBUTES","DPI","reNum","commaWsp","rePathCommand","reNonWord","fontPaths","iMatrix","svgNS","perfLimitSizeTotal","maxCacheSideLimit","minCacheSideLimit","charWidthsCache","textureSize","disableStyleCopyPaste","enableGLFiltering","devicePixelRatio","webkitDevicePixelRatio","mozDevicePixelRatio","browserShadowBlurConstant","arcToSegmentsCache","boundsOfCurveCache","cachesBoundsOfCurve","forceGLPutImageData","initFilterBackend","isWebglSupported","console","log","maxTextureSize","WebglFilterBackend","tileSize","Canvas2dFilterBackend","_removeEventListener","eventName","handler","__eventListeners","eventListener","indexOf","util","array","fill","_once","_handler","apply","arguments","off","bind","on","Observable","fire","options","listenersForEvent","i","len","length","call","filter","value","prop","push","once","Collection","_objects","add","_onObjectAdded","renderOnAddRemove","requestRenderAll","insertAt","object","index","nonSplicing","objects","splice","remove","somethingRemoved","_onObjectRemoved","forEachObject","callback","context","getObjects","type","concat","o","item","isEmpty","size","contains","deep","some","obj","complexity","reduce","memo","current","CommonMethods","_setOptions","set","_initGradient","filler","property","colorStops","Gradient","_initPattern","source","Pattern","_setObject","_set","key","toggle","get","Math","PI","cos","angle","sin","sign","removeFromArray","idx","getRandomInt","floor","random","degrees","radians","rotatePoint","point","origin","newPoint","Point","x","y","v","rotateVector","addEquals","vector","createVector","from","to","calcAngleBetweenVectors","a","b","acos","hypot","getHatVector","multiply","getBisector","A","B","C","AB","AC","alpha","phi","projectStrokeOnPoints","points","openPath","coords","s","strokeWidth","strokeUniformScalar","strokeUniform","scaleX","scaleY","getStrokeHatVector","scalar","forEach","p","miterVector","bisector","bisectorVector","strokeLineJoin","strokeMiterLimit","subtract","SQRT2","t","ignoreOffset","makeBoundingBoxFromPoints","transform","xPoints","minX","yPoints","minY","left","top","invertTransform","r","number","fractionDigits","parseFloat","Number","parseUnit","fontSize","unit","exec","Text","DEFAULT_SVG_FONT_SIZE","falseFunction","getKlass","namespace","string","camelize","charAt","toUpperCase","slice","resolveNamespace","getSvgAttributes","attributes","parts","split","loadImage","url","crossOrigin","img","createImage","onLoadCallback","onload","onerror","src","substring","loadImageInDom","div","createElement","style","position","appendChild","querySelector","parentNode","removeChild","enlivenObjects","reviver","enlivenedObjects","numLoadedObjects","numTotalObjects","onLoaded","fromObject","error","enlivenObjectEnlivables","enlivenProps","Object","ENLIVEN_PROPS","map","enlivedProps","enlivenPatterns","patterns","numLoadedPatterns","numPatterns","enlivenedPatterns","pattern","groupSVGElements","elements","path","sourcePath","centerPoint","Group","populateWithProperties","destination","properties","Array","isArray","createCanvasElement","copyCanvasElement","newCanvas","toDataURL","canvasEl","format","quality","multiplyTransformMatrices","is2x2","qrDecompose","denom","skewX","skewY","translateX","translateY","theta","calcDimensionsMatrix","scaleMatrix","flipX","flipY","tan","composeMatrix","matrix","resetObjectTransform","target","rotate","saveObjectTransform","isTransparent","tolerance","_isTransparent","imageData","getImageData","l","data","parsePreserveAspectRatioAttribute","attribute","align","meetOrSlice","aspectRatioAttrs","pop","alignX","alignY","clearFabricFontCache","fontFamily","toLowerCase","limitDimsByArea","ar","maximumArea","roughWidth","perfLimitSizeY","capValue","findScaleToFit","findScaleToCover","matrixToSVG","NUM_FRACTION_DIGITS","join","removeTransformFromObject","inverted","finalTransform","calcOwnMatrix","applyTransformToObject","addTransformToObject","center","setPositionByOrigin","sizeAfterTransform","dimX","dimY","transformMatrix","bbox","mergeClipPaths","c1","c2","calcTransformMatrix","clipPath","hasStyleChanged","prevStyle","thisStyle","forTextSpans","stroke","fontWeight","fontStyle","textBackgroundColor","deltaY","overline","underline","linethrough","stylesToArray","styles","text","textLines","charIndex","stylesArray","c","keys","start","end","stylesFromArray","styleIndex","stylesObject","assign","_join","prototype","commandLengths","m","h","q","repeatedCommands","M","segmentToBezier","th2","th3","cosTh","sinTh","rx","ry","cx1","cy1","mT","fromX","fromY","costh2","sinth2","costh3","sinth3","toX","toY","calcVectorAngle","ux","uy","vx","vy","ta","tb","fromArcToBeziers","fx","fy","rot","large","sweep","segsNorm","rotateX","th","px","py","rx2","abs","ry2","py2","px2","pl","root","cx","cy","mTheta","dtheta","segments","ceil","result","mDelta","arcToSegments","calcLineLength","x1","y1","x2","y2","getPointOnCubicBezierIterator","p1x","p1y","p2x","p2y","p3x","p3y","p4x","p4y","pct","CB2","c3","CB3","c4","CB4","getTangentCubicIterator","invT","tangentX","tangentY","getPointOnQuadraticBezierIterator","QB2","QB3","getTangentQuadraticIterator","pathIterator","iterator","perc","tempP","tmpLen","findPercentageForDistance","segInfo","distance","nextLen","lastPerc","nextStep","angleFinder","getPathSegmentsInfo","tempInfo","totalLength","info","command","destX","destY","joinPath","pathData","segment","parsePath","pathString","currentPath","parsed","match","coordsStr","re","rNumber","rNumberCommaWsp","rFlagCommaWsp","regArcArgumentSequence","RegExp","coordsParsed","trim","args","j","jlen","isNaN","commandLength","repeatedCommand","k","klen","makePathSimpler","converted","previous","controlX","controlY","destinationPath","getSmoothPathFromPoints","correction","p1","p2","multSignX","multSignY","manyPoints","eq","midPoint","midPointFrom","getBoundsOfCurve","x0","y0","x3","y3","argsString","t1","t2","b2ac","sqrtb2ac","tvalues","bounds","mt","getPointOnPath","infos","segPercent","lerp","transformPath","pathOffset","pathSegment","newSegment","find","byProperty","condition","invoke","method","value1","value2","extend","Element","hasOwnProperty","getWholeChar","str","code","charCodeAt","next","prev","replace","character","capitalize","firstLetterOnly","escapeXml","graphemeSplit","textstring","chr","graphemes","emptyFunction","IS_DONTENUM_BUGGY","toString","addMethods","klass","parent","superclass","constructor","returnValue","valueOf","Subclass","callSuper","methodName","parentMethod","_this","superClassMethod","createClass","initialize","shift","subclasses","attachEvent","addListener","element","addEventListener","removeListener","removeEventListener","getPointer","event","scroll","getScrollLeftTop","_evt","touchProp","changedTouches","getTouchInfo","clientX","clientY","isTouchEvent","pointerType","opacity","es","currentStyle","hasLayout","zoom","test","setStyle","elementStyle","cssText","normalizedProperty","styleFloat","setProperty","_slice","sliceCanConvertNodelists","getElementStyle","selectProp","toArray","arrayLike","childNodes","err","makeElement","tagName","el","className","htmlFor","setAttribute","docElement","documentElement","body","scrollLeft","scrollTop","host","nodeType","arr","defaultView","getComputedStyle","attr","undefined","makeElementUnselectable","onselectstart","unselectable","makeElementSelectable","setImageSmoothing","imageSmoothingEnabled","webkitImageSmoothingEnabled","mozImageSmoothingEnabled","msImageSmoothingEnabled","oImageSmoothingEnabled","getById","id","getElementById","addClass","wrapElement","wrapper","replaceChild","getElementOffset","docElem","scrollLeftTop","doc","ownerDocument","box","offset","offsetAttributes","borderLeftWidth","borderTopWidth","paddingLeft","paddingTop","parseInt","getBoundingClientRect","clientLeft","clientTop","getNodeCanvas","impl","_canvas","_image","cleanUpJsdomNode","_currentSrc","_attributes","_classList","emptyFn","request","onComplete","xhr","XMLHttpRequest","parameters","onreadystatechange","readyState","param","addParamToUrl","open","setRequestHeader","send","warn","RUNNING_ANIMATIONS","noop","defaultEasing","d","cancelAll","animations","animation","cancel","cancelByCanvas","cancelled","cancelByTarget","findAnimationsByTarget","findAnimationIndex","cancelFunc","findAnimation","_requestAnimFrame","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","oRequestAnimationFrame","msRequestAnimationFrame","setTimeout","_cancelAnimFrame","cancelAnimationFrame","clearTimeout","requestAnimFrame","animate","removeFromRegistry","runningAnimations","currentValue","startValue","completionRate","durationRate","timestamp","time","Date","duration","finish","onChange","abort","easing","isMany","endValue","byValue","onStart","tick","ticktime","currentTime","timePerc","_value","valuePerc","cancelAnimFrame","calculateColor","begin","pos","color","animateColor","fromColor","toColor","startColor","Color","getSource","endColor","originalOnComplete","originalOnChange","colorEasing","normalize","asin","elastic","opts","easeInBounce","easeOutBounce","ease","easeInQuad","easeOutQuad","easeInOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","easeInSine","easeOutSine","easeInOutSine","easeInExpo","easeOutExpo","easeInOutExpo","easeInCirc","easeOutCirc","easeInOutCirc","easeInElastic","easeOutElastic","easeInOutElastic","easeInBack","easeOutBack","easeInOutBack","easeInOutBounce","attributesMap","display","visibility","colorAttributes","normalizeAttr","normalizeValue","parentAttributes","parseTransformAttribute","visible","fillIndex","strokeIndex","getSvgRegex","_getMultipleNodes","nodeNames","nodeName","nodeList","nodeArray","getElementsByTagName","elementMatchesRule","selectors","firstMatching","parentMatching","selectorMatches","selector","doesSomeParentMatch","matcher","classNames","getAttribute","elementById","node","nodelist","svgValidTagNamesRegEx","svgViewBoxElementsRegEx","svgInvalidAncestorsRegEx","svgValidParentsRegEx","cssRules","gradientDefs","clipPaths","skewMatrix","reTransformList","reTransform","attributeValue","matrices","operation","translateMatrix","rotateMatrix","multiplierX","multiplierY","combinedMatrix","reViewBoxAttrValue","applyViewboxTransform","viewBoxWidth","viewBoxHeight","viewBoxAttr","widthAttr","heightAttr","preserveAspectRatio","missingViewBox","missingDimAttr","toBeParsed","parsedDim","widthDiff","heightDiff","removeAttribute","createElementNS","firstChild","recursivelyParseGradientsXlink","gradient","referencedGradient","hasAttribute","children","referenceClone","cloneNode","parseSVGDocument","parsingOptions","xlinkAttribute","attrs","xlink","el2","currentTrans","oldLength","el3","setAttributeNS","nodeValue","parseUseDirectives","svgUid","__uid","descendants","selectNodes","hasAncestorWithNodeName","getGradientDefs","getCSSRules","parseElements","instances","reFontDeclaration","parseFontDeclaration","oStyle","lineHeight","elList","parseAttributes","parentFontSize","ownAttributes","cssAttrs","rule","getGlobalStylesForElement","parseStyleAttribute","normalizedAttr","normalizedValue","normalizedStyle","font","mergedAttrs","setAlpha","getAlpha","toRgba","_setStrokeFillOpacity","ElementsParser","parse","chunk","pair","parseStyleString","parseStyleObject","parsePointsAttribute","parsedPoints","allRules","styleContents","textContent","ruleObj","propertyValuePairs","_rule","loadSVGFromURL","xml","responseXML","results","_options","allElements","loadSVGFromString","parseFromString","regexUrl","numElements","createObjects","createObject","findTag","fromElement","createCallback","checkIfDone","resolveGradient","Image","_originalElement","_removeTransformMatrix","resolveClipPath","extractPropertyDefinition","storage","regex","lastIndex","gradientDef","opacityAttr","createClipPathCallback","container","_newObj","fillRule","clipRule","usingElement","objTransformInv","gTransform","clipPathTag","clipPathOwner","that","scalarAdd","scalarAddEquals","subtractEquals","scalarSubtract","scalarSubtractEquals","multiplyEquals","divide","divideEquals","lt","lte","gt","gte","distanceFrom","dx","dy","setXY","setX","setY","setFromPoint","swap","Intersection","status","appendPoint","appendPoints","intersectLineLine","a1","a2","b1","b2","uaT","ubT","uB","ua","ub","intersectLinePolygon","inter","intersectPolygonPolygon","points1","points2","intersectPolygonRectangle","r1","r2","topRight","bottomLeft","inter1","inter2","inter3","inter4","_tryParsingColor","setSource","hue2rgb","colorNameMap","sourceFromHex","sourceFromRgb","sourceFromHsl","_rgbToHsl","g","round","_source","toRgb","toHsl","hsl","toHsla","toHex","toHexa","toGrayscale","average","currentAlpha","toBlackWhite","threshold","overlayWith","otherColor","otherSource","reRGBa","reHSLa","reHex","aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgrey","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgrey","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen","fromRgb","fromSource","fromRgba","fromHsl","fromHsla","fromHex","isShortNotation","isRGBa","oColor","scaleMap","skewMap","controls","LEFT","TOP","opposite","bottom","right","findCornerQuadrant","fabricObject","control","cornerAngle","fireEvent","canvasOptions","scaleIsProportional","eventData","uniformIsToggled","uniScaleKey","uniformScaling","isTransformCentered","originX","originY","scalingIsForbidden","by","scaleProportionally","lockX","lockScalingX","lockY","lockScalingY","commonEventInfo","e","pointer","wrapWithFixedAnchor","actionHandler","getCenterPoint","constraint","translateToOriginPoint","actionPerformed","wrapWithFireEvent","getLocalPoint","corner","getZoom","padding","localPoint","toLocalPoint","offsetX","offsetY","targetHasOneFlip","compensateScaleForSkew","oppositeSkew","scaleToCompensate","axis","reference","newValue","_getTransformedDimensions","skewObjectX","newSkew","dimNoSkew","totalSkewSize","currentSkew","hasSkewed","dimBeforeSkewing","skewObjectY","scaleObject","dim","signX","signY","forbidScaling","gestureScale","lockScalingFlip","original","oldScaleX","oldScaleY","scaleCursorStyleHandler","n","skewCursorStyleHandler","lockSkewingY","lockSkewingX","scaleSkewCursorStyleHandler","altActionKey","rotationWithSnapping","pivotPoint","lockRotation","hasRotated","lastAngle","ey","ex","curAngle","snapAngle","snapThreshold","rightAngleLocked","leftAngleLocked","scalingEqually","scalingX","scalingY","scalingYOrSkewingX","skewHandlerX","scalingXOrSkewingY","skewHandlerY","changeWidth","strokePadding","multiplier","oldWidth","newWidth","finalHandler","dragHandler","newLeft","newTop","moveX","moveY","scaleOrSkewActionName","isAlternative","rotationStyleHandler","cursorStyle","controlsUtils","renderCircleControl","styleOverride","xSize","sizeX","cornerSize","ySize","sizeY","transparentCorners","cornerStrokeColor","myLeft","myTop","save","fillStyle","cornerColor","strokeStyle","lineWidth","beginPath","arc","restore","renderSquareControl","xSizeBy2","ySizeBy2","strokeRect","Control","actionName","touchSizeX","touchSizeY","withConnection","mouseDownHandler","mouseUpHandler","getActionHandler","getMouseDownHandler","getMouseUpHandler","cursorStyleHandler","getActionName","getVisibility","controlKey","objectVisibility","_controlsVisibility","setVisibility","positionHandler","finalMatrix","calcCornerCoords","objectAngle","objectCornerSize","centerX","centerY","isTouch","cosHalfOffset","sinHalfOffset","cosHalfOffsetComp","sinHalfOffsetComp","controlTriangleAngle","cornerHypotenuse","newTheta","newThetaComp","tl","tr","bl","br","render","cornerStyle","getColorStop","colorAlpha","keyValuePairs","gradientTransform","gradientUnits","option","addColorStop","toObject","propertiesToInclude","toSVG","markup","commonAttributes","needsSwap","withViewport","additionalTransform","sort","reverse","minRadius","percentageShift","colorStop","toLive","createLinearGradient","createRadialGradient","instance","svgOptions","colorStopEls","getLinearCoords","getRadialCoords","propValue","finalValue","__convertPercentUnitsToValues","repeat","patternTransform","setOptions","isError","patternSource","patternWidth","patternHeight","patternOffsetX","patternOffsetY","patternImgSrc","complete","naturalWidth","naturalHeight","createPattern","Shadow","blur","affectStroke","includeDefaultValues","nonScaling","_parseShadow","shadow","shadowStr","offsetsAndBlur","reOffsetsAndBlur","fBoxX","fBoxY","StaticCanvas","CANVAS_INIT_ERROR","Error","renderAndResetBound","renderAndReset","requestRenderAllBound","_initStatic","backgroundColor","backgroundImage","overlayColor","overlayImage","stateful","controlsAboveOverlay","allowTouchScrolling","viewportTransform","backgroundVpt","overlayVpt","enableRetinaScaling","vptCoords","skipOffscreen","cb","_createLowerCanvas","_initOptions","interactive","_initRetinaScaling","setOverlayImage","setBackgroundImage","setBackgroundColor","setOverlayColor","calcOffset","_isRetinaScaling","getRetinaScaling","scaleRatio","__initRetinaScaling","lowerCanvasEl","contextContainer","upperCanvasEl","contextTop","_offset","image","__setBgOverlayImage","__setBgOverlayColor","_createCanvasElement","_originalCanvasStyle","_applyCanvasStyle","getWidth","getHeight","setWidth","setDimensions","setHeight","dimensions","cssValue","cssOnly","_setBackstoreDimension","hasLostContext","backstoreOnly","_setCssDimension","_isCurrentlyDrawing","freeDrawingBrush","_setBrushStyles","cacheCanvasEl","wrapperEl","setViewportTransform","vpt","activeObject","_activeObject","backgroundObject","overlayObject","group","setCoords","calcViewportBoundaries","zoomToPoint","before","after","setZoom","absolutePan","relativePan","getElement","setupState","clearContext","clearRect","clear","_hasITextHandlers","_mouseUpITextHandler","_iTextInstances","renderAll","canvasToDrawOn","renderCanvas","isRendering","iVpt","cancelRequestedRender","_renderBackground","_renderObjects","drawControls","shouldCache","_transformDone","renderCache","forClipping","drawClipPathOnCanvas","_renderOverlay","globalCompositeOperation","zoomX","zoomY","_cacheCanvas","cacheTranslationX","cacheTranslationY","_renderBackgroundOrOverlay","needsVpt","moveTo","lineTo","closePath","getCenter","centerObjectH","_centerObject","centerObjectV","centerObject","viewportCenterObject","vpCenter","getVpCenter","viewportCenterObjectH","viewportCenterObjectV","toDatalessJSON","toDatalessObject","_toObjectMethod","_toObjects","excludeFromExport","_toObject","__serializeBgOverlay","originalValue","bgImage","bgColor","background","overlay","svgViewportTransformation","_setSVGPreamble","_setSVGHeader","clipPathId","_setSVGBgOverlayColor","_setSVGBgOverlayImage","_setSVGObjects","suppressPreamble","encoding","viewBox","createSVGFontFacesMarkup","createSVGRefElementsMarkup","createSVGClipPathMarkup","toClipPathSVG","shouldTransform","row","rowIndex","fontList","_setSVGObject","finalWidth","finalHeight","sendToBack","objs","activeSelection","unshift","bringToFront","sendBackwards","intersecting","newIdx","objsMoved","_findNewLowerIndex","intersectsWithObject","isContainedWithinObject","bringForward","_findNewUpperIndex","dispose","classList","DataURLExporter","EMPTY_JSON","supports","setLineDash","toJSON","createPNGStream","createJPEGStream","BaseBrush","strokeLineCap","strokeDashArray","limitedToCanvasSize","lineCap","miterLimit","lineJoin","_saveAndTransform","_setShadow","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY","needsFullRender","_resetShadow","_isOutSideCanvas","PencilBrush","decimate","drawStraightLine","straightLineKey","_points","_hasStraightLine","_drawSegment","quadraticCurveTo","onMouseDown","_isMainEvent","_prepareForDrawing","_captureDrawingPath","_render","onMouseMove","oldEnd","onMouseUp","_finalizeAndAddPath","_reset","_addPoint","pointerPoint","convertPointsToSVGPath","_isEmptySVGPath","createPath","Path","decimatePoints","adjustedDistance","lastPoint","newPoints","CircleBrush","drawDot","addPoint","dot","radius","originalRenderOnAddRemove","circles","circle","Circle","circleRadius","circleColor","SprayBrush","density","dotWidth","dotWidthVariance","randomOpacity","optimizeOverlapping","sprayChunks","addSprayChunk","sprayChunkPoints","rects","ilen","sprayChunk","rect","Rect","_getOptimizedRects","uniqueRects","uniqueRectsArray","globalAlpha","fillRect","PatternBrush","getPatternSrc","patternCanvas","patternCtx","getPatternSrcFunction","String","getPattern","topLeft","_getLeftTopCoords","Canvas","_initInteractive","_createCacheCanvas","centeredScaling","centeredRotation","centeredKey","selection","selectionKey","altSelectionKey","selectionColor","selectionDashArray","selectionBorderColor","selectionLineWidth","selectionFullyContained","hoverCursor","moveCursor","defaultCursor","freeDrawingCursor","notAllowedCursor","containerClass","perPixelTargetFind","targetFindTolerance","skipTargetFind","isDrawingMode","preserveObjectStacking","stopContextMenu","fireRightClick","fireMiddleClick","targets","enablePointerEvents","_hoveredTarget","_hoveredTargets","_currentTransform","_groupSelector","_initWrapperElement","_createUpperCanvas","_initEventListeners","_chooseObjectsToRender","objsToRender","activeGroupObjects","activeObjects","getActiveObjects","contextTopDirty","renderTopLayer","_drawSelection","renderTop","_normalizePointer","invertedM","vptPointer","restorePointerVpt","isTargetTransparent","normalizedPointer","targetRelativeX","targetRelativeY","_cacheContext","contextCache","originalColor","selectionBackgroundColor","_isSelectionKeyPressed","_shouldClearSelection","evented","selectable","_shouldCenterTransform","action","altKey","centerTransform","_getOriginFromCorner","_getActionFromCorner","alreadySelected","_setupCurrentTransform","__corner","lastX","lastY","shiftKey","_beforeTransform","setCursor","cursor","viewportStart","viewportExtent","extent","maxX","maxY","strokeOffset","_setLineDash","findTarget","skipGroup","activeTarget","activeTargetSubs","aObjects","shouldLookForActive","_findTargetCorner","_searchPossibleTargets","_checkTarget","globalPointer","containsPoint","isEditing","subTarget","objToCheck","pointerToUse","subTargetCheck","ignoreZoom","_absolutePointer","_pointer","cssScale","boundsWidth","boundsHeight","retinaScaling","lowerCanvasClass","_copyCanvasStyle","getTopContext","fromEl","toEl","getSelectionContext","getSelectionElement","getActiveObject","active","_discardActiveObject","_fireSelectionEvents","oldObjects","somethingChanged","added","removed","oldObject","selected","deselected","setActiveObject","currentActives","_setActiveObject","onSelect","onDeselect","discardActiveObject","removeListeners","_renderControls","originalProperties","_realizeGroupTransformOnObject","_unwindGroupTransformOnObject","originalValues","clearContextTop","addEventOptions","passive","checkClick","button","mainTouchId","_bindEvents","addOrRemove","_getEventPrefix","functor","eventjsFunctor","canvasElement","eventTypePrefix","_onResize","_onMouseDown","_onMouseMove","_onMouseOut","_onMouseEnter","_onMouseWheel","_onContextMenu","_onDoubleClick","_onDragOver","_onDragEnter","_onDragLeave","_onDrop","_onTouchStart","eventjs","_onGesture","_onDrag","_onOrientationChange","_onShake","_onLongPress","_onMouseUp","_onTouchEnd","eventsBound","_simpleEventHandler","self","__onTransformGesture","__onDrag","__onMouseWheel","_target","__onOrientationChange","__onShake","__onLongPress","preventDefault","_fireEnterLeaveEvents","stopPropagation","_cacheTransformEventData","_handleEvent","_resetTransformEventData","getPointerId","evt","identifier","pointerId","isPrimary","touches","__onMouseDown","__onMouseUp","_willAddMouseDown","__onMouseMove","_shouldRender","groupSelector","shouldRender","isClick","_onMouseUpInDrawingMode","_finalizeCurrentTransform","targetWasActive","_maybeGroupObjects","activeOn","isMoving","originalControl","originalMouseUpHandler","_setCursorFromEvent","eventType","subTargets","absolutePointer","currentTarget","currentSubTargets","_scaling","hasStateChanged","_fire","_onMouseDownInDrawingMode","_onMouseMoveInDrawingMode","_previousPointer","shouldGroup","_shouldGroup","_handleGrouping","saveState","_transformObject","_fireOverOutEvents","fireSyntheticInOutEvents","oldTarget","evtOut","canvasEvtOut","evtIn","canvasEvtIn","_draggedoverTarget","config","inOpt","outOpt","inFires","targetChanged","previousTarget","nextTarget","reset","_performTransformAction","getCornerCursor","_updateActiveSelection","_createActiveSelection","currentActiveObjects","removeWithUpdate","addWithUpdate","_createGroup","groupObjects","exitEditing","ActiveSelection","_groupSelectedObjects","aGroup","_collectObjects","currentObject","selectionX1Y1","selectionX2Y2","allowIntersect","intersectsWithRect","isContainedWithinRect","toCanvasElement","cropping","scaledWidth","scaledHeight","originalWidth","originalHeight","newZoom","vp","originalInteractive","newVp","originalRetina","originalContextTop","loadFromJSON","json","serialized","JSON","_enlivenObjects","_setBgOverlay","enlivenedCanvasClip","__setupCanvas","loaded","cbIfLoaded","__setBgOverlay","enlivedObject","_toDataURL","_toDataURLWithMultiplier","toDataURLWithMultiplier","stringify","cloneWithoutData","backgroundImageOpacity","backgroundImageStretch","objectCaching","touchCornerSize","borderColor","borderDashArray","cornerDashArray","strokeDashOffset","borderOpacityWhenMoving","borderScaleFactor","minScaleLimit","hasControls","hasBorders","lockMovementX","lockMovementY","statefullCache","noScaleCache","dirty","paintFirst","stateProperties","cacheProperties","colorProperties","absolutePositioned","_cacheProperties","_updateCacheCanvas","_limitCacheSize","dims","limitedDims","capped","_getCacheCanvasDimensions","objectScale","getTotalObjectScaling","neededX","neededY","drawingWidth","drawingHeight","dimensionsChanged","cacheWidth","cacheHeight","zoomChanged","setTransform","needFullTransform","_removeDefaultValues","getObjectScaling","retina","getObjectOpacity","shouldConstrainValue","isChanged","groupNeedsUpdate","_constrainScale","isOnACache","setOnGroup","getViewportTransform","isNotVisible","isOnScreen","_setupCompositeOperation","drawSelectionBackground","_setOpacity","drawCacheOnCanvas","_removeCacheCanvas","drawObject","propertySet","isCacheDirty","hasStroke","hasFill","needsItsOwnCache","ownCaching","willDrawShadow","drawClipPathOnCache","originalFill","originalStroke","_setClippingProperties","_drawClipPath","skipCanvas","_getNonTransformedDimensions","_removeShadow","_setStrokeStyles","decl","lineDashOffset","_applyPatternForTransformedGradient","_applyPatternGradientTransform","_setFillStyles","dashArray","drawBorders","forActiveSelection","drawBordersInGroup","scaling","multX","multY","_renderPaintInOrder","_renderStroke","_renderFill","pCtx","pCanvas","_findCenterFromElement","_assignTransformMatrixProps","preserveAspectRatioOptions","cropX","cropY","offsetLeft","offsetTop","objectForm","_fromObject","cloneAsImage","utils","origParams","originalGroup","originalShadow","withoutTransform","withoutShadow","boundingRect","getBoundingRect","shadowOffset","originalCanvas","isType","includes","shouldCenterOrigin","_setOriginToCenter","_resetOrigin","centerH","viewportCenterH","centerV","viewportCenterV","viewportCenter","getLocalPointer","pClicked","objectLeftTop","createAccessors","extraParam","translateToGivenOrigin","fromOriginX","fromOriginY","toOriginX","toOriginY","translateToCenterPoint","leftTop","getPointByOrigin","adjustPosition","offsetFrom","offsetTo","hypotFull","getScaledWidth","xFull","yFull","_originalOriginX","_originalOriginY","originPoint","multiplyMatrices","oCoords","aCoords","lineCoords","ownMatrixCache","matrixCache","_getCoords","absolute","calculate","calcACoords","calcLineCoords","getCoords","pointTL","pointBR","other","otherCoords","lines","_getImageLines","_findCrossPoints","_containsCenterOfCanvas","isPartiallyOnScreen","every","topline","rightline","bottomline","leftline","xi","iLine","xcount","lineKey","getScaledHeight","scaleToWidth","boundingRectFactor","scaleToHeight","cosP","sinP","cosPSinP","cosPMinusSinP","calcOCoords","_calcRotateMatrix","_calcTranslateMatrix","startMatrix","_calculateCurrentDimensions","forEachControl","w","skipCorners","_setCornerCoords","transformMatrixKey","prefix","cache","tMatrix","noSkew","_finalizeDimensions","getSvgColorString","getSvgStyles","skipShadow","getSvgFilter","getSvgSpanStyles","useWhiteSpace","textDecoration","getSvgTextDecoration","decoration","getSvgCommons","getSvgTransform","full","_setSVGBg","textBgRects","_getFillAttributes","_createBaseSVGMarkup","_toSVG","_createBaseClipPathSVGMarkup","objectMarkup","commonPieces","clipPathMarkup","noStyle","styleInfo","shadowInfo","withShadow","vectorEffect","absoluteClipPath","addPaintOrder","saveProps","props","tmpObj","_isEqual","origValue","firstPass","dashedPropertySet","forTouch","isControlVisible","touchCorner","fn","controlObject","wh","shouldStroke","setControlVisible","setControlsVisibility","FX_DURATION","fxCenterObjectH","callbacks","empty","fxCenterObjectV","fxRemove","skipCallbacks","propsToAnimate","out","_animate","propPair","propIsColor","valueProgress","timeProgress","coordProps","makeEdgeToOriginGetter","propertyNames","originValues","axis1","axis2","dimension","nearest","farthest","Line","_setWidthHeight","_getLeftToOriginX","_getTopToOriginY","calcLinePoints","origStrokeStyle","xMult","yMult","ATTRIBUTE_NAMES","parsedAttributes","startAngle","endAngle","setRadius","svgString","getRadiusX","getRadiusY","Triangle","widthBy2","heightBy2","piBy2","Ellipse","getRx","getRy","_initRxRy","isRounded","bezierCurveTo","Polyline","exactBoundingBox","_setPositionDimensions","_projectStrokeOnPoints","correctLeftTop","calcDim","_calcDimensions","correctSize","fromSVG","diffX","diffY","commonRender","fromElementGenerator","_class","Polygon","_setPath","_renderPathCommands","subpathStartX","subpathStartY","_getOffsetTransform","digits","aX","aY","pathUrl","elivenedObjects","useSetOnGroup","isAlreadyGrouped","_updateObjectsACoords","_calcBounds","_updateObjectsCoords","_updateObjectCoords","objectLeft","objectTop","nested","_restoreObjectsState","_includeDefaultValues","objsToObject","originalDefaults","_obj","ownCache","groupMatrix","destroy","toActiveSelection","ungroupOnCanvas","setObjectsCoords","onlyWidthHeight","iLen","jLen","_getBounds","minXY","maxXY","toGroup","newGroup","childrenOverride","srcFromAttribute","_lastScaleX","_lastScaleY","_filterScalingX","_filterScalingY","minimumScaleTrigger","cacheKey","imageSmoothing","filters","_initElement","_element","setElement","removeTexture","_initConfig","applyFilters","resizeFilter","applyResizeFilters","backend","filterBackend","evictCachesForKey","getCrossOrigin","getOriginalSize","_stroke","filterObj","getSrc","hasCrop","strokeSvg","imageMarkup","imageRendering","getSvgSrc","origFill","filtered","setSrc","minimumScale","elementToFilter","_filteredEl","sourceWidth","sourceHeight","isNeutralState","imgElement","_needsResize","elementToDraw","elWidth","elHeight","sX","sY","sW","sH","maxDestW","maxDestH","_resetWidthHeight","CSS_CANVAS","_initFilters","pAR","rWidth","rHeight","pWidth","pHeight","_object","resizeFilters","fromURL","imgOptions","_getAngleValueForStraighten","straighten","fxStraighten","straightenObject","fxStraightenObject","testPrecision","precision","fragmentSource","fragmentShader","createShader","FRAGMENT_SHADER","shaderSource","compileShader","getShaderParameter","COMPILE_STATUS","setupGLContext","captureGPUInfo","isSupported","getParameter","MAX_TEXTURE_SIZE","precisions","webGlPrecision","createWebGLCanvas","aPosition","Float32Array","chooseFastestCopyGLTo2DMethod","canUseImageData","canMeasurePerf","performance","canUseArrayBuffer","ArrayBuffer","canUseUint8Clamped","copyGLTo2D","startTime","drawImageTime","testContext","now","glOptions","premultipliedAlpha","depth","stencil","antialias","clearColor","cachedTexture","getCachedTexture","sourceTexture","createTexture","targetTexture","originalTexture","passes","webgl","programCache","pass","tempFbo","createFramebuffer","bindFramebuffer","FRAMEBUFFER","applyTo","resizeCanvasIfNeeded","bindTexture","TEXTURE_2D","deleteTexture","deleteFramebuffer","clearWebGLCaches","textureCache","textureImageSource","filterType","texture","texParameteri","TEXTURE_MAG_FILTER","NEAREST","TEXTURE_MIN_FILTER","TEXTURE_WRAP_S","CLAMP_TO_EDGE","TEXTURE_WRAP_T","texImage2D","uniqueId","gpuInfo","renderer","vendor","ext","getExtension","UNMASKED_RENDERER_WEBGL","UNMASKED_VENDOR_WEBGL","sourceElement","originalEl","originalImageData","BaseFilter","vertexSource","createProgram","vertexShader","VERTEX_SHADER","getShaderInfoLog","program","attachShader","linkProgram","getProgramParameter","LINK_STATUS","getProgramInfoLog","attributeLocations","getAttributeLocations","uniformLocations","getUniformLocations","uStepW","getUniformLocation","uStepH","getAttribLocation","sendAttributeData","aPositionData","attributeLocation","buffer","createBuffer","bindBuffer","ARRAY_BUFFER","enableVertexAttribArray","vertexAttribPointer","FLOAT","bufferData","STATIC_DRAW","_setupFrameBuffer","framebufferTexture2D","COLOR_ATTACHMENT0","_swapTextures","temp","main","mainParameter","applyToWebGL","applyTo2d","retrieveShader","shader","useProgram","uniform1f","sendUniformData","viewport","drawArrays","TRIANGLE_STRIP","bindAdditionalTexture","textureUnit","activeTexture","TEXTURE0","unbindAdditionalTexture","getMainParameter","setMainParameter","createHelpLayer","helpLayer","mainP","ColorMatrix","colorsOnly","uColorMatrix","uConstants","constants","uniformMatrix4fv","uniform4fv","Brightness","brightness","uBrightness","Convolute","opaque","Convolute_3_1","Convolute_3_0","Convolute_5_1","Convolute_5_0","Convolute_7_1","Convolute_7_0","Convolute_9_1","Convolute_9_0","dstOff","scx","scy","srcOff","wt","weights","side","halfSide","sw","sh","output","createImageData","dst","alphaFac","uMatrix","uOpaque","uHalfSize","uSize","uniform1fv","Grayscale","lightness","luminosity","mode","uMode","uniform1i","Invert","invert","uInvert","Noise","noise","rand","uNoise","uSeed","Pixelate","blocksize","_i","_j","_iLen","_jLen","uBlocksize","RemoveColor","useAlpha","lowC","highC","uLow","uHigh","Brownie","Vintage","Kodachrome","Technicolor","Polaroid","Sepia","BlackWhite","BlendColor","screen","diff","lighten","darken","exclusion","tint","buildSource","tg","alpha1","uColor","BlendImage","mask","TEXTURE1","calculateMatrix","canvas1","blendData","blendImage","uTransformMatrix","uImage","uniformMatrix3fv","Resize","resizeType","lanczosLobes","uDelta","uTaps","uniform2fv","horizontal","taps","filterWindow","getFilterWindow","generateShader","tempScale","getTaps","lobeFunction","lanczosCreate","offsets","fragmentSourceTOP","dW","dH","lobes","xx","rcpScaleX","rcpScaleY","newData","oW","oH","sliceByTwo","hermiteFastResize","bilinearFiltering","lanczosResize","tmpCanvas","doneW","doneH","stepW","stepH","dX","dY","srcData","destImg","destData","lanczos","ratioX","ratioY","rcpRatioX","rcpRatioY","range2X","range2Y","cacheLanc","icenter","process","u","weight","fX","fY","xDiff","yDiff","chnl","origPix","w4","pixels","destImage","destPixels","ratioW","ratioH","ratioWHalf","ratioHHalf","img2","data2","weightsAlpha","gxR","gxG","gxB","gxA","yy","w0","Contrast","contrast","contrastF","uContrast","Saturation","saturation","adjust","uSaturation","Vibrance","vibrance","avg","amt","uVibrance","Blur","aspectRatio","simpleBlur","canvas2","blurLayer1","blurLayer2","percent","ctx1","ctx2","newImageData","delta","chooseRightDelta","blurScale","Gamma","gamma","rInv","gInv","bInv","rVals","gVals","bVals","uGamma","uniform3fv","Composed","subFilters","HueRotation","rotation","rad","aThird","aThirdSqtSin","OneMinusCos","additionalProps","_dimensionAffectingProps","_reNewline","_reSpacesAndTabs","_reSpaceAndTab","_reWords","textAlign","superscript","baseline","subscript","pathStartOffset","pathSide","pathAlign","_fontSizeFraction","_fontSizeMult","charSpacing","_measuringContext","direction","_styleProperties","__charBounds","CACHE_FONT_SIZE","MIN_TEXT_WIDTH","__skipDimension","setPathInfo","initDimensions","segmentsInfo","getMeasuringContext","_splitText","newLines","_splitTextIntoLines","_textLines","graphemeLines","_unwrappedTextLines","_unwrappedLines","_text","graphemeText","_clearCache","additionalWidth","getHeightOfLine","calcTextWidth","cursorWidth","calcTextHeight","enlargeSpaces","diffSpace","currentLineWidth","numberOfSpaces","accumulatedSpace","line","charBound","spaces","isEndOfWrapping","getLineWidth","kernedWidth","lineIndex","missingNewlineOffset","_setTextStyles","_renderTextLinesBackground","_renderTextDecoration","_renderText","_renderTextStroke","_renderTextFill","charStyle","forMeasuring","textBaseline","_getFontDeclaration","maxWidth","_renderTextLine","_renderChars","styleHas","heightOfLine","lineLeftOffset","lastColor","charBox","currentColor","drawStart","leftOffset","_getLeftOffset","lineTopOffset","_getTopOffset","boxStart","boxWidth","_getLineLeftOffset","getValueOfPropertyAt","renderLeft","getFontCache","cacheProp","_measureChar","_char","previousChar","prevCharStyle","coupleWidth","previousWidth","fontCache","couple","stylesAreEqual","fontMultiplier","measureText","getHeightOfChar","measureLine","lineInfo","_measureLine","_getWidthOfCharSpacing","grapheme","prevGrapheme","graphemeInfo","startingPoint","totalPathLength","lineBounds","positionInPath","_getGraphemeBox","_setGraphemeOnPath","numOfSpaces","centerPosition","skipLeft","getCompleteStyleDeclaration","previousBox","__lineHeights","maxHeight","_renderTextCommon","lineHeights","isEmptyStyles","actualStyle","nextStyle","timeToRender","drawingLeft","isJustify","charsToRender","shortCut","isLtr","currentDirection","_renderChar","_applyPatternGradientTransformText","handleFiller","fillOffsets","strokeOffsets","_getStyleDeclaration","fullDecl","shouldFill","fillText","strokeText","setSuperscript","_setScript","setSubscript","schema","loc","get2DCursorLocation","setSelectionStyles","lineDiff","__lineWidths","_shouldClearDimensionCache","shouldClear","_forceClearCache","_size","_dy","lastDecoration","currentDecoration","currentFill","lastFill","topOffset","styleObject","family","fontIsGeneric","genericFonts","newLine","newText","allProperties","needsDims","isAddingPath","_key","parsedAnchor","textAnchor","originalStrokeWidth","textHeightScaleFactor","scaledDiff","textHeight","offX","objectCopy","textInstance","pathInstance","p3","cleanStyle","letterCount","stylePropertyValue","stylesCount","allStyleObjectPropertiesMatch","graphemeCount","removeStyle","lineNum","charNum","_extendStyles","_getLineStyle","_setLineStyle","_setStyleDeclaration","selectionStart","skipWrapping","getSelectionStyles","startIndex","endIndex","selectionEnd","getStyleAtPosition","lineStyle","_deleteStyleDeclaration","_deleteLineStyle","parseDecoration","IText","editable","editingBorderColor","cursorColor","cursorDelay","cursorDuration","caching","hiddenTextareaContainer","_reSpace","_currentCursorOpacity","_selectionDirection","_abortCursorAnimation","__widthOfSpace","inCompositionMode","initBehavior","setSelectionStart","_updateAndFire","setSelectionEnd","_fireSelectionChanged","_updateTextarea","initDelayedCursor","cursorOffsetCache","renderCursorOrSelection","skipRestore","_clearTextArea","boundaries","_getCursorBoundaries","renderCursor","renderSelection","_getCursorBoundariesOffsets","cursorPosition","bound","cursorLocation","charHeight","__isMousedown","hiddenTextarea","startLine","endLine","startChar","endChar","realLineHeight","lineOffset","boxEnd","drawWidth","drawHeight","extraTop","compositionColor","getCurrentCharFontSize","cp","_getCurrentCharIndex","getCurrentCharColor","objCopy","initAddedHandler","initRemovedHandler","initCursorSelectionHandlers","initDoubleClickSimulation","mouseMoveHandler","_initCanvasHandlers","_removeCanvasHandlers","_tick","_currentTickState","_animateCursor","targetOpacity","completeMethod","tickState","isAborted","_onTickComplete","_cursorTimeout1","_currentTickCompleteState","restart","delay","abortCursorAnimation","_cursorTimeout2","selectAll","getSelectedText","findWordBoundaryLeft","startFrom","findWordBoundaryRight","findLineBoundaryLeft","findLineBoundaryRight","searchWordBoundary","selectWord","newSelectionStart","newSelectionEnd","selectLine","enterEditing","exitEditingOnOthers","initHiddenTextarea","focus","_saveEditingProps","_setEditingProps","_textBeforeEdit","initMouseMoveHandler","activeElement","getSelectionStartFromPointer","currentStart","currentEnd","__selectionStartOnMouseDown","restartCursorIfNeeded","fromStringToGraphemeSelection","smallerTextStart","graphemeStart","smallerTextEnd","fromGraphemeToStringSelection","newSelection","updateTextareaPosition","updateFromTextArea","_calcTextareaPosition","desiredPosition","compositionStart","upperCanvas","upperCanvasWidth","upperCanvasHeight","clientWidth","clientHeight","_savedProps","_restoreEditingProps","isTextChanged","_removeExtraneousStyles","removeStyleFromTo","styleObj","cursorStart","cursorEnd","lineStart","charStart","lineEnd","charEnd","shiftLineStyles","numericChar","clonedStyles","numericLine","insertNewlineStyleObject","qty","copiedStyle","currentCharStyle","newLineStyles","someStyleIsCarryingOver","originalLineLength","isEndOfLine","numIndex","styleCarriedOver","insertCharStyleObject","quantity","currentLineStyles","currentLineStylesCloned","numericIndex","newStyle","insertNewStyleBlock","insertedText","cursorLoc","addedLines","linesLength","setSelectionStartEndWithShift","setSelectionInBoundaries","__lastClickTime","__lastLastClickTime","__lastPointer","__newClickTime","newPointer","isTripleClick","_stopEvent","__lastIsEditing","__lastSelected","initMousedownHandler","initMouseupHandler","initClicks","doubleClickHandler","tripleClickHandler","_mouseDownHandler","setCursorByClick","_mouseDownHandlerBefore","currentActive","mouseOffset","prevWidth","_getNewSelectionStartFromOffset","distanceBtwLastCharAndCursor","distanceBtwNextCharAndCursor","onKeyDown","onKeyUp","onInput","copy","paste","onCompositionStart","onCompositionUpdate","onCompositionEnd","_clickHandlerInitialized","onClick","keysMap","keysMapRtl","ctrlKeysMapUp","ctrlKeysMapDown","keyMap","keyCode","ctrlKey","metaKey","stopImmediatePropagation","_copyDone","fromPaste","removedText","removeFrom","removeTo","nextText","charCount","nextCharCount","charDiff","textareaSelection","backDelete","copiedText","copiedTextStyle","compositionEnd","_getClipboardData","clipboardData","_getWidthBeforeCursor","widthBeforeCursor","getDownCursorOffset","isRight","selectionProp","_getSelectionForOffset","indexOnOtherLine","_getIndexOnLine","getUpCursorOffset","textBeforeCursor","charWidth","foundMatch","widthOfCharsOnLine","indexOnLine","leftEdge","rightEdge","offsetFromLeftEdge","moveCursorDown","_moveCursorUpOrDown","moveCursorUp","moveCursorWithShift","moveCursorWithoutShift","moveCursorLeft","_moveCursorLeftOrRight","_move","_moveLeft","_moveRight","moveCursorLeftWithoutShift","change","moveCursorLeftWithShift","moveCursorRight","moveCursorRightWithShift","moveCursorRightWithoutShift","changed","removeChars","insertChars","_getSVGLeftTopOffsets","textAndBg","_getSVGTextAndBg","textTop","textLeft","_wrapSVGTextAndBg","textSvg","lineTop","textSpans","textTopOffset","textLeftOffset","_setSVGTextLineBg","_setSVGTextLineText","_createTextCharSpan","styleDecl","shouldUseWhitespace","styleProps","fillStyles","dySpan","angleAttr","wBy2","renderPoint","_pushTextBgRect","fillColor","_getSVGLineTopOffset","lastHeight","Textbox","minWidth","dynamicMinWidth","__cachedLines","_wordJoiners","splitByGrapheme","_styleMap","_generateStyleMap","textInfo","realLineCount","realLineCharCount","isWrapping","nextOffset","shouldLimit","mapNextLine","_wrapText","desiredWidth","wrapped","_wrapLine","_measureWord","word","charOffset","_line","reservedSpace","words","infix","wordWidth","infixWidth","largestWordWidth","lineJustStarted","additionalSpace","getMinWidth","linesToKeep","scaleSkewStyleHandler","scaleStyleHandler","objectControls","ml","mr","mb","mtr","textBoxControls","ReactRouter5Adapter","useLocation","history","useHistory","location2","search","state","location"],"sourceRoot":""}