{"version":3,"file":"canvasTextSplit.mjs","sources":["../../../../src/scene/text/utils/canvasTextSplit.ts"],"sourcesContent":["import { Matrix } from '../../../maths/matrix/Matrix';\nimport { Container } from '../../container/Container';\nimport { FillGradient } from '../../graphics/shared/fill/FillGradient';\nimport { type SplitOptions } from '../../text-split/SplitText';\nimport { type TextSplitOutput } from '../../text-split/types';\nimport { CanvasTextGenerator } from '../canvas/CanvasTextGenerator';\nimport { CanvasTextMetrics } from '../canvas/CanvasTextMetrics';\nimport { type TextStyleRun } from '../canvas/utils/parseTaggedText';\nimport { Text } from '../Text';\nimport { type TextStyle } from '../TextStyle';\n\ninterface GroupedSegment\n{\n    line: string;\n    chars: string[];\n}\n\nfunction getAlignmentOffset(alignment: string, lineWidth: number, largestLine: number): number\n{\n    switch (alignment)\n    {\n        case 'center':\n            return (largestLine - lineWidth) / 2;\n        case 'right':\n            return largestLine - lineWidth;\n        case 'left':\n        default:\n            return 0;\n    }\n}\n\nfunction isNewlineCharacter(char: string): boolean\n{\n    return char === '\\r' || char === '\\n' || char === '\\r\\n';\n}\n\nconst whitespaceRegex = /^\\s*$/;\n\n/**\n * Groups text segments into lines based on measured text metrics\n * @param segments - Array of text segments to group\n * @param measuredText - The pre-measured text metrics\n * @param measuredText.lines\n * @returns Array of grouped segments containing line information\n */\nfunction groupTextSegments(\n    segments: string[],\n    measuredText: { lines: string[] },\n): GroupedSegment[]\n{\n    const groupedSegments: GroupedSegment[] = [];\n    let currentLine = measuredText.lines[0];\n    let matchedLine = '';\n    let chars: string[] = [];\n    let lineCount = 0;\n\n    segments.forEach((segment) =>\n    {\n        const isWhitespace = whitespaceRegex.test(segment);\n        const isNewline = isNewlineCharacter(segment);\n        const isSpaceAtStart = matchedLine.length === 0 && isWhitespace;\n\n        if (isWhitespace && !isNewline && isSpaceAtStart)\n        {\n            return;\n        }\n\n        if (!isNewline) matchedLine += segment;\n\n        chars.push(segment);\n\n        if (matchedLine.length >= currentLine.length)\n        {\n            groupedSegments.push({\n                line: matchedLine,\n                chars,\n            });\n            chars = [];\n            matchedLine = '';\n            lineCount++;\n            currentLine = measuredText.lines[lineCount];\n        }\n    });\n\n    return groupedSegments;\n}\n\n/**\n * Splits a Text object into segments based on the text's layout and style,\n * and adds these segments as individual Text objects to a specified container.\n *\n * This function handles word wrapping, alignment, and letter spacing,\n * ensuring that each segment is rendered correctly according to the original text's style.\n * It uses the CanvasTextMetrics to measure text dimensions and segment the text into lines.\n * @param options - Configuration options for the text split operation.\n * @returns An array of Text objects representing the split segments.\n * @internal\n */\nexport function canvasTextSplit(\n    options: Pick<SplitOptions, 'text' | 'style'> & { chars: Text[] },\n): TextSplitOutput<Text>\n{\n    const { text, style, chars: existingChars } = options;\n    const textStyle = style as TextStyle;\n\n    // measure the entire text to get the layout\n    const measuredText = CanvasTextMetrics.measureText(text, textStyle);\n\n    if (measuredText.runsByLine && measuredText.runsByLine.length > 0)\n    {\n        return canvasTaggedTextSplitFromRuns(measuredText, textStyle, existingChars, text);\n    }\n\n    // split the text into segments\n    const segments = CanvasTextMetrics.graphemeSegmenter(text);\n    // now group the segments into lines based on measured lines\n    const groupedSegments: GroupedSegment[] = groupTextSegments(segments, measuredText);\n\n    const alignment = textStyle.align;\n    const maxLineWidth = measuredText.lineWidths.reduce((max, line) => Math.max(max, line), 0);\n    const isSingleLine = measuredText.lines.length === 1;\n    // For single-line text, alignment has no effect (nothing to align relative to)\n    // Multi-line text uses wordWrapWidth when word wrap is enabled\n    const useWordWrapWidth = !isSingleLine && textStyle.wordWrap;\n    const alignWidth = useWordWrapWidth ? Math.max(textStyle.wordWrapWidth, maxLineWidth) : maxLineWidth;\n\n    // Check if fill or stroke contains a gradient that needs offset/bounds\n    const fillGradient = textStyle._fill?.fill;\n    const strokeGradient = textStyle._stroke?.fill;\n\n    const hasFillGradient = fillGradient instanceof FillGradient;\n    const hasStrokeGradient = strokeGradient instanceof FillGradient;\n    const hasGradient = hasFillGradient || hasStrokeGradient;\n    const hasLocalGradient = (hasFillGradient && fillGradient.textureSpace === 'local')\n        || (hasStrokeGradient && strokeGradient.textureSpace === 'local');\n\n    // Store full text dimensions for gradient calculation\n    const fullTextWidth = measuredText.width;\n    const fullTextHeight = measuredText.height;\n\n    // Clone style for individual characters with left alignment.\n    // Container-level positioning handles alignment via getAlignmentOffset().\n    // Without this, each character applies its own alignment offset within its measurement area.\n    const baseCharStyle = textStyle.clone();\n\n    baseCharStyle.align = 'left';\n\n    // When trim is enabled on the style, calculate the trim offset for the whole text block once,\n    // then disable trim on individual characters and offset all characters to compensate\n    let trimOffsetX = 0;\n    let trimOffsetY = 0;\n\n    if (baseCharStyle.trim)\n    {\n        const { frame, canvasAndContext } = CanvasTextGenerator.getCanvasAndContext({\n            text,\n            style: textStyle,\n            resolution: 1,\n        });\n\n        CanvasTextGenerator.returnCanvasAndContext(canvasAndContext);\n\n        trimOffsetX = -frame.x;\n        trimOffsetY = -frame.y;\n\n        // Disable trim for individual characters; we'll use the whole-text trim offset instead\n        baseCharStyle.trim = false;\n    }\n\n    // now create Text objects for each segment and add them to the container\n    const chars: Text[] = [];\n    const lineContainers: Container[] = [];\n    const wordContainers: Container[] = [];\n    let yOffset = 0;\n    let existingCharIndex = 0;\n\n    // Cache gradient bounds object; identical for every character\n    const gradientBounds = hasLocalGradient ? { width: fullTextWidth, height: fullTextHeight } : null;\n\n    groupedSegments.forEach((group, lineIndex) =>\n    {\n        const lineContainer = new Container({ label: `line-${lineIndex}` });\n\n        lineContainer.y = yOffset + trimOffsetY;\n        lineContainers.push(lineContainer);\n\n        const lineWidth = measuredText.lineWidths[lineIndex];\n        let xOffset = getAlignmentOffset(alignment, lineWidth, alignWidth);\n\n        let currentWordContainer = new Container({ label: 'word' });\n\n        currentWordContainer.x = xOffset + trimOffsetX;\n\n        // Use remaining-width technique for kerning-aware character positioning\n        const context = CanvasTextMetrics._context;\n\n        context.font = baseCharStyle._fontString;\n        if (CanvasTextMetrics.experimentalLetterSpacingSupported)\n        {\n            context.letterSpacing = '0px';\n            context.textLetterSpacing = '0px';\n        }\n\n        let remainingLineText = group.line;\n        let previousRemainingWidth = context.measureText(remainingLineText).width;\n\n        group.chars.forEach((segment) =>\n        {\n            if (isNewlineCharacter(segment))\n            {\n                return;\n            }\n\n            remainingLineText = remainingLineText.slice(segment.length);\n            const currentRemainingWidth = remainingLineText.length > 0\n                ? context.measureText(remainingLineText).width : 0;\n            const charAdvance = previousRemainingWidth - currentRemainingWidth;\n\n            previousRemainingWidth = currentRemainingWidth;\n\n            if (charAdvance === 0) return;\n\n            if (segment === ' ')\n            {\n                if (currentWordContainer.children.length > 0)\n                {\n                    wordContainers.push(currentWordContainer);\n                    lineContainer.addChild(currentWordContainer);\n                }\n\n                xOffset += charAdvance + textStyle.letterSpacing;\n                currentWordContainer = new Container({ label: 'word' });\n                currentWordContainer.x = xOffset + trimOffsetX;\n            }\n            else\n            {\n                let charStyle = baseCharStyle;\n\n                if (hasGradient)\n                {\n                    charStyle = baseCharStyle.clone();\n                    charStyle._gradientOffset = { x: -xOffset, y: -yOffset };\n                    if (gradientBounds)\n                    {\n                        charStyle._gradientBounds = gradientBounds;\n                    }\n                }\n\n                let char: Text;\n\n                if (existingCharIndex < existingChars.length)\n                {\n                    char = existingChars[existingCharIndex++];\n\n                    char.text = segment;\n                    char.style = charStyle;\n                    char.setFromMatrix(Matrix.IDENTITY);\n                    char.x = xOffset - currentWordContainer.x + trimOffsetX;\n                }\n                else\n                {\n                    char = new Text({\n                        text: segment,\n                        style: charStyle,\n                        x: xOffset - currentWordContainer.x + trimOffsetX,\n                    });\n                }\n\n                chars.push(char);\n                currentWordContainer.addChild(char);\n                xOffset += charAdvance + textStyle.letterSpacing;\n            }\n        });\n\n        // Add the last word container of the line if it has children\n        if (currentWordContainer.children.length > 0)\n        {\n            wordContainers.push(currentWordContainer);\n            lineContainer.addChild(currentWordContainer);\n        }\n\n        // Justify: distribute extra space among word gaps\n        if (alignment === 'justify' && textStyle.wordWrap && lineIndex < groupedSegments.length - 1)\n        {\n            const lineWords = lineContainer.children;\n            const wordGaps = lineWords.length - 1;\n\n            if (wordGaps > 0)\n            {\n                const extraPerGap = (alignWidth - lineWidth) / wordGaps;\n\n                for (let i = 1; i < lineWords.length; i++)\n                {\n                    lineWords[i].x += i * extraPerGap;\n                }\n            }\n        }\n\n        yOffset += measuredText.lineHeight;\n    });\n\n    return { chars, lines: lineContainers, words: wordContainers };\n}\n\nfunction canvasTaggedTextSplitFromRuns(\n    measuredText: CanvasTextMetrics,\n    textStyle: TextStyle,\n    existingChars: Text[],\n    text: string,\n): TextSplitOutput<Text>\n{\n    const { runsByLine } = measuredText;\n    const alignment = textStyle.align;\n    const maxLineWidth = measuredText.lineWidths.reduce((max, line) => Math.max(max, line), 0);\n    const isSingleLine = measuredText.lines.length === 1;\n    const useWordWrapWidth = !isSingleLine && textStyle.wordWrap;\n    const alignWidth = useWordWrapWidth ? Math.max(textStyle.wordWrapWidth, maxLineWidth) : maxLineWidth;\n\n    let trimOffsetX = 0;\n    let trimOffsetY = 0;\n\n    if (textStyle.trim)\n    {\n        const { frame, canvasAndContext } = CanvasTextGenerator.getCanvasAndContext({\n            text,\n            style: textStyle,\n            resolution: 1,\n        });\n\n        CanvasTextGenerator.returnCanvasAndContext(canvasAndContext);\n        trimOffsetX = -frame.x;\n        trimOffsetY = -frame.y;\n    }\n\n    const chars: Text[] = [];\n    const lineContainers: Container[] = [];\n    const wordContainers: Container[] = [];\n    let yOffset = 0;\n    let existingCharIndex = 0;\n\n    runsByLine.forEach((lineRuns: TextStyleRun[], lineIndex: number) =>\n    {\n        const lineContainer = new Container({ label: `line-${lineIndex}` });\n\n        lineContainer.y = yOffset + trimOffsetY;\n        lineContainers.push(lineContainer);\n\n        const lineWidth = measuredText.lineWidths[lineIndex];\n        let xOffset = getAlignmentOffset(alignment, lineWidth, alignWidth);\n\n        let currentWordContainer = new Container({ label: 'word' });\n\n        currentWordContainer.x = xOffset + trimOffsetX;\n\n        for (const run of lineRuns)\n        {\n            const runStyle = run.style;\n\n            const fillGradient = runStyle._fill?.fill;\n            const strokeGradient = runStyle._stroke?.fill;\n            const hasFillGradient = fillGradient instanceof FillGradient;\n            const hasStrokeGradient = strokeGradient instanceof FillGradient;\n            const hasGradient = hasFillGradient || hasStrokeGradient;\n            const hasLocalGradient = (hasFillGradient && fillGradient.textureSpace === 'local')\n                || (hasStrokeGradient && strokeGradient.textureSpace === 'local');\n\n            const graphemes = CanvasTextMetrics.graphemeSegmenter(run.text);\n\n            const baseRunStyle = runStyle.clone();\n\n            baseRunStyle.align = 'left';\n            baseRunStyle.wordWrap = false;\n            if (baseRunStyle.trim) baseRunStyle.trim = false;\n            baseRunStyle.tagStyles = undefined;\n\n            // Use remaining-width technique for kerning-aware character positioning\n            const context = CanvasTextMetrics._context;\n\n            context.font = baseRunStyle._fontString;\n            if (CanvasTextMetrics.experimentalLetterSpacingSupported)\n            {\n                context.letterSpacing = '0px';\n                context.textLetterSpacing = '0px';\n            }\n\n            let remainingText = run.text;\n            let previousRemainingWidth = context.measureText(remainingText).width;\n            const runStartX = xOffset;\n            const runTextWidth = previousRemainingWidth;\n            const runFontProps = CanvasTextMetrics.measureFont(baseRunStyle._fontString);\n            const runHeight = runStyle.lineHeight || runFontProps.fontSize;\n            const runGradientBounds = hasLocalGradient\n                ? { width: runTextWidth, height: runHeight } : null;\n\n            for (const grapheme of graphemes)\n            {\n                remainingText = remainingText.slice(grapheme.length);\n                const currentRemainingWidth = remainingText.length > 0\n                    ? context.measureText(remainingText).width : 0;\n                const charAdvance = previousRemainingWidth - currentRemainingWidth;\n\n                previousRemainingWidth = currentRemainingWidth;\n\n                if (isNewlineCharacter(grapheme)) continue;\n                if (charAdvance === 0) continue;\n\n                if (grapheme === ' ')\n                {\n                    if (currentWordContainer.children.length > 0)\n                    {\n                        wordContainers.push(currentWordContainer);\n                        lineContainer.addChild(currentWordContainer);\n                    }\n                    xOffset += charAdvance + runStyle.letterSpacing;\n                    currentWordContainer = new Container({ label: 'word' });\n                    currentWordContainer.x = xOffset + trimOffsetX;\n                }\n                else\n                {\n                    let charStyle = baseRunStyle;\n\n                    if (hasGradient)\n                    {\n                        charStyle = baseRunStyle.clone();\n                        if (hasLocalGradient)\n                        {\n                            charStyle._gradientOffset = { x: -(xOffset - runStartX), y: 0 };\n                            charStyle._gradientBounds = runGradientBounds;\n                        }\n                        else\n                        {\n                            charStyle._gradientOffset = { x: -(xOffset - runStartX), y: 0 };\n                        }\n                    }\n\n                    let char: Text;\n\n                    if (existingCharIndex < existingChars.length)\n                    {\n                        char = existingChars[existingCharIndex++];\n                        char.text = grapheme;\n                        char.style = charStyle;\n                        char.setFromMatrix(Matrix.IDENTITY);\n                        char.x = xOffset - currentWordContainer.x + trimOffsetX;\n                    }\n                    else\n                    {\n                        char = new Text({\n                            text: grapheme,\n                            style: charStyle,\n                            x: xOffset - currentWordContainer.x + trimOffsetX,\n                        });\n                    }\n\n                    chars.push(char);\n                    currentWordContainer.addChild(char);\n                    xOffset += charAdvance + runStyle.letterSpacing;\n                }\n            }\n        }\n\n        if (currentWordContainer.children.length > 0)\n        {\n            wordContainers.push(currentWordContainer);\n            lineContainer.addChild(currentWordContainer);\n        }\n\n        // Justify: distribute extra space among word gaps\n        if (alignment === 'justify' && textStyle.wordWrap && lineIndex < runsByLine.length - 1)\n        {\n            const lineWords = lineContainer.children;\n            const wordGaps = lineWords.length - 1;\n\n            if (wordGaps > 0)\n            {\n                const extraPerGap = (alignWidth - lineWidth) / wordGaps;\n\n                for (let i = 1; i < lineWords.length; i++)\n                {\n                    lineWords[i].x += i * extraPerGap;\n                }\n            }\n        }\n\n        const lineHeight = measuredText.lineHeights?.[lineIndex] ?? measuredText.lineHeight;\n\n        yOffset += lineHeight;\n    });\n\n    return { chars, lines: lineContainers, words: wordContainers };\n}\n"],"names":[],"mappings":"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"}