{"version":3,"file":"HTMLTextSystem.mjs","sources":["../../../src/scene/text-html/HTMLTextSystem.ts"],"sourcesContent":["import { type ImageLike } from '../../environment/ImageLike';\nimport { ExtensionType } from '../../extensions/Extensions';\nimport { type CanvasAndContext, CanvasPool } from '../../rendering/renderers/shared/texture/CanvasPool';\nimport { TexturePool } from '../../rendering/renderers/shared/texture/TexturePool';\nimport { type TextureStyle } from '../../rendering/renderers/shared/texture/TextureStyle';\nimport { type Renderer, RendererType } from '../../rendering/renderers/types';\nimport { isSafari } from '../../utils/browser/isSafari';\nimport { warn } from '../../utils/logging/warn';\nimport { BigPool } from '../../utils/pool/PoolGroup';\nimport { getPo2TextureFromSource } from '../text/utils/getPo2TextureFromSource';\nimport { HTMLTextRenderData } from './HTMLTextRenderData';\nimport { type HTMLTextStyle } from './HTMLTextStyle';\nimport { extractFontFamilies } from './utils/extractFontFamilies';\nimport { getFontCss } from './utils/getFontCss';\nimport { getSVGUrl } from './utils/getSVGUrl';\nimport { getTemporaryCanvasFromImage } from './utils/getTemporaryCanvasFromImage';\nimport { loadSVGImage } from './utils/loadSVGImage';\nimport { measureHtmlText } from './utils/measureHtmlText';\n\nimport type { System } from '../../rendering/renderers/shared/system/System';\nimport type { Texture } from '../../rendering/renderers/shared/texture/Texture';\nimport type { PoolItem } from '../../utils/pool/Pool';\nimport type { HTMLText, HTMLTextOptions } from './HTMLText';\n\n/**\n * System plugin to the renderer to manage HTMLText\n * @category rendering\n * @advanced\n */\nexport class HTMLTextSystem implements System\n{\n    /** @ignore */\n    public static extension = {\n        type: [\n            ExtensionType.WebGLSystem,\n            ExtensionType.WebGPUSystem,\n            ExtensionType.CanvasSystem,\n        ],\n        name: 'htmlText',\n    } as const;\n\n    /**\n     * WebGPU has a cors issue when uploading an image that is an SVGImage\n     * To get around this we need to create a canvas draw the image to it and upload that instead.\n     * Bit of a shame.. but no other work around just yet!\n     */\n    private readonly _createCanvas: boolean;\n    private readonly _renderer: Renderer;\n\n    private readonly _activeTextures: Record<string, {\n        texture: Texture,\n        usageCount: number,\n        promise: Promise<Texture>,\n    }> = {};\n\n    constructor(renderer: Renderer)\n    {\n        this._renderer = renderer;\n        this._createCanvas = renderer.type === RendererType.WEBGPU;\n    }\n\n    /**\n     * @param options\n     * @deprecated Use getTexturePromise instead\n     */\n    public getTexture(options: HTMLTextOptions): Promise<Texture>\n    {\n        return this.getTexturePromise(options);\n    }\n\n    /**\n     * Increases the reference count for a texture.\n     * @param text - The HTMLText instance associated with the texture.\n     */\n    public getManagedTexture(text: HTMLText): Promise<Texture>\n    {\n        const textKey = text.styleKey;\n\n        if (this._activeTextures[textKey])\n        {\n            this._increaseReferenceCount(textKey);\n\n            return this._activeTextures[textKey].promise;\n        }\n\n        const promise = this._buildTexturePromise(text)\n            .then((texture) =>\n            {\n                this._activeTextures[textKey].texture = texture;\n\n                return texture;\n            });\n\n        this._activeTextures[textKey] = {\n            texture: null,\n            promise,\n            usageCount: 1,\n        };\n\n        return promise;\n    }\n\n    /**\n     * Gets the current reference count for a texture associated with a text key.\n     * @param textKey - The unique key identifying the text style configuration\n     * @returns The number of Text instances currently using this texture\n     */\n    public getReferenceCount(textKey: string)\n    {\n        return this._activeTextures[textKey]?.usageCount ?? null;\n    }\n\n    private _increaseReferenceCount(textKey: string)\n    {\n        this._activeTextures[textKey].usageCount++;\n    }\n\n    /**\n     * Decreases the reference count for a texture.\n     * If the count reaches zero, the texture is cleaned up.\n     * @param textKey - The key associated with the HTMLText instance.\n     */\n    public decreaseReferenceCount(textKey: string)\n    {\n        const activeTexture = this._activeTextures[textKey];\n\n        if (!activeTexture) return;\n\n        activeTexture.usageCount--;\n\n        if (activeTexture.usageCount === 0)\n        {\n            if (activeTexture.texture)\n            {\n                this._cleanUp(activeTexture.texture);\n            }\n            else\n            {\n                // we did not resolve...\n                activeTexture.promise.then((texture) =>\n                {\n                    activeTexture.texture = texture;\n\n                    this._cleanUp(activeTexture.texture);\n                }).catch(() =>\n                {\n                    // #if _DEBUG\n                    warn('HTMLTextSystem: Failed to clean texture');\n                    // #endif\n                });\n            }\n\n            this._activeTextures[textKey] = null;\n        }\n    }\n\n    /**\n     * Returns a promise that resolves to a texture for the given HTMLText options.\n     * @param options - The options for the HTMLText.\n     * @returns A promise that resolves to a Texture.\n     */\n    public getTexturePromise(options: HTMLTextOptions): Promise<Texture>\n    {\n        return this._buildTexturePromise(options);\n    }\n\n    private async _buildTexturePromise(options: HTMLTextOptions)\n    {\n        const { text, style, resolution, textureStyle, autoGenerateMipmaps } = options as {\n            text: string,\n            style: HTMLTextStyle,\n            resolution: number,\n            textureStyle?: TextureStyle,\n            autoGenerateMipmaps?: boolean,\n        };\n\n        const htmlTextData = BigPool.get(HTMLTextRenderData);\n        const fontFamilies = extractFontFamilies(text, style);\n        const fontCSS = await getFontCss(fontFamilies);\n        const measured = measureHtmlText(text, style, fontCSS, htmlTextData);\n\n        const width = Math.ceil(Math.ceil((Math.max(1, measured.width) + (style.padding * 2))) * resolution);\n        const height = Math.ceil(Math.ceil((Math.max(1, measured.height) + (style.padding * 2))) * resolution);\n\n        const image = htmlTextData.image;\n\n        // this off set will ensure we don't get any UV bleeding!\n        const uvSafeOffset = 2;\n\n        image.width = (width | 0) + uvSafeOffset;\n        image.height = (height | 0) + uvSafeOffset;\n\n        const svgURL = getSVGUrl(text, style, resolution, fontCSS, htmlTextData);\n\n        await loadSVGImage(image, svgURL, isSafari() && fontFamilies.length > 0);\n\n        const resource: ImageLike | HTMLCanvasElement = image;\n        let canvasAndContext: CanvasAndContext;\n\n        if (this._createCanvas)\n        {\n            // silly webGPU workaround..\n            canvasAndContext = getTemporaryCanvasFromImage(image, resolution);\n        }\n\n        const texture = getPo2TextureFromSource(\n            canvasAndContext ? canvasAndContext.canvas : resource,\n            image.width - uvSafeOffset,\n            image.height - uvSafeOffset,\n            resolution,\n            autoGenerateMipmaps\n        );\n\n        if (textureStyle) texture.source.style = textureStyle;\n\n        if (this._createCanvas)\n        {\n            this._renderer.texture.initSource(texture.source);\n            CanvasPool.returnCanvasAndContext(canvasAndContext);\n        }\n\n        BigPool.return(htmlTextData as PoolItem);\n\n        return texture;\n    }\n\n    public returnTexturePromise(texturePromise: Promise<Texture>)\n    {\n        texturePromise.then((texture) =>\n        {\n            this._cleanUp(texture);\n        }).catch(() =>\n        {\n            // #if _DEBUG\n            warn('HTMLTextSystem: Failed to clean texture');\n            // #endif\n        });\n    }\n\n    private _cleanUp(texture: Texture)\n    {\n        TexturePool.returnTexture(texture, true);\n        texture.source.resource = null;\n        texture.source.uploadMethodId = 'unknown';\n    }\n\n    public destroy()\n    {\n        // BOOM!\n        (this._renderer as null) = null;\n        for (const key in this._activeTextures)\n        {\n            if (this._activeTextures[key]) this.returnTexturePromise(this._activeTextures[key].promise);\n        }\n        (this._activeTextures as null) = null;\n    }\n}\n"],"names":[],"mappings":"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"}