pixi.js
Version:
<p align="center"> <a href="https://pixijs.com" target="_blank" rel="noopener noreferrer"> <img height="150" src="https://files.pixijs.download/branding/pixijs-logo-transparent-dark.svg?v=1" alt="PixiJS logo"> </a> </p> <br/> <p align="center">
1 lines • 34.5 kB
Source Map (JSON)
{"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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"}