{"version":3,"file":"CanvasTextMetrics.mjs","sources":["../../../../src/scene/text/canvas/CanvasTextMetrics.ts"],"sourcesContent":["import { lru } from 'tiny-lru';\nimport { DOMAdapter } from '../../../environment/adapter';\nimport { measureTaggedText } from './utils/measureTaggedText';\nimport { hasTagMarkup, hasTagStyles, type TextStyleRun } from './utils/parseTaggedText';\nimport { isBreakingSpace as isBreakingSpaceUtil, NEWLINE_MATCH_REGEX } from './utils/textTokenization';\nimport { wordWrap } from './utils/wordWrap';\n\nimport type { ICanvas, ICanvasRenderingContext2DSettings } from '../../../environment/canvas/ICanvas';\nimport type { ICanvasRenderingContext2D } from '../../../environment/canvas/ICanvasRenderingContext2D';\nimport type { TextStyle } from '../TextStyle';\nimport type { FontMetrics } from './utils/types';\n\n// The type for Intl.Segmenter is only available since TypeScript 4.7.2, so let's make a polyfill for it.\ninterface ISegmentData\n{\n    segment: string;\n}\ninterface ISegments\n{\n    [Symbol.iterator](): IterableIterator<ISegmentData>;\n}\ninterface ISegmenter\n{\n    segment(input: string): ISegments;\n}\ninterface IIntl\n{\n    Segmenter?: {\n        prototype: ISegmenter;\n        /**\n         * Creates a new Intl.Segmenter object.\n         * @returns A new Intl.Segmenter object.\n         */\n        new(): ISegmenter;\n    };\n}\n\n// Default settings used for all getContext calls\nconst contextSettings: ICanvasRenderingContext2DSettings = {\n    // TextMetrics requires getImageData readback for measuring fonts.\n    willReadFrequently: true,\n};\n\n/**\n * The TextMetrics object represents the measurement of a block of text with a specified style.\n * @example\n * import { CanvasTextMetrics, TextStyle } from 'pixi.js';\n *\n * const style = new TextStyle({\n *     fontFamily: 'Arial',\n *     fontSize: 24,\n *     fill: 0xff1010,\n *     align: 'center',\n * });\n * const textMetrics = CanvasTextMetrics.measureText('Your text', style);\n * @category text\n * @advanced\n */\nexport class CanvasTextMetrics\n{\n    /** The text that was measured. */\n    public text: string;\n\n    /** The style that was measured. */\n    public style: TextStyle;\n\n    /** The measured width of the text. */\n    public width: number;\n\n    /** The measured height of the text. */\n    public height: number;\n\n    /** An array of lines of the text broken by new lines and wrapping is specified in style. */\n    public lines: string[];\n\n    /** An array of the line widths for each line matched to `lines`. */\n    public lineWidths: number[];\n\n    /** The measured line height for this style. */\n    public lineHeight: number;\n\n    /** The maximum line width for all measured lines. */\n    public maxLineWidth: number;\n\n    /** The font properties object from TextMetrics.measureFont. */\n    public fontProperties: FontMetrics;\n\n    /**\n     * Per-line style runs for tagged text rendering.\n     * Each element is an array of runs for that line.\n     * Only populated when text contains tag markup.\n     * @internal\n     */\n    public runsByLine?: TextStyleRun[][];\n\n    /**\n     * Per-line ascent values for tagged text with mixed fonts.\n     * Represents the max ascent across all runs on each line.\n     * Only populated when text contains tag markup.\n     * @internal\n     */\n    public lineAscents?: number[];\n\n    /**\n     * Per-line descent values for tagged text with mixed fonts.\n     * Represents the max descent across all runs on each line.\n     * Only populated when text contains tag markup.\n     * @internal\n     */\n    public lineDescents?: number[];\n\n    /**\n     * Per-line heights for tagged text with mixed fonts.\n     * Each line may have different height based on the fonts used.\n     * Only populated when text contains tag markup.\n     * @internal\n     */\n    public lineHeights?: number[];\n\n    /**\n     * Whether any run in the tagged text has a drop shadow.\n     * Cached during measurement to avoid per-render iteration.\n     * Only populated when text contains tag markup.\n     * @internal\n     */\n    public hasDropShadow?: boolean;\n\n    /**\n     * String used for calculate font metrics.\n     * These characters are all tall to help calculate the height required for text.\n     */\n    public static METRICS_STRING = '|ÉqÅ';\n\n    /** Baseline symbol for calculate font metrics. */\n    public static BASELINE_SYMBOL = 'M';\n\n    /** Baseline multiplier for calculate font metrics. */\n    public static BASELINE_MULTIPLIER = 1.4;\n\n    /** Height multiplier for setting height of canvas to calculate font metrics. */\n    public static HEIGHT_MULTIPLIER = 2.0;\n\n    /**\n     * A Unicode \"character\", or \"grapheme cluster\", can be composed of multiple Unicode code points,\n     * such as letters with diacritical marks (e.g. `'\\u0065\\u0301'`, letter e with acute)\n     * or emojis with modifiers (e.g. `'\\uD83E\\uDDD1\\u200D\\uD83D\\uDCBB'`, technologist).\n     * The new `Intl.Segmenter` API in ES2022 can split the string into grapheme clusters correctly. If it is not available,\n     * PixiJS will fallback to use the iterator of String, which can only spilt the string into code points.\n     * If you want to get full functionality in environments that don't support `Intl.Segmenter` (such as Firefox),\n     * you can use other libraries such as [grapheme-splitter]{@link https://www.npmjs.com/package/grapheme-splitter}\n     * or [graphemer]{@link https://www.npmjs.com/package/graphemer} to create a polyfill. Since these libraries can be\n     * relatively large in size to handle various Unicode grapheme clusters properly, PixiJS won't use them directly.\n     */\n    public static graphemeSegmenter: (s: string) => string[] = (() =>\n    {\n        if (typeof (Intl as IIntl)?.Segmenter === 'function')\n        {\n            const segmenter = new (Intl as IIntl).Segmenter();\n\n            return (s: string) =>\n            {\n                const segments = segmenter.segment(s);\n                const result = [];\n\n                let i = 0;\n\n                for (const segment of segments)\n                {\n                    result[i++] = (segment.segment);\n                }\n\n                return result;\n            };\n        }\n\n        return (s: string) => [...s];\n    })();\n\n    public static _experimentalLetterSpacingSupported?: boolean;\n\n    /**\n     * Checking that we can use modern canvas 2D API.\n     *\n     * Note: This is an unstable API, Chrome < 94 use `textLetterSpacing`, later versions use `letterSpacing`.\n     * @see CanvasTextMetrics.experimentalLetterSpacing\n     * @see https://developer.mozilla.org/en-US/docs/Web/API/ICanvasRenderingContext2D/letterSpacing\n     * @see https://developer.chrome.com/origintrials/#/view_trial/3585991203293757441\n     */\n    public static get experimentalLetterSpacingSupported(): boolean\n    {\n        let result = CanvasTextMetrics._experimentalLetterSpacingSupported;\n\n        if (result === undefined)\n        {\n            const proto = DOMAdapter.get().getCanvasRenderingContext2D().prototype;\n\n            result\n                = CanvasTextMetrics._experimentalLetterSpacingSupported\n                = 'letterSpacing' in proto || 'textLetterSpacing' in proto;\n        }\n\n        return result;\n    }\n\n    /**\n     * New rendering behavior for letter-spacing which uses Chrome's new native API. This will\n     * lead to more accurate letter-spacing results because it does not try to manually draw\n     * each character. However, this Chrome API is experimental and may not serve all cases yet.\n     * @see CanvasTextMetrics.experimentalLetterSpacingSupported\n     */\n    public static experimentalLetterSpacing = false;\n\n    /** Cache of {@link TextMetrics.FontMetrics} objects. */\n    private static _fonts: Record<string, FontMetrics> = {};\n\n    // eslint-disable-next-line @typescript-eslint/naming-convention\n    private static __canvas: ICanvas;\n    // eslint-disable-next-line @typescript-eslint/naming-convention\n    private static __context: ICanvasRenderingContext2D;\n\n    /** Cache for measured text metrics */\n    private static readonly _measurementCache = lru<CanvasTextMetrics>(1000);\n\n    /**\n     * @param text - the text that was measured\n     * @param style - the style that was measured\n     * @param width - the measured width of the text\n     * @param height - the measured height of the text\n     * @param lines - an array of the lines of text broken by new lines and wrapping if specified in style\n     * @param lineWidths - an array of the line widths for each line matched to `lines`\n     * @param lineHeight - the measured line height for this style\n     * @param maxLineWidth - the maximum line width for all measured lines\n     * @param fontProperties - the font properties object from TextMetrics.measureFont\n     * @param taggedData - optional object containing tagged text specific data\n     * @param taggedData.runsByLine - per-line style runs for tagged text\n     * @param taggedData.lineAscents - per-line ascent values for tagged text\n     * @param taggedData.lineDescents - per-line descent values for tagged text\n     * @param taggedData.lineHeights - per-line height values for tagged text\n     * @param taggedData.hasDropShadow - whether any run has a drop shadow\n     */\n    constructor(\n        text: string,\n        style: TextStyle,\n        width: number,\n        height: number,\n        lines: string[],\n        lineWidths: number[],\n        lineHeight: number,\n        maxLineWidth: number,\n        fontProperties: FontMetrics,\n        taggedData?: {\n            runsByLine?: TextStyleRun[][],\n            lineAscents?: number[],\n            lineDescents?: number[],\n            lineHeights?: number[],\n            hasDropShadow?: boolean,\n        },\n    )\n    {\n        this.text = text;\n        this.style = style;\n        this.width = width;\n        this.height = height;\n        this.lines = lines;\n        this.lineWidths = lineWidths;\n        this.lineHeight = lineHeight;\n        this.maxLineWidth = maxLineWidth;\n        this.fontProperties = fontProperties;\n\n        if (taggedData)\n        {\n            this.runsByLine = taggedData.runsByLine;\n            this.lineAscents = taggedData.lineAscents;\n            this.lineDescents = taggedData.lineDescents;\n            this.lineHeights = taggedData.lineHeights;\n            this.hasDropShadow = taggedData.hasDropShadow;\n        }\n    }\n\n    /**\n     * Measures the supplied string of text and returns a Rectangle.\n     * @param text - The text to measure.\n     * @param style - The text style to use for measuring\n     * @param canvas - optional specification of the canvas to use for measuring.\n     * @param wordWrap\n     * @returns Measured width and height of the text.\n     */\n    public static measureText(\n        text = ' ',\n        style: TextStyle,\n        canvas: ICanvas = CanvasTextMetrics._canvas,\n        wordWrap: boolean = style.wordWrap,\n    ): CanvasTextMetrics\n    {\n        const textKey = `${text}-${style.styleKey}-wordWrap-${wordWrap}`;\n\n        // check if we have already measured this text with the same style\n        if (CanvasTextMetrics._measurementCache.has(textKey))\n        {\n            return CanvasTextMetrics._measurementCache.get(textKey);\n        }\n\n        // Check if we need to use tagged text measurement\n        const isTagged = hasTagStyles(style) && hasTagMarkup(text);\n\n        if (isTagged)\n        {\n            const result = measureTaggedText(\n                text,\n                style,\n                wordWrap,\n                CanvasTextMetrics._context,\n                CanvasTextMetrics._measureText,\n                CanvasTextMetrics.measureFont,\n                CanvasTextMetrics.canBreakChars,\n                CanvasTextMetrics.wordWrapSplit,\n            );\n\n            const measurements = new CanvasTextMetrics(\n                text,\n                style,\n                result.width,\n                result.height,\n                result.lines,\n                result.lineWidths,\n                result.lineHeight,\n                result.maxLineWidth,\n                result.fontProperties,\n                {\n                    runsByLine: result.runsByLine,\n                    lineAscents: result.lineAscents,\n                    lineDescents: result.lineDescents,\n                    lineHeights: result.lineHeights,\n                    hasDropShadow: result.hasDropShadow,\n                },\n            );\n\n            CanvasTextMetrics._measurementCache.set(textKey, measurements);\n\n            return measurements;\n        }\n\n        const font = style._fontString;\n        const fontProperties = CanvasTextMetrics.measureFont(font);\n\n        // fallback in case UA disallow canvas data extraction\n        if (fontProperties.fontSize === 0)\n        {\n            fontProperties.fontSize = style.fontSize as number;\n            fontProperties.ascent = style.fontSize as number;\n            fontProperties.descent = 0;\n        }\n\n        const context = CanvasTextMetrics._context;\n\n        context.font = font;\n\n        const outputText = wordWrap\n            ? CanvasTextMetrics._wordWrap(text, style, canvas)\n            : text;\n        const lines = outputText.split(NEWLINE_MATCH_REGEX);\n        const lineWidths = new Array<number>(lines.length);\n        let maxLineWidth = 0;\n\n        for (let i = 0; i < lines.length; i++)\n        {\n            const lineWidth = CanvasTextMetrics._measureText(lines[i], style.letterSpacing, context);\n\n            lineWidths[i] = lineWidth;\n            maxLineWidth = Math.max(maxLineWidth, lineWidth);\n        }\n\n        const strokeWidth = style._stroke?.width ?? 0;\n        const lineHeight = style.lineHeight || fontProperties.fontSize;\n\n        // Calculate base width - use wordWrapWidth for non-left alignment when wrapping\n        const baseWidth = CanvasTextMetrics._getAlignWidth(maxLineWidth, style, wordWrap);\n        const width = CanvasTextMetrics._adjustWidthForStyle(baseWidth, style);\n\n        // Calculate height\n        const baseHeight = Math.max(lineHeight, fontProperties.fontSize + strokeWidth)\n            + ((lines.length - 1) * (lineHeight + style.leading));\n        const height = CanvasTextMetrics._adjustHeightForStyle(baseHeight, style);\n\n        const measurements = new CanvasTextMetrics(\n            text,\n            style,\n            width,\n            height,\n            lines,\n            lineWidths,\n            lineHeight + style.leading,\n            maxLineWidth,\n            fontProperties\n        );\n\n        // cache the measurements\n        CanvasTextMetrics._measurementCache.set(textKey, measurements);\n\n        return measurements;\n    }\n\n    /**\n     * Adjusts the measured width to account for stroke and drop shadow.\n     * @param baseWidth - The base content width\n     * @param style - The text style\n     * @returns The adjusted width\n     */\n    private static _adjustWidthForStyle(baseWidth: number, style: TextStyle): number\n    {\n        const strokeWidth = style._stroke?.width || 0;\n        let width = baseWidth + strokeWidth;\n\n        if (style.dropShadow)\n        {\n            width += style.dropShadow.distance;\n        }\n\n        return width;\n    }\n\n    /**\n     * Adjusts the measured height to account for drop shadow.\n     * @param baseHeight - The base content height\n     * @param style - The text style\n     * @returns The adjusted height\n     */\n    private static _adjustHeightForStyle(baseHeight: number, style: TextStyle): number\n    {\n        let height = baseHeight;\n\n        if (style.dropShadow)\n        {\n            height += style.dropShadow.distance;\n        }\n\n        return height;\n    }\n\n    /**\n     * Calculates the base width for alignment purposes.\n     * When word wrap is enabled with center/right alignment, uses wordWrapWidth.\n     * @param maxLineWidth - The maximum line width\n     * @param style - The text style\n     * @param wordWrapEnabled - Whether word wrap is enabled\n     * @returns The width to use for alignment calculations\n     */\n    private static _getAlignWidth(maxLineWidth: number, style: TextStyle, wordWrapEnabled: boolean): number\n    {\n        const useWrapWidth = wordWrapEnabled && style.align !== 'left';\n\n        return useWrapWidth ? Math.max(maxLineWidth, style.wordWrapWidth) : maxLineWidth;\n    }\n\n    /**\n     * Measures the rendered width of a string, accounting for letter spacing and using the provided context.\n     * @param text - The text to measure\n     * @param letterSpacing - Letter spacing in pixels\n     * @param context - Canvas 2D context\n     * @returns The measured width of the text with spacing\n     * @internal\n     */\n    public static _measureText(\n        text: string,\n        letterSpacing: number,\n        context: ICanvasRenderingContext2D\n    ): number\n    {\n        let useExperimentalLetterSpacing = false;\n\n        if (CanvasTextMetrics.experimentalLetterSpacingSupported)\n        {\n            if (CanvasTextMetrics.experimentalLetterSpacing)\n            {\n                context.letterSpacing = `${letterSpacing}px`;\n                context.textLetterSpacing = `${letterSpacing}px`;\n                useExperimentalLetterSpacing = true;\n            }\n            else\n            {\n                context.letterSpacing = '0px';\n                context.textLetterSpacing = '0px';\n            }\n        }\n\n        const metrics = context.measureText(text);\n        let metricWidth = metrics.width;\n        const actualBoundingBoxLeft = -(metrics.actualBoundingBoxLeft ?? 0);\n        const actualBoundingBoxRight = metrics.actualBoundingBoxRight ?? 0;\n        let boundsWidth = actualBoundingBoxRight - actualBoundingBoxLeft;\n\n        if (metricWidth > 0)\n        {\n            if (useExperimentalLetterSpacing)\n            {\n                metricWidth -= letterSpacing;\n                boundsWidth -= letterSpacing;\n            }\n            else\n            {\n                const val = (CanvasTextMetrics.graphemeSegmenter(text).length - 1) * letterSpacing;\n\n                metricWidth += val;\n                boundsWidth += val;\n            }\n        }\n\n        // NOTE: this is a bit of a hack as metrics.width and the bounding box width do not measure the same thing\n        // We can't seem to exclusively use one or the other, so are taking the largest of the two\n        return Math.max(metricWidth, boundsWidth);\n    }\n\n    /**\n     * Applies newlines to a string to have it optimally fit into the horizontal\n     * bounds set by the Text object's wordWrapWidth property.\n     * @param text - String to apply word wrapping to\n     * @param style - the style to use when wrapping\n     * @param canvas - optional specification of the canvas to use for measuring.\n     * @returns New string with new lines applied where required\n     */\n    private static _wordWrap(\n        text: string,\n        style: TextStyle,\n        canvas: ICanvas = CanvasTextMetrics._canvas\n    ): string\n    {\n        return wordWrap(\n            text,\n            style,\n            canvas,\n            CanvasTextMetrics._measureText,\n            CanvasTextMetrics.canBreakWords,\n            CanvasTextMetrics.canBreakChars,\n            CanvasTextMetrics.wordWrapSplit,\n        );\n    }\n\n    /**\n     * Determines if char is a breaking whitespace.\n     *\n     * It allows one to determine whether char should be a breaking whitespace\n     * For example certain characters in CJK langs or numbers.\n     * It must return a boolean.\n     * @param char - The character\n     * @param [_nextChar] - The next character\n     * @returns True if whitespace, False otherwise.\n     */\n    public static isBreakingSpace(char: string, _nextChar?: string): boolean\n    {\n        return isBreakingSpaceUtil(char, _nextChar);\n    }\n\n    /**\n     * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior.\n     *\n     * It allows one to customise which words should break\n     * Examples are if the token is CJK or numbers.\n     * It must return a boolean.\n     * @param _token - The token\n     * @param breakWords - The style attr break words\n     * @returns Whether to break word or not\n     */\n    public static canBreakWords(_token: string, breakWords: boolean): boolean\n    {\n        return breakWords;\n    }\n\n    /**\n     * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior.\n     *\n     * It allows one to determine whether a pair of characters\n     * should be broken by newlines\n     * For example certain characters in CJK langs or numbers.\n     * It must return a boolean.\n     * @param _char - The character\n     * @param _nextChar - The next character\n     * @param _token - The token/word the characters are from\n     * @param _index - The index in the token of the char\n     * @param _breakWords - The style attr break words\n     * @returns whether to break word or not\n     */\n    public static canBreakChars(_char: string, _nextChar: string, _token: string, _index: number,\n        _breakWords: boolean): boolean\n    {\n        return true;\n    }\n\n    /**\n     * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior.\n     *\n     * It is called when a token (usually a word) has to be split into separate pieces\n     * in order to determine the point to break a word.\n     * It must return an array of characters.\n     * @param token - The token to split\n     * @returns The characters of the token\n     * @see CanvasTextMetrics.graphemeSegmenter\n     */\n    public static wordWrapSplit(token: string): string[]\n    {\n        return CanvasTextMetrics.graphemeSegmenter(token);\n    }\n\n    /**\n     * Calculates the ascent, descent and fontSize of a given font-style\n     * @param font - String representing the style of the font\n     * @returns Font properties object\n     */\n    public static measureFont(font: string): FontMetrics\n    {\n        // as this method is used for preparing assets, don't recalculate things if we don't need to\n        if (CanvasTextMetrics._fonts[font])\n        {\n            return CanvasTextMetrics._fonts[font];\n        }\n\n        const context = CanvasTextMetrics._context;\n\n        context.font = font;\n        const metrics = context.measureText(CanvasTextMetrics.METRICS_STRING + CanvasTextMetrics.BASELINE_SYMBOL);\n\n        const ascent = metrics.actualBoundingBoxAscent ?? 0;\n        const descent = metrics.actualBoundingBoxDescent ?? 0;\n\n        const properties = {\n            ascent,\n            descent,\n            fontSize: ascent + descent\n        };\n\n        CanvasTextMetrics._fonts[font] = properties;\n\n        return properties;\n    }\n\n    /**\n     * Clear font metrics in metrics cache.\n     * @param {string} [font] - font name. If font name not set then clear cache for all fonts.\n     */\n    public static clearMetrics(font = ''): void\n    {\n        if (font)\n        {\n            delete CanvasTextMetrics._fonts[font];\n        }\n        else\n        {\n            CanvasTextMetrics._fonts = {};\n        }\n    }\n\n    /**\n     * Cached canvas element for measuring text\n     * TODO: this should be private, but isn't because of backward compat, will fix later.\n     * @ignore\n     */\n    public static get _canvas(): ICanvas\n    {\n        if (!CanvasTextMetrics.__canvas)\n        {\n            let canvas: ICanvas;\n\n            try\n            {\n                // OffscreenCanvas2D measureText can be up to 40% faster.\n                const c = new OffscreenCanvas(0, 0);\n                const context = c.getContext('2d', contextSettings);\n\n                if (context?.measureText)\n                {\n                    CanvasTextMetrics.__canvas = c as ICanvas;\n\n                    return c as ICanvas;\n                }\n\n                canvas = DOMAdapter.get().createCanvas();\n            }\n            catch (_cx)\n            {\n                canvas = DOMAdapter.get().createCanvas();\n            }\n            canvas.width = canvas.height = 10;\n            CanvasTextMetrics.__canvas = canvas;\n        }\n\n        return CanvasTextMetrics.__canvas;\n    }\n\n    /**\n     * TODO: this should be private, but isn't because of backward compat, will fix later.\n     * @ignore\n     */\n    public static get _context(): ICanvasRenderingContext2D\n    {\n        if (!CanvasTextMetrics.__context)\n        {\n            CanvasTextMetrics.__context = CanvasTextMetrics._canvas.getContext('2d', contextSettings);\n        }\n\n        return CanvasTextMetrics.__context;\n    }\n}\n"],"names":["wordWrap","measurements","isBreakingSpaceUtil"],"mappings":"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"}