{"version":3,"file":"SVGResource.mjs","sources":["../../../src/textures/resources/SVGResource.ts"],"sourcesContent":["import { settings } from '@pixi/settings';\nimport { uid } from '@pixi/utils';\nimport { BaseImageResource } from './BaseImageResource';\n\nimport type { ISize } from '@pixi/math';\nimport type { ICanvas } from '@pixi/settings';\n\nexport interface ISVGResourceOptions\n{\n    source?: string;\n    scale?: number;\n    width?: number;\n    height?: number;\n    autoLoad?: boolean;\n    crossorigin?: boolean | string;\n}\n/**\n * Resource type for SVG elements and graphics.\n * @memberof PIXI\n */\nexport class SVGResource extends BaseImageResource\n{\n    /** Base64 encoded SVG element or URL for SVG file. */\n    public readonly svg: string;\n\n    /** The source scale to apply when rasterizing on load. */\n    public readonly scale: number;\n\n    /** A width override for rasterization on load. */\n    public readonly _overrideWidth: number;\n\n    /** A height override for rasterization on load. */\n    public readonly _overrideHeight: number;\n\n    /** Call when completely loaded. */\n    private _resolve: () => void;\n\n    /** Promise when loading */\n    private _load: Promise<this>;\n\n    /** Cross origin value to use */\n    private _crossorigin?: boolean | string;\n\n    /**\n     * @param sourceBase64 - Base64 encoded SVG element or URL for SVG file.\n     * @param {object} [options] - Options to use\n     * @param {number} [options.scale=1] - Scale to apply to SVG. Overridden by...\n     * @param {number} [options.width] - Rasterize SVG this wide. Aspect ratio preserved if height not specified.\n     * @param {number} [options.height] - Rasterize SVG this high. Aspect ratio preserved if width not specified.\n     * @param {boolean} [options.autoLoad=true] - Start loading right away.\n     */\n    constructor(sourceBase64: string, options?: ISVGResourceOptions)\n    {\n        options = options || {};\n\n        super(settings.ADAPTER.createCanvas());\n        this._width = 0;\n        this._height = 0;\n\n        this.svg = sourceBase64;\n        this.scale = options.scale || 1;\n        this._overrideWidth = options.width;\n        this._overrideHeight = options.height;\n\n        this._resolve = null;\n        this._crossorigin = options.crossorigin;\n        this._load = null;\n\n        if (options.autoLoad !== false)\n        {\n            this.load();\n        }\n    }\n\n    load(): Promise<this>\n    {\n        if (this._load)\n        {\n            return this._load;\n        }\n\n        this._load = new Promise((resolve): void =>\n        {\n            // Save this until after load is finished\n            this._resolve = (): void =>\n            {\n                this.update();\n                resolve(this);\n            };\n\n            // Convert SVG inline string to data-uri\n            if (SVGResource.SVG_XML.test(this.svg.trim()))\n            {\n                if (!btoa)\n                {\n                    throw new Error('Your browser doesn\\'t support base64 conversions.');\n                }\n                (this as any).svg = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(this.svg)))}`;\n            }\n\n            this._loadSvg();\n        });\n\n        return this._load;\n    }\n\n    /** Loads an SVG image from `imageUrl` or `data URL`. */\n    private _loadSvg(): void\n    {\n        const tempImage = new Image();\n\n        BaseImageResource.crossOrigin(tempImage, this.svg, this._crossorigin);\n        tempImage.src = this.svg;\n\n        tempImage.onerror = (event): void =>\n        {\n            if (!this._resolve)\n            {\n                return;\n            }\n\n            tempImage.onerror = null;\n            this.onError.emit(event);\n        };\n\n        tempImage.onload = (): void =>\n        {\n            if (!this._resolve)\n            {\n                return;\n            }\n\n            const svgWidth = tempImage.width;\n            const svgHeight = tempImage.height;\n\n            if (!svgWidth || !svgHeight)\n            {\n                throw new Error('The SVG image must have width and height defined (in pixels), canvas API needs them.');\n            }\n\n            // Set render size\n            let width = svgWidth * this.scale;\n            let height = svgHeight * this.scale;\n\n            if (this._overrideWidth || this._overrideHeight)\n            {\n                width = this._overrideWidth || this._overrideHeight / svgHeight * svgWidth;\n                height = this._overrideHeight || this._overrideWidth / svgWidth * svgHeight;\n            }\n            width = Math.round(width);\n            height = Math.round(height);\n\n            // Create a canvas element\n            const canvas = this.source as ICanvas;\n\n            canvas.width = width;\n            canvas.height = height;\n            (canvas as any)._pixiId = `canvas_${uid()}`;\n\n            // Draw the Svg to the canvas\n            canvas\n                .getContext('2d')\n                .drawImage(tempImage, 0, 0, svgWidth, svgHeight, 0, 0, width, height);\n\n            this._resolve();\n            this._resolve = null;\n        };\n    }\n\n    /**\n     * Get size from an svg string using a regular expression.\n     * @param svgString - a serialized svg element\n     * @returns - image extension\n     */\n    static getSize(svgString?: string): ISize\n    {\n        const sizeMatch = SVGResource.SVG_SIZE.exec(svgString);\n        const size: any = {};\n\n        if (sizeMatch)\n        {\n            size[sizeMatch[1]] = Math.round(parseFloat(sizeMatch[3]));\n            size[sizeMatch[5]] = Math.round(parseFloat(sizeMatch[7]));\n        }\n\n        return size;\n    }\n\n    /** Destroys this texture. */\n    dispose(): void\n    {\n        super.dispose();\n        this._resolve = null;\n        this._crossorigin = null;\n    }\n\n    /**\n     * Used to auto-detect the type of resource.\n     * @param {*} source - The source object\n     * @param {string} extension - The extension of source, if set\n     * @returns {boolean} - If the source is a SVG source or data file\n     */\n    static test(source: unknown, extension?: string): boolean\n    {\n        // url file extension is SVG\n        return extension === 'svg'\n            // source is SVG data-uri\n            || (typeof source === 'string' && source.startsWith('data:image/svg+xml'))\n            // source is SVG inline\n            || (typeof source === 'string' && SVGResource.SVG_XML.test(source));\n    }\n\n    /**\n     * Regular expression for SVG XML document.\n     * @example &lt;?xml version=\"1.0\" encoding=\"utf-8\" ?&gt;&lt;!-- image/svg --&gt;&lt;svg\n     * @readonly\n     */\n    static SVG_XML = /^(<\\?xml[^?]+\\?>)?\\s*(<!--[^(-->)]*-->)?\\s*\\<svg/m;\n\n    /**\n     * Regular expression for SVG size.\n     * @example &lt;svg width=\"100\" height=\"100\"&gt;&lt;/svg&gt;\n     * @readonly\n     */\n    static SVG_SIZE = /<svg[^>]*(?:\\s(width|height)=('|\")(\\d*(?:\\.\\d+)?)(?:px)?('|\"))[^>]*(?:\\s(width|height)=('|\")(\\d*(?:\\.\\d+)?)(?:px)?('|\"))[^>]*>/i; // eslint-disable-line max-len\n}\n"],"names":["_SVGResource"],"mappings":"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"}