{"version":3,"file":"elements_parser.mjs","sources":["../../../src/parser/elements_parser.ts"],"sourcesContent":["import { Gradient } from '../gradient/Gradient';\nimport { Pattern } from '../Pattern/Pattern';\nimport { Group } from '../shapes/Group';\nimport { FabricImage } from '../shapes/Image';\nimport { classRegistry } from '../ClassRegistry';\nimport {\n  invertTransform,\n  multiplyTransformMatrices,\n  qrDecompose,\n} from '../util/misc/matrix';\nimport { removeTransformMatrixForSvgParsing } from '../util/transform_matrix_removal';\nimport type { FabricObject } from '../shapes/Object/FabricObject';\nimport { Point } from '../Point';\nimport { CENTER, FILL, STROKE } from '../constants';\nimport { getGradientDefs } from './getGradientDefs';\nimport { getCSSRules } from './getCSSRules';\nimport type { LoadImageOptions } from '../util';\nimport type { CSSRules, TSvgReviverCallback } from './typedefs';\nimport type { ParsedViewboxTransform } from './applyViewboxTransform';\nimport type { SVGOptions } from '../gradient';\nimport { getTagName } from './getTagName';\nimport { parseTransformAttribute } from './parseTransformAttribute';\nimport { getPatternDefs } from './getPatternDefs';\nimport { PatternOptions, SerializedPatternOptions } from '../Pattern';\n\nconst findTag = (el: Element) => {\n  let tagName = getTagName(el).toLowerCase();\n  if (tagName === 'text') tagName = 'textbox';\n\n  return classRegistry.getSVGClass(tagName);\n};\n\ntype StorageType = {\n  fill: SVGGradientElement | PatternOptions;\n  stroke: SVGGradientElement;\n  clipPath: Element[];\n};\n\ntype NotParsedFabricObject = FabricObject & {\n  fill: string;\n  stroke: string;\n  clipPath?: string;\n  clipRule?: CanvasFillRule;\n};\n\nexport class ElementsParser {\n  declare elements: Element[];\n  declare options: LoadImageOptions & ParsedViewboxTransform;\n  declare reviver?: TSvgReviverCallback;\n  declare regexUrl: RegExp;\n  declare doc: Document;\n  declare clipPaths: Record<string, Element[]>;\n  declare gradientDefs: Record<string, SVGGradientElement>;\n  declare patternDefs: Record<string, PatternOptions>;\n  declare cssRules: CSSRules;\n\n  constructor(\n    elements: Element[],\n    options: LoadImageOptions & ParsedViewboxTransform,\n    reviver: TSvgReviverCallback | undefined,\n    doc: Document,\n    clipPaths: Record<string, Element[]>,\n  ) {\n    this.elements = elements;\n    this.options = options;\n    this.reviver = reviver;\n    this.regexUrl = /^url\\(['\"]?#([^'\"]+)['\"]?\\)/g;\n    this.doc = doc;\n    this.clipPaths = clipPaths;\n    this.gradientDefs = getGradientDefs(doc);\n    this.patternDefs = getPatternDefs(doc);\n    this.cssRules = getCSSRules(doc);\n  }\n\n  parse(): Promise<Array<FabricObject | null>> {\n    return Promise.all(\n      this.elements.map((element) => this.createObject(element)),\n    );\n  }\n\n  async createObject(el: Element): Promise<FabricObject | null> {\n    const klass = findTag(el);\n    if (klass) {\n      const obj: NotParsedFabricObject = await klass.fromElement(\n        el,\n        this.options,\n        this.cssRules,\n      );\n      this.resolveGradient(obj, el, FILL);\n      // James modified\n      this.resolvePattern(obj, el, FILL);\n      this.resolveGradient(obj, el, STROKE);\n      if (obj instanceof FabricImage && obj._originalElement) {\n        removeTransformMatrixForSvgParsing(\n          obj,\n          obj.parsePreserveAspectRatioAttribute(),\n        );\n      } else {\n        removeTransformMatrixForSvgParsing(obj);\n      }\n      await this.resolveClipPath(obj, el);\n      this.reviver && this.reviver(el, obj);\n      return obj;\n    }\n    return null;\n  }\n\n  extractPropertyDefinition(\n    obj: NotParsedFabricObject,\n    property: 'fill' | 'stroke' | 'clipPath',\n    storage: Record<string, StorageType[typeof property]>,\n  ): StorageType[typeof property] | undefined {\n    const value = obj[property]!,\n      regex = this.regexUrl;\n    if (!regex.test(value)) {\n      return undefined;\n    }\n    // verify: can we remove the 'g' flag? and remove lastIndex changes?\n    regex.lastIndex = 0;\n    // we passed the regex test, so we know is not null;\n    const id = regex.exec(value)![1];\n    regex.lastIndex = 0;\n    // @todo fix this\n    return storage[id];\n  }\n\n  resolveGradient(\n    obj: NotParsedFabricObject,\n    el: Element,\n    property: 'fill' | 'stroke',\n  ) {\n    const gradientDef = this.extractPropertyDefinition(\n      obj,\n      property,\n      this.gradientDefs,\n    ) as SVGGradientElement;\n    if (gradientDef) {\n      const opacityAttr = el.getAttribute(property + '-opacity');\n      const gradient = Gradient.fromElement(gradientDef, obj, {\n        ...this.options,\n        opacity: opacityAttr,\n      } as SVGOptions);\n      obj.set(property, gradient);\n    }\n  }\n\n  /**\n   * James modified\n   * @param {*} obj\n   * @param {*} el\n   * @param {*} property\n   */\n  resolvePattern(obj: NotParsedFabricObject, el: Element, property: 'fill') {\n    var patternDef = this.extractPropertyDefinition(\n      obj,\n      property,\n      this.patternDefs,\n    ) as PatternOptions;\n    if (patternDef) {\n      var pattern = new Pattern(patternDef);\n      obj.set(property, pattern);\n    }\n  }\n\n  // TODO: resolveClipPath could be run once per clippath with minor work per object.\n  // is a refactor that i m not sure is worth on this code\n  async resolveClipPath(\n    obj: NotParsedFabricObject,\n    usingElement: Element,\n    exactOwner?: Element,\n  ) {\n    const clipPathElements = this.extractPropertyDefinition(\n      obj,\n      'clipPath',\n      this.clipPaths,\n    ) as Element[];\n    if (clipPathElements) {\n      const objTransformInv = invertTransform(obj.calcTransformMatrix());\n      const clipPathTag = clipPathElements[0].parentElement!;\n      let clipPathOwner = usingElement;\n      while (\n        !exactOwner &&\n        clipPathOwner.parentElement &&\n        clipPathOwner.getAttribute('clip-path') !== obj.clipPath\n      ) {\n        clipPathOwner = clipPathOwner.parentElement;\n      }\n\n      // James modified\n      // 把 ClipPath 节点移出clipPathOwner, 避免重复解析clipPath 并造成 Maximum call stack size\n      // 但是这个操作导致了 clipPath的父节点的矩阵在调用fabric.parseAttributes没有乘到clipPath上\n      // 通常矩阵是 svg > g > clipPath > path, 这样的话变成了 svg > clipPath > path\n      // 因此把 下面的移出操作放到创建path(klass.fromElement)之后\n      // clipPathOwner.parentNode.appendChild(clipPathTag);\n\n      // 暂时通过修改 clipPath的transform处理\n      if (clipPathOwner.hasAttribute('transform'))\n        clipPathTag.setAttribute(\n          'transform',\n          clipPathOwner.getAttribute('transform')!,\n        );\n      // move the clipPath tag as sibling to the real element that is using it\n      clipPathOwner.parentElement!.appendChild(clipPathTag!);\n\n      // this multiplication order could be opposite.\n      // but i don't have an svg to test it\n      // at the first SVG that has a transform on both places and is misplaced\n      // try to invert this multiplication order\n      const finalTransform = parseTransformAttribute(\n        `${clipPathOwner.getAttribute('transform') || ''} ${\n          clipPathTag.getAttribute('originalTransform') || ''\n        }`,\n      );\n\n      clipPathTag.setAttribute(\n        'transform',\n        `matrix(${finalTransform.join(',')})`,\n      );\n\n      const container = await Promise.all(\n        clipPathElements.map((clipPathElement) => {\n          return findTag(clipPathElement)\n            .fromElement(clipPathElement, this.options, this.cssRules)\n            .then((enlivedClippath: NotParsedFabricObject) => {\n              removeTransformMatrixForSvgParsing(enlivedClippath);\n              enlivedClippath.fillRule = enlivedClippath.clipRule!;\n              delete enlivedClippath.clipRule;\n              return enlivedClippath;\n            });\n        }),\n      );\n      const clipPath =\n        container.length === 1 ? container[0] : new Group(container);\n      const gTransform = multiplyTransformMatrices(\n        objTransformInv,\n        clipPath.calcTransformMatrix(),\n      );\n      if (clipPath.clipPath) {\n        await this.resolveClipPath(\n          clipPath,\n          clipPathOwner,\n          // this is tricky.\n          // it tries to differentiate from when clipPaths are inherited by outside groups\n          // or when are really clipPaths referencing other clipPaths\n          clipPathTag.getAttribute('clip-path') ? clipPathOwner : undefined,\n        );\n      }\n      const { scaleX, scaleY, angle, skewX, translateX, translateY } =\n        qrDecompose(gTransform);\n      clipPath.set({\n        flipX: false,\n        flipY: false,\n      });\n      clipPath.set({\n        scaleX,\n        scaleY,\n        angle,\n        skewX,\n        skewY: 0,\n      });\n      clipPath.setPositionByOrigin(\n        new Point(translateX, translateY),\n        CENTER,\n        CENTER,\n      );\n      obj.clipPath = clipPath;\n    } else {\n      // if clip-path does not resolve to any element, delete the property.\n      delete obj.clipPath;\n      return;\n    }\n  }\n}\n"],"names":["findTag","el","tagName","getTagName","toLowerCase","classRegistry","getSVGClass","ElementsParser","constructor","elements","options","reviver","doc","clipPaths","regexUrl","gradientDefs","getGradientDefs","patternDefs","getPatternDefs","cssRules","getCSSRules","parse","Promise","all","map","element","createObject","klass","obj","fromElement","resolveGradient","FILL","resolvePattern","STROKE","FabricImage","_originalElement","removeTransformMatrixForSvgParsing","parsePreserveAspectRatioAttribute","resolveClipPath","extractPropertyDefinition","property","storage","value","regex","test","undefined","lastIndex","id","exec","gradientDef","opacityAttr","getAttribute","gradient","Gradient","opacity","set","patternDef","pattern","Pattern","usingElement","exactOwner","clipPathElements","objTransformInv","invertTransform","calcTransformMatrix","clipPathTag","parentElement","clipPathOwner","clipPath","hasAttribute","setAttribute","appendChild","finalTransform","parseTransformAttribute","join","container","clipPathElement","then","enlivedClippath","fillRule","clipRule","length","Group","gTransform","multiplyTransformMatrices","scaleX","scaleY","angle","skewX","translateX","translateY","qrDecompose","flipX","flipY","skewY","setPositionByOrigin","Point","CENTER"],"mappings":"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"}