48 lines
1.1 KiB
TypeScript
48 lines
1.1 KiB
TypeScript
import { lineWidth } from './line-width-cache.js'
|
|
|
|
type Output = {
|
|
width: number
|
|
height: number
|
|
}
|
|
|
|
// Single-pass measurement: computes both width and height in one
|
|
// iteration instead of two (widestLine + countVisualLines).
|
|
// Uses indexOf to avoid array allocation from split('\n').
|
|
function measureText(text: string, maxWidth: number): Output {
|
|
if (text.length === 0) {
|
|
return {
|
|
width: 0,
|
|
height: 0,
|
|
}
|
|
}
|
|
|
|
// Infinite or non-positive width means no wrapping — each line is one visual line.
|
|
// Must check before the loop since Math.ceil(w / Infinity) = 0.
|
|
const noWrap = maxWidth <= 0 || !Number.isFinite(maxWidth)
|
|
|
|
let height = 0
|
|
let width = 0
|
|
let start = 0
|
|
|
|
while (start <= text.length) {
|
|
const end = text.indexOf('\n', start)
|
|
const line = end === -1 ? text.substring(start) : text.substring(start, end)
|
|
|
|
const w = lineWidth(line)
|
|
width = Math.max(width, w)
|
|
|
|
if (noWrap) {
|
|
height++
|
|
} else {
|
|
height += w === 0 ? 1 : Math.ceil(w / maxWidth)
|
|
}
|
|
|
|
if (end === -1) break
|
|
start = end + 1
|
|
}
|
|
|
|
return { width, height }
|
|
}
|
|
|
|
export default measureText
|