UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

1 lines 13.8 kB
{"version":3,"file":"elements_parser.mjs","sources":["../../../src/parser/elements_parser.ts"],"sourcesContent":["import { Gradient } from '../gradient/Gradient';\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';\n\nconst findTag = (el: Element) =>\n classRegistry.getSVGClass(getTagName(el).toLowerCase());\n\ntype StorageType = {\n fill: SVGGradientElement;\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 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.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 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 // 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 // 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","classRegistry","getSVGClass","getTagName","toLowerCase","ElementsParser","constructor","elements","options","reviver","doc","clipPaths","regexUrl","gradientDefs","getGradientDefs","cssRules","getCSSRules","parse","Promise","all","map","element","createObject","klass","obj","fromElement","resolveGradient","FILL","STROKE","FabricImage","_originalElement","removeTransformMatrixForSvgParsing","parsePreserveAspectRatioAttribute","resolveClipPath","extractPropertyDefinition","property","storage","value","regex","test","undefined","lastIndex","id","exec","gradientDef","opacityAttr","getAttribute","gradient","Gradient","_objectSpread","opacity","set","usingElement","exactOwner","clipPathElements","objTransformInv","invertTransform","calcTransformMatrix","clipPathTag","parentElement","clipPathOwner","clipPath","appendChild","finalTransform","parseTransformAttribute","concat","setAttribute","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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"}