pptx-ts 4.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +147 -114
- package/dist/{autopage-odPz7zZO.js → autopage-D4kyVp11.js} +5 -5
- package/dist/{autopage-odPz7zZO.js.map → autopage-D4kyVp11.js.map} +1 -1
- package/dist/{body-insets-Dw_BeWD_.js → body-insets-kVHmjGc6.js} +2 -2
- package/dist/{body-insets-Dw_BeWD_.js.map → body-insets-kVHmjGc6.js.map} +1 -1
- package/dist/browser.d.ts +7 -7
- package/dist/browser.js +5 -5
- package/dist/{clip-Bl01BPcN.d.ts → clip-DHDlnHUq.d.ts} +2 -2
- package/dist/{clip-Bl01BPcN.d.ts.map → clip-DHDlnHUq.d.ts.map} +1 -1
- package/dist/{diagnostics-D8ot4Ei7.d.ts → diagnostics-DiMmBU8P.d.ts} +6 -6
- package/dist/{diagnostics-D8ot4Ei7.d.ts.map → diagnostics-DiMmBU8P.d.ts.map} +1 -1
- package/dist/{embedded-fonts-DarT9aoa.d.ts → embedded-fonts-CI_YGW2d.d.ts} +2 -2
- package/dist/{embedded-fonts-DarT9aoa.d.ts.map → embedded-fonts-CI_YGW2d.d.ts.map} +1 -1
- package/dist/{entry-compose-DCnvBZz2.d.ts → entry-compose-6hF9aTmT.d.ts} +19 -17
- package/dist/{entry-compose-DCnvBZz2.d.ts.map → entry-compose-6hF9aTmT.d.ts.map} +1 -1
- package/dist/{enums-BUKTUB6V.d.ts → enums-DQRpVOLh.d.ts} +3 -3
- package/dist/{enums-BUKTUB6V.d.ts.map → enums-DQRpVOLh.d.ts.map} +1 -1
- package/dist/{errors-C4oENPcu.js → errors-Da2nXCJm.js} +6 -6
- package/dist/{errors-C4oENPcu.js.map → errors-Da2nXCJm.js.map} +1 -1
- package/dist/families.d.ts +6 -6
- package/dist/families.js +2 -2
- package/dist/{fit-Cb7naFj6.js → fit-CcXbg__l.js} +10 -10
- package/dist/{fit-Cb7naFj6.js.map → fit-CcXbg__l.js.map} +1 -1
- package/dist/{font-metrics-v5fn7s7e.d.ts → font-metrics-CBGmhLo0.d.ts} +6 -6
- package/dist/{font-metrics-v5fn7s7e.d.ts.map → font-metrics-CBGmhLo0.d.ts.map} +1 -1
- package/dist/{grid-DikTjFey.js → grid-9B2w5EaY.js} +2 -2
- package/dist/{grid-DikTjFey.js.map → grid-9B2w5EaY.js.map} +1 -1
- package/dist/{html-dom-Iuog2wdK.js → html-dom-DvJmuHt2.js} +10 -10
- package/dist/html-dom-DvJmuHt2.js.map +1 -0
- package/dist/html.d.ts +3 -3
- package/dist/html.js +2 -2
- package/dist/{image-size-CvN2iCA4.js → image-size-DwDbakcl.js} +64 -5
- package/dist/image-size-DwDbakcl.js.map +1 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +3 -3
- package/dist/inspect.d.ts +4 -4
- package/dist/inspect.js +4 -4
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/math.js +1 -1
- package/dist/measure.d.ts +3 -3
- package/dist/measure.js +2 -2
- package/dist/node.d.ts +7 -7
- package/dist/node.js +3 -3
- package/dist/{notes-Dh12JAbn.js → notes-BcT571R4.js} +19 -18
- package/dist/notes-BcT571R4.js.map +1 -0
- package/dist/options-internal-WqgMf720.js.map +1 -1
- package/dist/{package-J49Ck6S2.d.ts → package-KoEgVwII.d.ts} +6 -2
- package/dist/{package-J49Ck6S2.d.ts.map → package-KoEgVwII.d.ts.map} +1 -1
- package/dist/{pres-C6qgOFAa.d.ts → pres-BA9_lJbY.d.ts} +32 -12
- package/dist/pres-BA9_lJbY.d.ts.map +1 -0
- package/dist/{presentation-DGYlAWhl.js → presentation-Cyl74rq2.js} +70 -35
- package/dist/presentation-Cyl74rq2.js.map +1 -0
- package/dist/{presentation-types-8jLQHI4M.d.ts → presentation-types-B3VQH4Bz.d.ts} +19 -15
- package/dist/presentation-types-B3VQH4Bz.d.ts.map +1 -0
- package/dist/read.d.ts +6 -6
- package/dist/read.js +3 -3
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +11 -11
- package/dist/script.js.map +1 -1
- package/dist/{shapes-re0KyQk_.js → shapes-BcyFdZpp.js} +14 -10
- package/dist/shapes-BcyFdZpp.js.map +1 -0
- package/dist/{slide-Dx2ZeVZ6.d.ts → slide-BqPtyKmb.d.ts} +12 -7
- package/dist/slide-BqPtyKmb.d.ts.map +1 -0
- package/dist/{table-cell-margins-EVg0EwxT.js → table-cell-margins-PDshga8T.js} +4 -4
- package/dist/{table-cell-margins-EVg0EwxT.js.map → table-cell-margins-PDshga8T.js.map} +1 -1
- package/dist/{table-dom-BTDP3lEP.js → table-dom-CVbvUfgh.js} +3 -3
- package/dist/{table-dom-BTDP3lEP.js.map → table-dom-CVbvUfgh.js.map} +1 -1
- package/dist/{text-sN64Otf_.js → text-BvFFMMFQ.js} +38 -36
- package/dist/{text-sN64Otf_.js.map → text-BvFFMMFQ.js.map} +1 -1
- package/dist/{text-anchor-CrYXAfUu.js → text-anchor-BgLPbwbL.js} +2 -2
- package/dist/{text-anchor-CrYXAfUu.js.map → text-anchor-BgLPbwbL.js.map} +1 -1
- package/dist/{units-internal-XJlf-hOl.js → units-internal-DFcUYjh3.js} +11 -6
- package/dist/units-internal-DFcUYjh3.js.map +1 -0
- package/dist/{zip-C0leZZMj.d.ts → zip-CTll_dr0.d.ts} +2 -2
- package/dist/{zip-C0leZZMj.d.ts.map → zip-CTll_dr0.d.ts.map} +1 -1
- package/dist/{zip-CKd8ihcf.js → zip-CYZ0F6BV.js} +2 -2
- package/dist/{zip-CKd8ihcf.js.map → zip-CYZ0F6BV.js.map} +1 -1
- package/dist/zip.d.ts +2 -2
- package/dist/zip.js +2 -2
- package/dist/{zoom-DPUHh85d.js → zoom-BoNyOlPm.js} +65 -51
- package/dist/zoom-BoNyOlPm.js.map +1 -0
- package/package.json +39 -31
- package/skills/ts-pptx-upstream/SKILL.md +18 -18
- package/dist/html-dom-Iuog2wdK.js.map +0 -1
- package/dist/image-size-CvN2iCA4.js.map +0 -1
- package/dist/notes-Dh12JAbn.js.map +0 -1
- package/dist/pres-C6qgOFAa.d.ts.map +0 -1
- package/dist/presentation-DGYlAWhl.js.map +0 -1
- package/dist/presentation-types-8jLQHI4M.d.ts.map +0 -1
- package/dist/shapes-re0KyQk_.js.map +0 -1
- package/dist/slide-Dx2ZeVZ6.d.ts.map +0 -1
- package/dist/units-internal-XJlf-hOl.js.map +0 -1
- package/dist/zoom-DPUHh85d.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fit-Cb7naFj6.js","names":["resolveMarginInsetsEmu"],"sources":["../src/measure/font-collection.ts","../src/measure/font-metrics.ts","../src/measure/text-fit.ts","../src/measure/paragraphs.ts","../src/gen/table/cell-inherit.ts","../src/measure/table-fit.ts","../src/measure/fit.ts"],"sourcesContent":["/**\n * Font **collection** (`.ttc` / `.otc`) support for the write-side metrics.\n *\n * A collection is a single file holding several fonts that share their heavy tables.\n * `msgothic.ttc` is three fonts (MS Gothic, MS UI Gothic, MS PGothic) over one 5.5 MB\n * `glyf`; `cambria.ttc` is Cambria plus Cambria Math over one outline set. On Windows\n * that is how most of the East Asian faces ship, and Cambria too, so a measurement API\n * that only reads a bare sfnt cannot measure them at all.\n *\n * `opentype.js` does not read the `ttcf` wrapper (it throws `Unsupported OpenType\n * signature ttcf` from `parseBuffer`, still true in 2.0.0), so this module unwraps one\n * member into a standalone sfnt before handing the bytes over. It parses only the two\n * structures that requires: the table directories and the `name` table.\n *\n * Upstream tracks the gap as opentypejs/opentype.js#379, open since 2019, with #866 an\n * unmerged PR implementing it; check both before rewriting any of this.\n *\n * ## Layout\n *\n * ```text\n * 0 'ttcf' uint16 major, uint16 minor, uint32 numFonts, uint32 dirOffset[numFonts]\n * ... per member: uint32 sfntVersion, uint16 numTables, uint16 searchRange,\n * uint16 entrySelector, uint16 rangeShift, then numTables x 16-byte records\n * { char tag[4], uint32 checksum, uint32 offset, uint32 length }\n * ```\n *\n * The record `offset` is **absolute from the start of the file**, which is the whole\n * trick: two members name the same `glyf` bytes by pointing at them. So a member does\n * not have to be *copied out* to be read on its own; it is enough to give the reader a\n * buffer whose first bytes are that member's directory, leaving every table where it\n * already sits. See {@link extractFontFace}.\n */\n\nimport { InvalidOptionError, MediaError } from '../errors.js'\n\n/** `'ttcf'`, the tag that marks a font collection. */\nconst TTC_TAG = 'ttcf'\n\n/** Bytes in one sfnt table record: tag, checksum, offset, length. */\nconst RECORD_SIZE = 16\n\n/** Bytes in an sfnt table directory header, before the first record. */\nconst DIRECTORY_HEADER_SIZE = 12\n\n/** `name` IDs read for face identity: family, subfamily, full name, PostScript name. */\nconst NAME_FAMILY = 1\nconst NAME_SUBFAMILY = 2\nconst NAME_FULL = 4\nconst NAME_POSTSCRIPT = 6\n\n/** Identity of one font inside a font file, as read from its `name` table. */\nexport interface FontFaceInfo {\n\t/** Position in the file: `0` for a plain TTF/OTF, `0..n-1` inside a collection. */\n\treadonly index: number\n\t/** `name` ID 1, e.g. `'MS PGothic'`. Absent when the table has no readable record. */\n\treadonly family?: string\n\t/** `name` ID 2, e.g. `'Regular'`. */\n\treadonly subfamily?: string\n\t/** `name` ID 4, e.g. `'MS PGothic'`. */\n\treadonly fullName?: string\n\t/** `name` ID 6, e.g. `'MS-PGothic'`. */\n\treadonly postScriptName?: string\n}\n\n/** A parsed sfnt table directory: the member's format tag plus its table records. */\ninterface Directory {\n\treadonly sfntVersion: number\n\treadonly tables: readonly TableRecord[]\n}\n\ninterface TableRecord {\n\t/** Four ASCII characters, e.g. `'glyf'`. */\n\treadonly tag: string\n\treadonly checksum: number\n\t/** Absolute from the start of the file, shared between members of a collection. */\n\treadonly offset: number\n\treadonly length: number\n}\n\nfunction view(data: Uint8Array): DataView {\n\treturn new DataView(data.buffer, data.byteOffset, data.byteLength)\n}\n\n/** Four ASCII bytes at `off` as a string, or `''` when they run past the end. */\nfunction tagAt(data: Uint8Array, off: number): string {\n\tif (off < 0 || off + 4 > data.byteLength) return ''\n\tlet s = ''\n\tfor (let i = 0; i < 4; i++) s += String.fromCharCode(data[off + i] as number)\n\treturn s\n}\n\n/** True when `data` starts with the `ttcf` tag, i.e. holds more than one font. */\nexport function isFontCollection(data: Uint8Array): boolean {\n\treturn tagAt(data, 0) === TTC_TAG\n}\n\n/**\n * Offsets of every member's table directory, in file order. A plain sfnt has exactly\n * one, at 0.\n */\nfunction directoryOffsets(data: Uint8Array): number[] {\n\tif (!isFontCollection(data)) return [0]\n\tconst dv = view(data)\n\tif (data.byteLength < 12) throw new MediaError('font/parse-failed', 'Font collection header is truncated')\n\tconst numFonts = dv.getUint32(8)\n\t// A collection with no members, or one whose offset table cannot fit, is malformed\n\t// rather than merely unsupported: there is nothing to select from.\n\tif (numFonts === 0) throw new MediaError('font/parse-failed', 'Font collection declares 0 fonts')\n\tif (12 + numFonts * 4 > data.byteLength)\n\t\tthrow new MediaError(\n\t\t\t'font/parse-failed',\n\t\t\t`Font collection declares ${numFonts} fonts but the offset table is truncated`\n\t\t)\n\tconst offsets: number[] = []\n\tfor (let i = 0; i < numFonts; i++) offsets.push(dv.getUint32(12 + i * 4))\n\treturn offsets\n}\n\n/** Read the table directory at `dirOff`, materializing every record before any write. */\nfunction readDirectory(data: Uint8Array, dirOff: number): Directory {\n\tconst dv = view(data)\n\tif (dirOff + DIRECTORY_HEADER_SIZE > data.byteLength)\n\t\tthrow new MediaError('font/parse-failed', `Font table directory at ${dirOff} is truncated`)\n\tconst sfntVersion = dv.getUint32(dirOff)\n\tconst numTables = dv.getUint16(dirOff + 4)\n\tif (numTables === 0) throw new MediaError('font/parse-failed', `Font at ${dirOff} declares 0 tables`)\n\tconst end = dirOff + DIRECTORY_HEADER_SIZE + numTables * RECORD_SIZE\n\tif (end > data.byteLength)\n\t\tthrow new MediaError(\n\t\t\t'font/parse-failed',\n\t\t\t`Font at ${dirOff} declares ${numTables} tables but the directory is truncated`\n\t\t)\n\tconst tables: TableRecord[] = []\n\tfor (let i = 0; i < numTables; i++) {\n\t\tconst rec = dirOff + DIRECTORY_HEADER_SIZE + i * RECORD_SIZE\n\t\ttables.push({\n\t\t\ttag: tagAt(data, rec),\n\t\t\tchecksum: dv.getUint32(rec + 4),\n\t\t\toffset: dv.getUint32(rec + 8),\n\t\t\tlength: dv.getUint32(rec + 12),\n\t\t})\n\t}\n\treturn { sfntVersion, tables }\n}\n\n/**\n * Decode one `name` record's string. Windows (platform 3) and Unicode (platform 0)\n * records are UTF-16BE; Macintosh (platform 1) Roman is byte-per-character and\n * coincides with Latin-1 over the ASCII range these names use.\n */\nfunction decodeNameString(data: Uint8Array, off: number, length: number, platformID: number): string {\n\tif (off < 0 || off + length > data.byteLength) return ''\n\tif (platformID === 1) {\n\t\tlet s = ''\n\t\tfor (let i = 0; i < length; i++) s += String.fromCharCode(data[off + i] as number)\n\t\treturn s\n\t}\n\tlet s = ''\n\tfor (let i = 0; i + 1 < length; i += 2)\n\t\ts += String.fromCharCode(((data[off + i] as number) << 8) | (data[off + i + 1] as number))\n\treturn s\n}\n\n/**\n * How much a `name` record is preferred when several carry the same ID. Windows English\n * wins, then any Windows or Unicode record, then Macintosh. The ranking matters because\n * `msgothic.ttc` carries both `'MS Gothic'` (0x409) and the Japanese localized name for\n * the same ID, and a caller selecting by name types the former.\n */\nfunction nameRecordRank(platformID: number, languageID: number): number {\n\tif (platformID === 3) return languageID === 0x409 ? 3 : 2\n\tif (platformID === 0) return 2\n\tif (platformID === 1) return languageID === 0 ? 1 : 0\n\treturn 0\n}\n\n/** Read the wanted IDs out of a `name` table, keeping the best-ranked record for each. */\nfunction readNames(data: Uint8Array, base: number, length: number): Map<number, string> {\n\tconst out = new Map<number, string>()\n\tconst ranks = new Map<number, number>()\n\tif (base + 6 > data.byteLength || base + length > data.byteLength) return out\n\tconst dv = view(data)\n\tconst count = dv.getUint16(base + 2)\n\tconst storage = base + dv.getUint16(base + 4)\n\tfor (let i = 0; i < count; i++) {\n\t\tconst rec = base + 6 + i * 12\n\t\tif (rec + 12 > data.byteLength) break\n\t\tconst nameID = dv.getUint16(rec + 6)\n\t\tif (nameID !== NAME_FAMILY && nameID !== NAME_SUBFAMILY && nameID !== NAME_FULL && nameID !== NAME_POSTSCRIPT)\n\t\t\tcontinue\n\t\tconst platformID = dv.getUint16(rec)\n\t\tconst languageID = dv.getUint16(rec + 4)\n\t\tconst rank = nameRecordRank(platformID, languageID)\n\t\tif (rank <= (ranks.get(nameID) ?? -1)) continue\n\t\tconst text = decodeNameString(data, storage + dv.getUint16(rec + 10), dv.getUint16(rec + 8), platformID)\n\t\tif (!text) continue\n\t\tout.set(nameID, text)\n\t\tranks.set(nameID, rank)\n\t}\n\treturn out\n}\n\n/**\n * The fonts inside `data`, in file order. A plain TTF/OTF yields exactly one entry, so a\n * caller never has to branch on the container format.\n *\n * Identity comes from each member's own `name` table, which is one of the tables a\n * collection does *not* share. A field is absent when the table carries no readable\n * record for it; a font whose `name` table is missing or malformed still yields an entry\n * (with only `index`), because the metrics do not depend on it.\n * @param {Uint8Array} data - the font file's bytes\n * @returns {FontFaceInfo[]} one entry per font, index-ordered\n * @example listFontFaces(readFileSync('C:/Windows/Fonts/msgothic.ttc')).map((f) => f.family)\n */\nexport function listFontFaces(data: Uint8Array): FontFaceInfo[] {\n\treturn directoryOffsets(data).map((dirOff, index) => {\n\t\tconst { tables } = readDirectory(data, dirOff)\n\t\tconst name = tables.find((t) => t.tag === 'name')\n\t\tconst names = name ? readNames(data, name.offset, name.length) : new Map<number, string>()\n\t\tconst family = names.get(NAME_FAMILY)\n\t\tconst subfamily = names.get(NAME_SUBFAMILY)\n\t\tconst fullName = names.get(NAME_FULL)\n\t\tconst postScriptName = names.get(NAME_POSTSCRIPT)\n\t\treturn {\n\t\t\tindex,\n\t\t\t...(family ? { family } : {}),\n\t\t\t...(subfamily ? { subfamily } : {}),\n\t\t\t...(fullName ? { fullName } : {}),\n\t\t\t...(postScriptName ? { postScriptName } : {}),\n\t\t}\n\t})\n}\n\n/** A face's names, lowercased, for case-insensitive selection. */\nfunction selectableNames(face: FontFaceInfo): string[] {\n\treturn [face.family, face.fullName, face.postScriptName]\n\t\t.filter((n): n is string => typeof n === 'string' && n.length > 0)\n\t\t.map((n) => n.toLowerCase())\n}\n\n/** Render the available faces for an error message, e.g. ``0 `MS Gothic`, 1 `MS PGothic` ``. */\nfunction describeFaces(faces: readonly FontFaceInfo[]): string {\n\treturn faces.map((f) => `${f.index} \\`${f.family ?? f.fullName ?? '(unnamed)'}\\``).join(', ')\n}\n\n/**\n * Resolve a `font` selector against the faces in `data`.\n *\n * The selector means the same thing whatever the container: a plain TTF/OTF is a\n * one-entry list, so `{ font: 1 }` or a name that does not match is an error there too\n * rather than being quietly ignored. Silently falling back to the only/first font is the\n * failure mode worth refusing: it measures one face's advances while the caller believes\n * it registered another's, and nothing downstream can tell.\n * @param {Uint8Array} data - the font file's bytes\n * @param {number | string} [font] - 0-based index, or a name matched case-insensitively\n * against the family, full, and PostScript names. Absent selects index 0.\n * @returns {number} the index of the selected font\n */\nexport function resolveFontFace(data: Uint8Array, font?: number | string): number {\n\tif (font === undefined) return 0\n\tconst faces = listFontFaces(data)\n\tif (typeof font === 'number') {\n\t\tif (!Number.isInteger(font) || font < 0 || font >= faces.length)\n\t\t\tthrow new InvalidOptionError(\n\t\t\t\t'font/collection-index-out-of-range',\n\t\t\t\t`Font index ${font} is out of range: the file holds ${faces.length} font(s) (${describeFaces(faces)})`\n\t\t\t)\n\t\treturn font\n\t}\n\tconst wanted = font.toLowerCase()\n\tconst hit = faces.find((f) => selectableNames(f).includes(wanted))\n\tif (!hit)\n\t\tthrow new InvalidOptionError(\n\t\t\t'font/collection-face-not-found',\n\t\t\t`No font named \"${font}\" in this file. It holds: ${describeFaces(faces)}`\n\t\t)\n\treturn hit.index\n}\n\n/**\n * Bytes for one font of `data` as a standalone sfnt, ready for a parser that does not\n * read the `ttcf` wrapper.\n *\n * A plain TTF/OTF at index 0 is returned as-is. For a collection the member's tables are\n * **not copied out**: the file is copied once and the member's directory is written over\n * the prologue at offset 0, so every record keeps the absolute offset it already had and\n * the shared `glyf` is neither duplicated nor moved. The prologue is always large enough\n * to hold that directory, because a well-formed collection places the first table after\n * the `ttcf` header *and* every member's directory, which already includes this one.\n * That is asserted rather than assumed: a file that violates it would otherwise have its\n * first table silently overwritten.\n * @param {Uint8Array} data - the font file's bytes\n * @param {number} index - which font, as resolved by {@link resolveFontFace}\n * @returns {Uint8Array} a buffer whose first bytes are a plain sfnt table directory\n */\nexport function extractFontFace(data: Uint8Array, index: number): Uint8Array {\n\tconst offsets = directoryOffsets(data)\n\tconst dirOff = offsets[index]\n\tif (dirOff === undefined)\n\t\tthrow new InvalidOptionError(\n\t\t\t'font/collection-index-out-of-range',\n\t\t\t`Font index ${index} is out of range: the file holds ${offsets.length} font(s)`\n\t\t)\n\tif (!isFontCollection(data)) return data\n\n\tconst { sfntVersion, tables } = readDirectory(data, dirOff)\n\tconst prologue = DIRECTORY_HEADER_SIZE + tables.length * RECORD_SIZE\n\tconst firstTable = Math.min(...tables.map((t) => t.offset))\n\tif (prologue > firstTable)\n\t\tthrow new MediaError(\n\t\t\t'font/parse-failed',\n\t\t\t`Font ${index} in this collection cannot be unwrapped: its ${tables.length}-table directory needs ${prologue} bytes but the first table starts at ${firstTable}`\n\t\t)\n\n\t// Copy first, then overwrite: `dirOff` frequently sits *inside* the region about to be\n\t// written (member 0 of msgothic.ttc has its directory at 36, and the prologue is 380),\n\t// which is safe only because `readDirectory` already materialized every record.\n\tconst out = new Uint8Array(data)\n\tconst dv = new DataView(out.buffer, out.byteOffset, out.byteLength)\n\tconst entrySelector = Math.floor(Math.log2(tables.length))\n\tconst searchRange = RECORD_SIZE * 2 ** entrySelector\n\tdv.setUint32(0, sfntVersion)\n\tdv.setUint16(4, tables.length)\n\tdv.setUint16(6, searchRange)\n\tdv.setUint16(8, entrySelector)\n\tdv.setUint16(10, tables.length * RECORD_SIZE - searchRange)\n\tlet p = DIRECTORY_HEADER_SIZE\n\tfor (const t of tables) {\n\t\tfor (let i = 0; i < 4; i++) out[p + i] = t.tag.charCodeAt(i) & 0xff\n\t\tdv.setUint32(p + 4, t.checksum)\n\t\tdv.setUint32(p + 8, t.offset)\n\t\tdv.setUint32(p + 12, t.length)\n\t\tp += RECORD_SIZE\n\t}\n\t// `head.checkSumAdjustment` now describes the collection rather than this buffer. No\n\t// consumer here validates it, and recomputing it would mean check-summing the whole\n\t// file to produce a number only a validator reads.\n\treturn out\n}\n","/**\n * Write-side font metrics.\n *\n * Provides per-glyph advance widths for measured text fit (see `text-fit.ts`).\n * The library has no write-side font registration otherwise; consumers register\n * a face's font file via `pptx.registerFontMetrics(...)` and the measured-fit\n * pass uses these advances to compute a baked `fontScale` for `fit: 'shrink'`.\n *\n * Width is summed from **raw `hmtx` advances with no kerning/shaping** (GPOS/GSUB\n * are deliberately ignored): kerning almost always narrows a line, so raw advances\n * over-estimate width — the conservative direction (shrink a touch too much, never\n * overflow). See `docs/contributing/design/text-fit.md` (\"Font metrics provider\").\n */\n\nimport { InvalidOptionError, MediaError, UnsupportedFeatureError } from '../errors.js'\nimport { extractFontFace, resolveFontFace } from './font-collection.js'\nimport type { FitParagraph, MetricsResolver } from './text-fit.js'\n\n/** Per-(face,bold,italic) advance-width source backed by a parsed font file. */\nexport interface FontMetrics {\n\t/** Font design units per em (advances are in these units). */\n\treadonly unitsPerEm: number\n\t/**\n\t * Advance width of `text` at `sizePt`, in points. Sums raw glyph advances\n\t * (no kerning) and adds `charSpacingPt` after every character, matching how\n\t * PowerPoint widens runs with character spacing.\n\t */\n\tadvanceWidthPt: (text: string, sizePt: number, charSpacingPt?: number) => number\n\t/**\n\t * True if this face's cmap maps code point `cp` to a real glyph (not the\n\t * `.notdef` fallback). Use it to flag source code points the face cannot\n\t * render. Authoritative only for file-backed metrics; the unregistered-font\n\t * heuristic has no cmap and reports every code point as covered.\n\t */\n\thasCodepoint: (cp: number) => boolean\n}\n\n/** Minimal slice of an opentype.js `Font` that `OpentypeFontMetrics` relies on. */\ninterface OpentypeFontLike {\n\tunitsPerEm: number\n\tcharToGlyph: (ch: string) => { advanceWidth?: number } | undefined\n\thasChar: (ch: string) => boolean\n}\n\nclass OpentypeFontMetrics implements FontMetrics {\n\tprivate readonly font: OpentypeFontLike\n\tconstructor(font: OpentypeFontLike) {\n\t\tthis.font = font\n\t}\n\n\tget unitsPerEm(): number {\n\t\treturn this.font.unitsPerEm\n\t}\n\n\tadvanceWidthPt(text: string, sizePt: number, charSpacingPt = 0): number {\n\t\tif (!text) return 0\n\t\t// Sum raw per-glyph `hmtx` advances via cmap (charToGlyph) — deliberately\n\t\t// NOT getAdvanceWidth(), which runs GPOS/GSUB shaping (kerning narrows lines,\n\t\t// and some lookups even throw). Raw advances over-estimate width, the\n\t\t// conservative direction. `for..of` iterates code points (astral-safe).\n\t\tconst scale = sizePt / this.font.unitsPerEm\n\t\tlet width = 0\n\t\tlet count = 0\n\t\tfor (const ch of text) {\n\t\t\tconst glyph = this.font.charToGlyph(ch)\n\t\t\twidth += (glyph?.advanceWidth ?? 0) * scale\n\t\t\tcount++\n\t\t}\n\t\tif (charSpacingPt) width += charSpacingPt * count\n\t\treturn width\n\t}\n\n\thasCodepoint(cp: number): boolean {\n\t\t// opentype's charToGlyph() falls back to .notdef for uncovered code points,\n\t\t// so it can't answer coverage; hasChar() keys on the cmap (glyph index > 0).\n\t\treturn this.font.hasChar(String.fromCodePoint(cp))\n\t}\n}\n\nconst HEURISTIC_UNITS_PER_EM = 1000\n\n/**\n * Advance width of an ASCII/Unicode code point as a fraction of em, for the\n * unregistered-font fallback. Values are biased to **over-estimate** a typical\n * proportional Latin face: over-estimating width is the conservative direction for\n * both solvers (shrink a touch too much / grow a touch too tall, never overflow).\n * Non-Latin code points are treated as full-em (safe for CJK, which is otherwise\n * out of scope; slightly over-wide for accented Latin, which is harmless).\n */\nfunction heuristicCharRatio(ch: string): number {\n\tconst cp = ch.codePointAt(0) ?? 0\n\tif (cp > 0x2e7f) return 1.0 // CJK / full-width and beyond\n\tif (cp > 0xff) return 0.62 // Latin-Extended / accented / misc symbols\n\tif (ch === ' ' || ch === '\\t') return 0.3\n\tif (\"ijl.,'`!|:;\".includes(ch)) return 0.3\n\tif ('ftr()[]{}/\\\\I'.includes(ch)) return 0.4\n\tif (ch === 'm' || ch === 'w') return 0.9\n\tif (ch === 'M' || ch === 'W') return 0.98\n\tif (ch === '@' || ch === '%') return 1.0\n\tif (ch >= 'A' && ch <= 'Z') return 0.72\n\treturn 0.58 // lowercase, digits, default punctuation\n}\n\nclass HeuristicFontMetrics implements FontMetrics {\n\treadonly unitsPerEm = HEURISTIC_UNITS_PER_EM\n\tadvanceWidthPt(text: string, sizePt: number, charSpacingPt = 0): number {\n\t\tif (!text) return 0\n\t\tlet width = 0\n\t\tlet count = 0\n\t\tfor (const ch of text) {\n\t\t\twidth += heuristicCharRatio(ch) * sizePt\n\t\t\tcount++\n\t\t}\n\t\tif (charSpacingPt) width += charSpacingPt * count\n\t\treturn width\n\t}\n\n\thasCodepoint(): boolean {\n\t\treturn true // no cmap to consult; never fabricate a 'missing' glyph\n\t}\n}\n\nlet heuristicSingleton: FontMetrics | undefined\n\n/**\n * Shared, font-independent `FontMetrics` used when a named face has no registered\n * metrics but the deck has opted into measured fit (some other face is registered).\n * Approximate but conservative — see `heuristicCharRatio`. A deck with no\n * registered metrics at all does not engage measured fit, so this never fires there.\n */\nexport function getHeuristicFontMetrics(): FontMetrics {\n\tif (!heuristicSingleton) heuristicSingleton = new HeuristicFontMetrics()\n\treturn heuristicSingleton\n}\n\n/** Options for {@link parseFontMetrics}. */\nexport interface ParseFontMetricsOptions {\n\t/**\n\t * Which font to read out of a file that holds several: a 0-based index, or a name\n\t * matched case-insensitively against the family, full, and PostScript names\n\t * (`listFontFaces` lists them). Omitted selects the first.\n\t *\n\t * Collections (`.ttc`/`.otc`) are why this exists: `msgothic.ttc` is three fonts and\n\t * `cambria.ttc` is two. The selector means the same thing for a plain TTF/OTF, which\n\t * is a one-entry list, so a wrong index or an unmatched name is an error there rather\n\t * than being ignored.\n\t */\n\treadonly font?: number | string\n}\n\n/**\n * Parse a font file into a `FontMetrics`. Lazily imports opentype.js.\n *\n * Reads plain TTF/OTF and **font collections** (`.ttc`/`.otc`); for a collection, pass\n * `font` to say which member, since a collection has no single answer. The underlying\n * parser does not read the `ttcf` wrapper, so the selected member is unwrapped into a\n * standalone sfnt first (see `measure/font-collection.ts`).\n * @param {Uint8Array} data - the font file's bytes\n * @param {ParseFontMetricsOptions} [opts] - which font, for a file holding several\n * @returns {Promise<FontMetrics>} advance widths and cmap coverage for that font\n * @example await parseFontMetrics(bytes) // a plain .ttf\n * @example await parseFontMetrics(ttcBytes, { font: 'MS PGothic' })\n */\nexport async function parseFontMetrics(data: Uint8Array, opts?: ParseFontMetricsOptions): Promise<FontMetrics> {\n\t// Dynamic import keeps opentype.js off the critical/browser path until a\n\t// consumer actually registers metrics.\n\tconst mod = (await import('opentype.js')) as unknown as {\n\t\tparse?: (buf: ArrayBuffer) => OpentypeFontLike\n\t\tdefault?: { parse: (buf: ArrayBuffer) => OpentypeFontLike }\n\t}\n\tconst parse = mod.parse ?? mod.default?.parse\n\tif (typeof parse !== 'function')\n\t\tthrow new UnsupportedFeatureError('font/opentype-unavailable', 'opentype.js: parse() not found in module exports')\n\tconst sfnt = extractFontFace(data, resolveFontFace(data, opts?.font))\n\t// opentype.parse needs a standalone ArrayBuffer view of exactly the font bytes.\n\tconst buf = sfnt.buffer.slice(sfnt.byteOffset, sfnt.byteOffset + sfnt.byteLength) as ArrayBuffer\n\ttry {\n\t\treturn new OpentypeFontMetrics(parse(buf))\n\t} catch (ex) {\n\t\t// The parser throws bare `Error`s. Reclassify so a consumer can catch this by the\n\t\t// same taxonomy as every other library failure instead of matching on a message.\n\t\tthrow new MediaError('font/parse-failed', `Unable to parse font file: ${String(ex)}`, { cause: ex })\n\t}\n}\n\n/**\n * Registry of `FontMetrics` keyed by `(face, bold, italic)`. Variant advances\n * differ, so bold/italic are stored separately; lookup falls back to the regular\n * variant (then any registered variant of the face) so a deck that only registers\n * the regular weight still measures bold runs approximately rather than not at all.\n */\nexport class FontMetricsRegistry {\n\tprivate readonly map = new Map<string, FontMetrics>()\n\n\tprivate key(face: string, bold: boolean, italic: boolean): string {\n\t\treturn `${face.toLowerCase()}\\0${bold ? 1 : 0}\\0${italic ? 1 : 0}`\n\t}\n\n\tset(face: string, metrics: FontMetrics, opts?: { bold?: boolean; italic?: boolean }): void {\n\t\t// An empty name registers under a key no `fontFace` resolves to, so the metrics would sit unused.\n\t\tif (typeof face !== 'string' || face.trim() === '') {\n\t\t\tthrow new InvalidOptionError(\n\t\t\t\t'font/missing-typeface',\n\t\t\t\t`registerFontMetrics: \\`face\\` must be the non-empty family name your fontFace options use, got ${JSON.stringify(face)}.`\n\t\t\t)\n\t\t}\n\t\tthis.map.set(this.key(face, !!opts?.bold, !!opts?.italic), metrics)\n\t}\n\n\t/** True if any variant of `face` has registered metrics. */\n\thasFace(face: string): boolean {\n\t\tconst prefix = `${face.toLowerCase()}\\0`\n\t\tfor (const k of this.map.keys()) if (k.startsWith(prefix)) return true\n\t\treturn false\n\t}\n\n\t/**\n\t * Coverage of code point `cp` for `face`, read from the registered font's cmap:\n\t * `true`/`false` when a variant of `face` is registered (see {@link get} for the\n\t * exact→regular→any-variant fallback), or `undefined` when the face has **no**\n\t * registered metrics — \"unknown\", deliberately distinct from a `false`\n\t * \"registered but not covered\". A coverage audit must not treat an unregistered\n\t * face as fully covered, so callers get `undefined` here rather than the per-face\n\t * {@link FontMetrics.hasCodepoint} boolean (which, for the heuristic fallback,\n\t * always reports covered). Register the face via {@link parseFontMetrics} +\n\t * {@link set} first.\n\t */\n\thasCodepoint(\n\t\tface: string | undefined | null,\n\t\tcp: number,\n\t\topts?: { bold?: boolean; italic?: boolean }\n\t): boolean | undefined {\n\t\treturn this.get(face, opts?.bold, opts?.italic)?.hasCodepoint(cp)\n\t}\n\n\t/** Resolve metrics for a run, falling back from exact variant → regular → any variant. */\n\tget(face: string | undefined | null, bold = false, italic = false): FontMetrics | undefined {\n\t\t// A run with no explicit face inherits the theme font, which we cannot resolve\n\t\t// reliably here — treat as unregistered so measured fit degrades gracefully.\n\t\tif (typeof face !== 'string' || face.length === 0) return undefined\n\t\tconst exact = this.map.get(this.key(face, bold, italic))\n\t\tif (exact) return exact\n\t\tconst regular = this.map.get(this.key(face, false, false))\n\t\tif (regular) return regular\n\t\tconst prefix = `${face.toLowerCase()}\\0`\n\t\tfor (const [k, v] of this.map) if (k.startsWith(prefix)) return v\n\t\treturn undefined\n\t}\n\n\tget size(): number {\n\t\treturn this.map.size\n\t}\n}\n\n/**\n * A {@link MetricsResolver} backed by a registry: exact metrics for a registered face, otherwise\n * the shared heuristic fallback (with `onHeuristic` told which face it stood in for). A run with\n * no `fontFace` at all resolves to `undefined`, which the callers treat as unmeasurable.\n */\nexport function makeRegistryResolver(\n\tregistry: FontMetricsRegistry,\n\tonHeuristic?: (face: string) => void\n): MetricsResolver {\n\treturn (run) => {\n\t\tconst exact = registry.get(run.fontFace, run.bold, run.italic)\n\t\tif (exact) return exact\n\t\tif (typeof run.fontFace === 'string' && run.fontFace.length > 0) {\n\t\t\tonHeuristic?.(run.fontFace)\n\t\t\treturn getHeuristicFontMetrics()\n\t\t}\n\t\treturn undefined\n\t}\n}\n\n/**\n * Accumulate, per face, the code points `paragraphs` uses that the run's **registered**\n * metrics have no glyph for.\n *\n * This is the one thing the width arithmetic cannot see. PowerPoint substitutes another\n * face per code point and lays the run out in *that* font's advances; the model has no\n * fallback and charges the registered font's `.notdef` advance instead, which is a single\n * flat number unrelated to the glyph that actually paints. Unlike the other approximations\n * here it is **not** conservative in a fixed direction: a `.notdef` wider than the real\n * glyph over-reports (a phantom line, which is safe), a narrower one under-reports and can drop a\n * line, which is the overflow direction the resize bake has no safety net for. So it is\n * surfaced rather than absorbed. See `docs/contributing/design/text-fit.md` (\"Font fallback\").\n *\n * Runs whose face has no registered metrics at all are skipped: they measure through the\n * cmap-less heuristic, which has no coverage to report, and the caller already flags them\n * as approximated faces.\n * @param paragraphs - the runs to audit, as handed to the layout\n * @param registry - the metrics the layout resolved against\n * @param into - face → uncovered code points, added to in place\n */\nexport function collectUncoveredCodepoints(\n\tparagraphs: FitParagraph[],\n\tregistry: FontMetricsRegistry,\n\tinto: Map<string, Set<number>>\n): void {\n\tfor (const para of paragraphs) {\n\t\tfor (const run of para.runs) {\n\t\t\tconst face = run.fontFace\n\t\t\tif (typeof face !== 'string' || face.length === 0) continue\n\t\t\tconst metrics = registry.get(face, run.bold, run.italic)\n\t\t\tif (!metrics) continue\n\t\t\tlet missing: Set<number> | undefined\n\t\t\t// `for..of` iterates code points, so an astral character is audited whole\n\t\t\t// rather than as two uncovered surrogates.\n\t\t\tfor (const ch of run.text) {\n\t\t\t\tconst cp = ch.codePointAt(0)\n\t\t\t\tif (cp === undefined || metrics.hasCodepoint(cp)) continue\n\t\t\t\tmissing ??= into.get(face) ?? new Set<number>()\n\t\t\t\tmissing.add(cp)\n\t\t\t}\n\t\t\tif (missing) into.set(face, missing)\n\t\t}\n\t}\n}\n","/**\n * ts-pptx: Measured text fit (line-break simulator + shrink solver)\n *\n * Computes a baked `fontScale` for `fit: 'shrink'` so overflowing text renders\n * pre-shrunk in headless renderers (and on plain file-open) without a manual\n * edit/resize. See `docs/contributing/design/text-fit.md`.\n *\n * Calibration: every constant here is pinned against PowerPoint-authored fixtures\n * (`test/read/fixtures/autofit-calibration.json`). The model errs **conservative**\n * — it over-estimates width (raw advances, no kerning) and uses the calibrated\n * line pitch — so the computed `fontScale` is ≤ PowerPoint's and the text never\n * overflows in either PowerPoint or LibreOffice.\n */\n\nimport type { FontMetrics } from './font-metrics.js'\n\n/**\n * PowerPoint single-spacing line pitch as a multiple of font size.\n *\n * Calibrated from `autofit-calibration.json` (Deck 1, `autofit-line-metrics`):\n * the per-line `cy` delta is a **font-independent** 1.2117× at 12/18/32 pt across\n * {Aptos, Aptos SemiBold, Calibri, Tahoma, Arial}, and PowerPoint vs LibreOffice\n * agree to ≤ 0.041 pt. See \"Findings behind the constants\" in\n * `docs/contributing/design/text-fit.md`.\n */\nexport const SINGLE_LINE_PITCH = 1.2117\n\n/** PowerPoint's `fontScale` search grid: discrete 2.5% steps (`docs/contributing/design/text-fit.md`). */\nexport const FONT_SCALE_STEP_PCT = 2.5\n\n/** Floor for the shrink search (see `docs/contributing/design/text-fit.md` → Wrap simulator and solvers). */\nexport const MIN_FONT_SCALE_PCT = 25\n\n/**\n * Conservative safety factors applied by the shrink solver (not by the pure\n * `measureHeightPt`). Raw `hmtx` advances summed without shaping still pack a line\n * a little tighter than PowerPoint, which lays text out at a device DPI and rounds\n * each glyph advance up — so PowerPoint wraps marginally earlier and its fitted\n * box is marginally taller. Inflating measured width and height by these factors\n * makes the computed `fontScale` ≤ PowerPoint's across the calibration oracle\n * (`test/read/autofit-calibration-oracle.test.js`: 0 violations over the Aptos\n * cases). They err on the side of shrinking slightly too much, never overflowing.\n */\nexport const WIDTH_SAFETY_FACTOR = 1.03\nexport const HEIGHT_SAFETY_FACTOR = 1.04\n\n/** One text run with the inputs measurement needs. */\nexport interface FitRun {\n\ttext: string\n\tsizePt: number\n\tbold?: boolean\n\titalic?: boolean\n\tfontFace?: string | undefined\n\t/** Character spacing in points (PowerPoint `spc`/1200). */\n\tcharSpacingPt?: number | undefined\n}\n\n/**\n * One paragraph: its runs plus vertical-rhythm options.\n *\n * The three `| undefined` members here are deliberate, and the exception to the rule the\n * generator's option bags follow (`options-internal.ts`): these are measurement records, built in\n * one place by `paragraphs.ts` and read in one place by the solver below, with `??` and\n * truthiness. Nothing spreads or enumerates them, so a key holding `undefined` cannot mean\n * anything different from an absent one — and the builder does produce every key on every run.\n * Saying so is more honest than making the builder omit keys nothing distinguishes.\n */\nexport interface FitParagraph {\n\truns: FitRun[]\n\t/** Line spacing as a percent of single (100 = single). Ignored if `lineSpacingPts` set. */\n\tlineSpacingPct?: number\n\t/** Exact line spacing in points (overrides `lineSpacingPct`). */\n\tlineSpacingPts?: number | undefined\n\tspaceBeforePts?: number\n\tspaceAfterPts?: number\n}\n\n/** Inner box (shape minus insets) the text must fit, in points. */\nexport interface FitBox {\n\tinnerWidthPt: number\n\tinnerHeightPt: number\n\t/**\n\t * `false` when the frame does not wrap (`wrap:false` / `wrap=\"none\"`): text lays\n\t * out as one line per paragraph (no width-wrapping), and the shrink solver must\n\t * additionally keep the widest line within `innerWidthPt`. A too-wide line\n\t * overflows HORIZONTALLY — `normAutofit`'s vertical shrink never catches it, so\n\t * without this check a non-wrapping line is never shrunk and spills out of the box\n\t * in PowerPoint. Defaults to wrapping (`true`), so table cells and `measureText`\n\t * are unaffected.\n\t */\n\twrap?: boolean\n}\n\n/** Resolve the metrics for a run, or `undefined` if the face is not registered. */\nexport type MetricsResolver = (run: FitRun) => FontMetrics | undefined\n\nexport interface ShrinkResult {\n\tfontScalePct: number\n\tlnSpcReductionPct: number\n}\n\nexport type ShrinkOutcome =\n\t| { kind: 'fits' } // already fits at 100% — no shrink needed\n\t| { kind: 'unmeasurable' } // a run's face has no registered metrics — caller degrades\n\t| { kind: 'shrink'; result: ShrinkResult }\n\ninterface WordToken {\n\tkind: 'word'\n\tw: number\n\tcharWidths: number[]\n}\ntype Token = WordToken | { kind: 'space'; w: number } | { kind: 'newline'; w: 0 }\n\nconst isWhitespace = (ch: string): boolean => ch === ' ' || ch === '\\t' || ch === ' ' || /\\s/.test(ch)\n\n/**\n * A code point that is its own wrap opportunity: a line may break either side of\n * it, with no whitespace involved. Latin words break only at whitespace, but\n * Chinese and Japanese text breaks between any two characters, so treating one\n * long run of them as a single unbreakable \"word\" moves the whole run to the next\n * line, over-reports the laid-out line count, and shrinks text that actually fits.\n *\n * **Hangul is deliberately absent.** UAX #14 makes Hangul breakable between\n * syllables, but PowerPoint does not: Korean is written with spaces between words\n * and the app breaks it like Latin. `autofit-cjk-wrap.pptx` pins that directly —\n * the same box that lays out in 2 lines in Han or Kana takes 3 in Hangul, because\n * the run moves down whole. A Hangul run longer than one line still breaks between\n * syllables, but that is the over-long-token character-wrap fallback in\n * `countLines`, which handles it without a break class. Adding Hangul here would\n * *under*-report the line count for Korean, which is the direction that overflows.\n *\n * Backed by `autofit-cjk-wrap.pptx` (PowerPoint-authored, one case per claim):\n * CJK Unified Ideographs, Hiragana/Katakana, fullwidth Latin, halfwidth Katakana\n * and Plane 2 all break per character; Hangul syllables do not. The remaining\n * ranges are the sibling blocks of the same UAX #14 class ID, generalized from\n * those cases rather than pinned one by one.\n *\n * Known gap: no kinsoku (line-break prohibition) rules. PowerPoint will not start\n * a line with `。` or `、` and hangs them past the right inset instead; this model\n * breaks before them. That is a widest-line difference, not a line-count one, and\n * `docs/contributing/design/text-fit.md` records it.\n */\nexport function isCjkBreakCharacter(ch: string): boolean {\n\tconst cp = ch.codePointAt(0) ?? 0\n\treturn (\n\t\t// U+3000 IDEOGRAPHIC SPACE falls in this first range but never reaches here:\n\t\t// `isWhitespace` claims it first, so it stays a space token.\n\t\t(cp >= 0x2e80 && cp <= 0x303f) || // CJK Radicals / Kangxi / IDC / CJK Symbols and Punctuation\n\t\t(cp >= 0x3040 && cp <= 0x30ff) || // Hiragana / Katakana (fixture)\n\t\t// Bopomofo and Bopomofo Extended sit either side of the Hangul Compatibility\n\t\t// Jamo block excluded below, but they are Chinese phonetic notation, not Korean:\n\t\t// same UAX #14 class as Han, and PowerPoint breaks them the same way.\n\t\t(cp >= 0x3100 && cp <= 0x312f) || // Bopomofo\n\t\t(cp >= 0x3190 && cp <= 0x319f) || // Kanbun\n\t\t(cp >= 0x31a0 && cp <= 0x31ff) || // Bopomofo Extended / CJK Strokes / Katakana Phonetic Extensions\n\t\t(cp >= 0x3200 && cp <= 0x4dbf) || // Enclosed CJK / CJK Compatibility / Ideographs Ext A\n\t\t(cp >= 0x4e00 && cp <= 0x9fff) || // CJK Unified Ideographs (fixture)\n\t\t(cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs\n\t\t(cp >= 0xfe10 && cp <= 0xfe1f) || // Vertical Forms\n\t\t(cp >= 0xfe30 && cp <= 0xfe4f) || // CJK Compatibility Forms\n\t\t// Halfwidth and Fullwidth Forms, minus U+FFA0..U+FFDF (halfwidth Hangul jamo),\n\t\t// which follows the Hangul rule above. Fullwidth Latin and halfwidth Katakana\n\t\t// are both fixture-backed.\n\t\t(cp >= 0xff00 && cp <= 0xff9f) ||\n\t\t(cp >= 0xffe0 && cp <= 0xffef) ||\n\t\t(cp >= 0x1b000 && cp <= 0x1b16f) || // Kana Supplement / Kana Extended-A / Small Kana Extension\n\t\t(cp >= 0x20000 && cp <= 0x2fffd) || // CJK Ideographs Extension B..F + Compatibility Supplement (fixture)\n\t\t(cp >= 0x30000 && cp <= 0x323af) // CJK Ideographs Extension G, H, I (Plane 3)\n\t)\n}\n\n/**\n * Tokenize one paragraph at a given `fontScalePct`. Words can span run boundaries\n * (a break is only allowed at whitespace, or either side of a per-character\n * breaking code point — see `isCjkBreakCharacter`). Returns `null` if any run's\n * face has no registered metrics (the paragraph cannot be measured).\n */\nfunction tokenizeParagraph(\n\tpara: FitParagraph,\n\tresolve: MetricsResolver,\n\tfontScalePct: number,\n\twidthSafety: number\n): Token[] | null {\n\tconst tokens: Token[] = []\n\tlet curWord: WordToken | null = null\n\tconst flushWord = (): void => {\n\t\tif (curWord) {\n\t\t\ttokens.push(curWord)\n\t\t\tcurWord = null\n\t\t}\n\t}\n\tfor (const run of para.runs) {\n\t\tconst metrics = resolve(run)\n\t\tif (!metrics) return null\n\t\tconst scaledSize = run.sizePt * (fontScalePct / 100)\n\t\tconst charSpacingPt = run.charSpacingPt ?? 0\n\t\tfor (const ch of run.text ?? '') {\n\t\t\tif (ch === '\\n') {\n\t\t\t\tflushWord()\n\t\t\t\ttokens.push({ kind: 'newline', w: 0 })\n\t\t\t} else if (isWhitespace(ch)) {\n\t\t\t\tflushWord()\n\t\t\t\t// Tabs are approximated as a single space-width gap (documented P1 gap).\n\t\t\t\tconst w = metrics.advanceWidthPt(ch === '\\t' ? ' ' : ch, scaledSize, charSpacingPt) * widthSafety\n\t\t\t\ttokens.push({ kind: 'space', w })\n\t\t\t} else {\n\t\t\t\tconst w = metrics.advanceWidthPt(ch, scaledSize, charSpacingPt) * widthSafety\n\t\t\t\tif (isCjkBreakCharacter(ch)) {\n\t\t\t\t\tflushWord()\n\t\t\t\t\ttokens.push({ kind: 'word', w, charWidths: [w] })\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (!curWord) curWord = { kind: 'word', w: 0, charWidths: [] }\n\t\t\t\tcurWord.w += w\n\t\t\t\tcurWord.charWidths.push(w)\n\t\t\t}\n\t\t}\n\t}\n\tflushWord()\n\treturn tokens\n}\n\n/** Greedy `wrap=square` line layout for a tokenized paragraph. */\ninterface LineLayout {\n\tlines: number\n\t/** Width (points) of the widest laid-out line — for natural/widest-line measurement. */\n\tmaxLineWidthPt: number\n}\n\n/**\n * Greedy `wrap=square` line layout: the wrapped line count plus the widest\n * laid-out line width. `maxLineWidthPt` tracks the running line width and records\n * it whenever a line completes (a wrap or the final line), so callers can measure\n * the actual text extent, not just the box width. Trailing whitespace counts\n * toward width, as PowerPoint counts it, which slightly over-reports — the\n * conservative direction, consistent with the wrap model erring wide. The\n * PowerPoint behaviour this follows is tabled in `docs/contributing/design/text-fit.md`.\n */\nfunction countLines(tokens: Token[], innerWidthPt: number): LineLayout {\n\tlet lines = 1\n\tlet lineW = 0\n\tlet maxLineWidthPt = 0\n\tconst finishLine = (): void => {\n\t\tif (lineW > maxLineWidthPt) maxLineWidthPt = lineW\n\t}\n\tfor (const tok of tokens) {\n\t\tif (tok.kind === 'newline') {\n\t\t\tfinishLine()\n\t\t\tlines++\n\t\t\tlineW = 0\n\t\t} else if (tok.kind === 'space') {\n\t\t\t// Trailing whitespace counts toward line width, as in PowerPoint; if it\n\t\t\t// overflows, the line wraps and the space is consumed at the break.\n\t\t\tif (lineW + tok.w > innerWidthPt && lineW > 0) {\n\t\t\t\tfinishLine()\n\t\t\t\tlines++\n\t\t\t\tlineW = 0\n\t\t\t} else {\n\t\t\t\tlineW += tok.w\n\t\t\t}\n\t\t} else if (tok.w <= innerWidthPt) {\n\t\t\tif (lineW + tok.w > innerWidthPt && lineW > 0) {\n\t\t\t\tfinishLine()\n\t\t\t\tlines++\n\t\t\t\tlineW = tok.w\n\t\t\t} else {\n\t\t\t\tlineW += tok.w\n\t\t\t}\n\t\t} else {\n\t\t\t// Over-long unbreakable word → character-wrap, as PowerPoint does at wrap=square.\n\t\t\tif (lineW > 0) {\n\t\t\t\tfinishLine()\n\t\t\t\tlines++\n\t\t\t\tlineW = 0\n\t\t\t}\n\t\t\tfor (const cw of tok.charWidths) {\n\t\t\t\tif (lineW + cw > innerWidthPt && lineW > 0) {\n\t\t\t\t\tfinishLine()\n\t\t\t\t\tlines++\n\t\t\t\t\tlineW = cw\n\t\t\t\t} else {\n\t\t\t\t\tlineW += cw\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfinishLine()\n\treturn { lines, maxLineWidthPt }\n}\n\n/** Max run size in a paragraph (PowerPoint's line height follows the tallest run). */\nfunction maxRunSizePt(para: FitParagraph): number {\n\tlet max = 0\n\tfor (const run of para.runs) if (run.sizePt > max) max = run.sizePt\n\treturn max\n}\n\n/** Laid-out result of {@link measureLayout}: total height (points) + wrapped line count. */\nexport interface LayoutResult {\n\theightPt: number\n\tlineCount: number\n\t/**\n\t * Width (points) of the widest laid-out line across all paragraphs. Useful for\n\t * tightening a box to the actual text extent or measuring a natural (single-line)\n\t * width. Carries the same `widthSafety` inflation as the wrap decision, so a box\n\t * set to this width will not re-wrap. Conservative (slightly wide).\n\t */\n\twidestLineWidthPt: number\n}\n\n/**\n * Lay out `paragraphs` at a given scale/reduction and return the total height\n * (points) and wrapped line count, or `null` if any paragraph is unmeasurable.\n * Errs tall (conservative): includes space-before/after and the calibrated line\n * pitch. The single source of truth for both {@link measureHeightPt} (the solvers)\n * and the public layout-time measure API.\n */\nexport function measureLayout(\n\tparagraphs: FitParagraph[],\n\tinnerWidthPt: number,\n\tresolve: MetricsResolver,\n\tfontScalePct: number,\n\tlnSpcReductionPct: number,\n\twidthSafety = 1\n): LayoutResult | null {\n\t// Negated so `NaN` is refused too; `Infinity` still passes, for a layout that does not wrap.\n\tif (!(innerWidthPt > 0)) return null\n\tlet total = 0\n\tlet lineCount = 0\n\tlet widestLineWidthPt = 0\n\tfor (const para of paragraphs) {\n\t\tconst tokens = tokenizeParagraph(para, resolve, fontScalePct, widthSafety)\n\t\tif (tokens === null) return null\n\t\tconst { lines, maxLineWidthPt } = countLines(tokens, innerWidthPt)\n\t\tlineCount += lines\n\t\tif (maxLineWidthPt > widestLineWidthPt) widestLineWidthPt = maxLineWidthPt\n\t\tconst scaledMax = maxRunSizePt(para) * (fontScalePct / 100)\n\t\tlet lineHeight =\n\t\t\tpara.lineSpacingPts != null && para.lineSpacingPts > 0\n\t\t\t\t? para.lineSpacingPts\n\t\t\t\t: SINGLE_LINE_PITCH * scaledMax * ((para.lineSpacingPct ?? 100) / 100)\n\t\tlineHeight *= 1 - lnSpcReductionPct / 100\n\t\ttotal += lines * lineHeight + (para.spaceBeforePts ?? 0) + (para.spaceAfterPts ?? 0)\n\t}\n\treturn { heightPt: total, lineCount, widestLineWidthPt }\n}\n\n/**\n * Total laid-out height (points) at a given scale/reduction, or `null` if any\n * paragraph is unmeasurable. Thin wrapper over {@link measureLayout}.\n */\nexport function measureHeightPt(\n\tparagraphs: FitParagraph[],\n\tinnerWidthPt: number,\n\tresolve: MetricsResolver,\n\tfontScalePct: number,\n\tlnSpcReductionPct: number,\n\twidthSafety = 1\n): number | null {\n\tconst result = measureLayout(paragraphs, innerWidthPt, resolve, fontScalePct, lnSpcReductionPct, widthSafety)\n\treturn result === null ? null : result.heightPt\n}\n\n/** What the resize solver concluded: it could not measure, or the inner height the text needs. */\nexport type ResizeOutcome =\n\t| { kind: 'unmeasurable' } // a run's face has no registered metrics — caller degrades\n\t| { kind: 'resize'; neededInnerHeightPt: number }\n\n/**\n * Width used for wrap layout: the inner box width when wrapping, or unbounded for a\n * non-wrapping frame (`wrap:false`) so each paragraph lays out as a single line. A\n * non-wrapping frame's width constraint is enforced separately, against the widest\n * laid-out line — see {@link solveShrink}.\n */\nfunction layoutWidthPt(box: FitBox): number {\n\treturn box.wrap === false ? Infinity : box.innerWidthPt\n}\n\n/**\n * Inner height (points) the text needs at full size — the value to bake into the\n * shape's `a:ext/@cy` for `fit: 'resize'` (`spAutoFit`). Unlike shrink, resize has\n * **no safety net**: an under-estimate overflows (there is no text scaling\n * fallback), so this errs **tall** — width is inflated (earlier wrap ⇒ more lines)\n * and the laid-out height by the calibrated height factor, so the computed `cy` is\n * ≥ PowerPoint's and ≥ the LibreOffice-rendered height across the resize oracle.\n */\nexport function solveResize(paragraphs: FitParagraph[], box: FitBox, resolve: MetricsResolver): ResizeOutcome {\n\tconst h = measureHeightPt(paragraphs, layoutWidthPt(box), resolve, 100, 0, WIDTH_SAFETY_FACTOR)\n\tif (h === null) return { kind: 'unmeasurable' }\n\treturn { kind: 'resize', neededInnerHeightPt: h * HEIGHT_SAFETY_FACTOR }\n}\n\n/**\n * Largest `fontScale` (on PowerPoint's 2.5% grid) at which the text fits the box.\n * Width and height both re-measured per scale. Conservative: because the model\n * over-estimates, the returned scale is ≤ PowerPoint's and the text never overflows.\n *\n * `lnSpcReduction` is left at 0 — dropping `fontScale` alone is provably\n * conservative (PowerPoint trades line-spacing reduction to keep the font *larger*,\n * so a reduction-free fit is always ≤ PowerPoint's scale). The reduction ramp\n * PowerPoint applies is recorded in `docs/contributing/design/text-fit.md`.\n */\nexport function solveShrink(paragraphs: FitParagraph[], box: FitBox, resolve: MetricsResolver): ShrinkOutcome {\n\tconst width = layoutWidthPt(box)\n\tconst noWrap = box.wrap === false\n\t// Inflate measured width (earlier wrap) and height by the calibrated safety\n\t// factors so the fit threshold is conservative against PowerPoint. For a\n\t// non-wrapping frame the single line always fits the box HEIGHT, so height alone\n\t// never triggers a shrink: also require the widest (unwrapped) line to fit the box\n\t// WIDTH. `widestLineWidthPt` already carries the WIDTH_SAFETY_FACTOR inflation, so\n\t// comparing it straight to `innerWidthPt` stays on the conservative (shrink-more) side.\n\tconst fits = (scale: number): boolean | null => {\n\t\tconst layout = measureLayout(paragraphs, width, resolve, scale, 0, WIDTH_SAFETY_FACTOR)\n\t\tif (layout === null) return null\n\t\tif (layout.heightPt * HEIGHT_SAFETY_FACTOR > box.innerHeightPt) return false\n\t\tif (noWrap && layout.widestLineWidthPt > box.innerWidthPt) return false\n\t\treturn true\n\t}\n\n\tconst at100 = fits(100)\n\tif (at100 === null) return { kind: 'unmeasurable' }\n\tif (at100) return { kind: 'fits' }\n\n\tfor (let scale = 100 - FONT_SCALE_STEP_PCT; scale >= MIN_FONT_SCALE_PCT; scale -= FONT_SCALE_STEP_PCT) {\n\t\tif (fits(scale)) return { kind: 'shrink', result: { fontScalePct: scale, lnSpcReductionPct: 0 } }\n\t}\n\t// Even at the floor it overflows our conservative model — bake the floor as best effort.\n\treturn { kind: 'shrink', result: { fontScalePct: MIN_FONT_SCALE_PCT, lnSpcReductionPct: 0 } }\n}\n","/**\n * ts-pptx: turning a slide text object into the simulator's inputs\n *\n * The lower half of the measured-fit pass: normalize a text object's runs into `FitParagraph`s,\n * resolve its body insets and box, and work out how a height change is shared between `off.y` and\n * `ext.cy` for a given anchor. Everything here is about *reading* an authored object; the solving\n * and the rewriting live in the siblings (`table-fit.ts`, `fit.ts`).\n */\n\nimport { DEF_FONT_SIZE } from '../constants-internal.js'\nimport { EMU_PER_POINT } from '../units.js'\nimport { getSmartParseNumber, resolveInsetsEmu as resolveMarginInsetsEmu } from '../units-internal.js'\nimport { BODY_INSET_DEFAULTS_EMU } from '../ooxml/body-insets.js'\nimport type { FitBox, FitParagraph, FitRun } from './text-fit.js'\nimport { TextAnchor } from '../enums.js'\nimport type { TextProps, TextPropsOptions } from '../types/index.js'\nimport type { ObjectOptionsInternal, SlideObject, PresSlideInternal } from '../types/internal.js'\nimport { pickDefined } from '../options-internal.js'\n\nconst CRLF_RE = /\\r*\\n/g\n\nexport type RunOpts = TextPropsOptions & ObjectOptionsInternal\n\n/**\n * The two fields a run list is read from, and the whole contract {@link normalizeRuns} and\n * {@link extractParagraphs} have.\n *\n * Both used to take a full `SlideObject`, which is why both of their table call sites had to\n * write `{ text: cell.text, options: eff } as unknown as SlideObject` — a cell's `text` is\n * `string | TableCellInternal[]` and a slide object's is `TextProps[]`, so nothing weaker than a\n * double cast would fit. Naming the two fields these functions actually read makes a table\n * cell an ordinary argument, and a `SlideObject` still one too.\n *\n * `text` is deliberately loose: `normalizeRuns` accepts a bare string, a number, one\n * `TextProps`, or an array of them, and branches on the shape at runtime.\n */\ninterface RunSource {\n\ttext?: unknown\n\toptions?: RunOpts\n}\n\n/** Normalize `slideObj.text` (string | TextProps | TextProps[]) to a run list. */\nexport function normalizeRuns(obj: RunSource): TextProps[] {\n\tconst opts = obj.options ?? {}\n\tconst text = obj.text\n\tif (text == null) return []\n\tif (typeof text === 'string' || typeof text === 'number') return [{ text: String(text), options: opts }]\n\t// `pickDefined` for `text`: a run that carries none keeps the key off, which is what the\n\t// `TextProps` the generator builds do — this list is handed straight to `extractParagraphs`\n\t// and, from the table path, compared against runs that came from there.\n\tif (!Array.isArray(text) && typeof text === 'object' && 'text' in text) {\n\t\tconst t = text as TextProps\n\t\treturn [{ ...pickDefined(t, ['text']), options: t.options ?? opts }]\n\t}\n\tif (Array.isArray(text))\n\t\treturn (text as TextProps[]).map((t) => ({ ...pickDefined(t, ['text']), options: t.options ?? opts }))\n\treturn []\n}\n\n/** Build a measurable `FitParagraph[]` from a text object, or null if not measurable. */\nexport function extractParagraphs(obj: RunSource): FitParagraph[] | null {\n\tconst opts = obj.options ?? {}\n\tconst runs = normalizeRuns(obj)\n\tif (runs.length === 0) return null\n\treturn buildFitParagraphs(runs, opts)\n}\n\n/**\n * Convert a run list (+ box-level default options) into a measurable\n * `FitParagraph[]`, or null if empty. The single converter shared by the\n * export-time pass (`extractParagraphs`) and the public layout-time\n * `measureText` API, so a layout-time prediction and the baked export never drift.\n */\nexport function buildFitParagraphs(runs: TextProps[], opts: RunOpts): FitParagraph[] | null {\n\tif (runs.length === 0) return null\n\n\t// Expand \"\\n\" inside a run into separate pieces, flagging the paragraph break\n\t// after each (mirrors `gen/slide/objects/table.ts` STEP 4). `breakLine` ends a paragraph too.\n\tinterface Piece {\n\t\ttext: string\n\t\toptions: RunOpts\n\t\tbreakAfter: boolean\n\t}\n\tconst pieces: Piece[] = []\n\tfor (const run of runs) {\n\t\tconst ro = (run.options ?? opts) as RunOpts\n\t\tconst raw = String(run.text ?? '').replace(CRLF_RE, '\\n')\n\t\tif (raw.includes('\\n')) {\n\t\t\tconst lines = raw.split('\\n')\n\t\t\tlines.forEach((line, i) => {\n\t\t\t\tconst isLast = i === lines.length - 1\n\t\t\t\tpieces.push({ text: line, options: ro, breakAfter: isLast ? !!ro.breakLine : true })\n\t\t\t})\n\t\t} else {\n\t\t\tpieces.push({ text: raw, options: ro, breakAfter: !!ro.breakLine })\n\t\t}\n\t}\n\n\tconst toRun = (p: Piece): FitRun => {\n\t\tconst ro = p.options\n\t\tconst sizePt = Number(ro.fontSize ?? opts.fontSize ?? DEF_FONT_SIZE)\n\t\treturn {\n\t\t\ttext: p.text,\n\t\t\tsizePt: Number.isFinite(sizePt) && sizePt > 0 ? sizePt : DEF_FONT_SIZE,\n\t\t\tbold: !!(ro.bold ?? opts.bold),\n\t\t\titalic: !!(ro.italic ?? opts.italic),\n\t\t\tfontFace: ro.fontFace ?? opts.fontFace,\n\t\t\tcharSpacingPt: (ro.charSpacing ?? opts.charSpacing) || undefined,\n\t\t}\n\t}\n\tconst toPara = (runsForPara: FitRun[], paraOpts: RunOpts): FitParagraph => {\n\t\tconst lineSpacing = paraOpts.lineSpacing ?? opts.lineSpacing\n\t\tconst lineSpacingMultiple = paraOpts.lineSpacingMultiple ?? opts.lineSpacingMultiple\n\t\treturn {\n\t\t\truns: runsForPara,\n\t\t\tlineSpacingPts: typeof lineSpacing === 'number' && lineSpacing > 0 ? lineSpacing : undefined,\n\t\t\tlineSpacingPct:\n\t\t\t\ttypeof lineSpacingMultiple === 'number' && lineSpacingMultiple > 0 ? lineSpacingMultiple * 100 : 100,\n\t\t\tspaceBeforePts: Number(paraOpts.paraSpaceBefore ?? opts.paraSpaceBefore ?? 0) || 0,\n\t\t\tspaceAfterPts: Number(paraOpts.paraSpaceAfter ?? opts.paraSpaceAfter ?? 0) || 0,\n\t\t}\n\t}\n\n\tconst paras: FitParagraph[] = []\n\tlet cur: FitRun[] = []\n\tlet curParaOpts: RunOpts = opts\n\tfor (const piece of pieces) {\n\t\tcur.push(toRun(piece))\n\t\tcurParaOpts = piece.options\n\t\tif (piece.breakAfter) {\n\t\t\tparas.push(toPara(cur, curParaOpts))\n\t\t\tcur = []\n\t\t}\n\t}\n\tif (cur.length > 0) paras.push(toPara(cur, curParaOpts))\n\treturn paras.length > 0 ? paras : null\n}\n\ninterface InsetsEmu {\n\tlIns: number\n\trIns: number\n\ttIns: number\n\tbIns: number\n}\n\n/**\n * Resolve a text frame's insets (EMU): explicit `_bodyProp` (from `inset`) → `margin` →\n * PowerPoint's defaults.\n *\n * Named for the question it answers, which is not the one `units-internal.resolveInsetsEmu`\n * answers: that one takes a `margin` alone and returns `null` when the caller stated none, so\n * an emitter can leave the attributes off. This one takes the whole option bag, consults\n * `_bodyProp` first, and always produces four numbers, because a solver has to measure against\n * something. Two exported functions with one name, imported from two places, was a coin-flip\n * for anyone reading a call site.\n *\n * The `[T, R, B, L]` shuffle and the defaults both come from the modules that own them rather\n * than being spelled again here.\n */\nexport function resolveBodyInsetsEmu(opts: RunOpts): InsetsEmu {\n\tconst bp = opts._bodyProp ?? {}\n\tlet lIns = bp.lIns\n\tlet rIns = bp.rIns\n\tlet tIns = bp.tIns\n\tlet bIns = bp.bIns\n\tif (lIns == null && rIns == null && tIns == null && bIns == null) {\n\t\tconst insets = resolveMarginInsetsEmu(opts.margin)\n\t\tif (insets) ({ l: lIns, r: rIns, t: tIns, b: bIns } = insets)\n\t}\n\treturn {\n\t\tlIns: lIns ?? BODY_INSET_DEFAULTS_EMU.left,\n\t\trIns: rIns ?? BODY_INSET_DEFAULTS_EMU.right,\n\t\ttIns: tIns ?? BODY_INSET_DEFAULTS_EMU.top,\n\t\tbIns: bIns ?? BODY_INSET_DEFAULTS_EMU.bottom,\n\t}\n}\n\n/**\n * Resolve the inner box (shape minus insets) in points; null if degenerate.\n *\n * Reads the object's own `opts.w/h` with no ancestor walk — correct only because a group keeps an\n * identity child coordinate space (`chOff/chExt == off/ext`, see the `gen/slide/object.ts` group renderer and\n * `docs/groups.md`), so a group never scales its children and a grouped text box's authored w/h is its\n * true rendered size. `applyMeasuredFit` reaches here for grouped text via its explicit group descent\n * (`measureObject`). If `addGroup` ever authored a scaled group (non-identity `chExt`), this would need\n * the same ancestor-scale composition `Shape.absoluteFrame` performs on the read path.\n */\nexport function computeBox(obj: SlideObject, presLayout: PresSlideInternal['_presLayout']): FitBox | null {\n\tconst opts = (obj.options ?? {}) as RunOpts\n\tconst wEmu = getSmartParseNumber(opts.w, 'X', presLayout)\n\tconst hEmu = getSmartParseNumber(opts.h, 'Y', presLayout)\n\tif (!(wEmu > 0) || !(hEmu > 0)) return null\n\n\tconst { lIns, rIns, tIns, bIns } = resolveBodyInsetsEmu(opts)\n\n\t// wrap=none lays text out one line per paragraph (no width-wrapping, handled by\n\t// the solver via the wrap flag), but the box width is still a real constraint:\n\t// solveShrink enforces it against the widest line so an over-wide non-wrapping\n\t// line shrinks to fit horizontally instead of spilling out of the box.\n\tconst wrap = (opts._bodyProp ?? {}).wrap !== false\n\tconst innerWidthPt = (wEmu - lIns - rIns) / EMU_PER_POINT\n\tconst innerHeightPt = (hEmu - tIns - bIns) / EMU_PER_POINT\n\tif (!(innerHeightPt > 0)) return null\n\tif (!(innerWidthPt > 0)) return null\n\treturn { innerWidthPt, innerHeightPt, wrap }\n}\n\n/** Vertical-anchor share of a height change that moves the box top up (`off.y` shift). */\nexport function anchorTopShareOfDelta(opts: RunOpts): number {\n\t// `_bodyProp.anchor` is the resolved valign ('t' | 'ctr' | 'b'); default 'ctr'.\n\tconst anchor = (opts._bodyProp ?? {}).anchor\n\tif (anchor === TextAnchor.t) return 0 // grow downward — top fixed\n\tif (anchor === TextAnchor.b) return 1 // grow upward — bottom fixed\n\treturn 0.5 // centered growth (default)\n}\n","/**\n * ts-pptx: what a table cell inherits from its table.\n *\n * A cell that states nothing takes the table's value, and two paths resolve that: the emitter,\n * building the bag it hands to the text-body writer, and the measured-fit pass, building the\n * effective text it lays out. They inherited **different lists** -- the measure side named\n * `italic`, `charSpacing`, `lineSpacing` and `lineSpacingMultiple` that the emitter did not,\n * while its docstring claimed to mirror the emitter's -- so a table-level `italic` was measured\n * with italic metrics and emitted upright, and on `fit: 'shrink'` a table-level line spacing\n * made the solver compute a taller layout and bake a smaller font that the cell then rendered\n * at default spacing. `pptx.tableLayout()` reported geometry the file disagreed with.\n *\n * So the text keys are one list, shared. The second list is the emitter's alone, and is a\n * statement rather than an omission: those keys either paint (`fill`, `color`, `border`,\n * `underline`) or are not modelled by the fitter (`textDirection`, which does change how text\n * lays out -- the measured-fit pass does not read it on a cell either way, and widening the\n * fitter to handle vertical cell text is its own change).\n */\n\n/**\n * The keys both paths inherit: everything that decides how a cell's text is laid out.\n *\n * `margin` and `valign` are here rather than below because the fitter reads them -- insets\n * shrink the box the text has to fit, and the anchor decides where a short line sits in it.\n */\nexport const CELL_INHERITED_TEXT_KEYS = [\n\t'align',\n\t'bold',\n\t'charSpacing',\n\t'fontFace',\n\t'fontSize',\n\t'italic',\n\t'lineSpacing',\n\t'lineSpacingMultiple',\n\t'margin',\n\t'valign',\n] as const\n\n/** The keys only the emitter inherits: they paint, or the fitter does not model them. */\nconst CELL_INHERITED_EMIT_KEYS = ['border', 'color', 'fill', 'textDirection', 'underline'] as const\n\n/** Every key the emitter inherits from the table onto a cell. */\nexport const CELL_INHERITED_KEYS = [...CELL_INHERITED_TEXT_KEYS, ...CELL_INHERITED_EMIT_KEYS] as const\n","/**\n * ts-pptx: measuring a table's row heights and cell fits\n *\n * A table is measured cell by cell against its resolved grid: each cell inherits the table's text\n * options where it sets none, gets its own margins resolved to EMU insets, and is laid out inside\n * the column span it actually occupies. A merged region is measured once, at its origin, across\n * the columns it covers — which is what `walkTableGrid` exists to hand out.\n */\n\nimport { DEF_FONT_SIZE, MIN_FONT_SIZE_PT } from '../constants-internal.js'\nimport { type GridPlacement, tableColCount, walkTableGrid } from '../gen/table/grid.js'\nimport { EMU_PER_POINT, emuToInches } from '../units.js'\nimport {\n\tautoPageLineHeightEmu,\n\tgetSmartParseNumber,\n\tmarginToEmu,\n\tresolveCellMarginsInches,\n\tresolveTableColWidthsEmu,\n\tresolveTableRowHeightEmu,\n} from '../units-internal.js'\nimport { measureLayout, WIDTH_SAFETY_FACTOR, HEIGHT_SAFETY_FACTOR } from './text-fit.js'\nimport { makeRegistryResolver, type FontMetricsRegistry } from './font-metrics.js'\nimport { extractParagraphs, type RunOpts } from './paragraphs.js'\nimport { CELL_INHERITED_TEXT_KEYS } from '../gen/table/cell-inherit.js'\nimport type { TableCellInternal } from '../types/internal.js'\nimport type {\n\tCoord,\n\tMargin,\n\tPresLayout,\n\tTableCellLayout,\n\tTableCellProps,\n\tTableLayoutResult,\n\tTableProps,\n} from '../types/index.js'\n\n/**\n * Effective cell options: the cell's own values, with table-level values filled in where unset.\n *\n * The keys are `CELL_INHERITED_TEXT_KEYS` (`gen/table/cell-inherit.ts`), the half of the\n * emitter's list that decides how text lays out. This used to be its own list, claiming in its\n * docstring to mirror the emitter's while naming four keys the emitter did not.\n *\n * PowerPoint has no text-autofit for a table cell — `a:tcPr` carries no autofit, and the app\n * ignores a `normAutofit` inside one; rows auto-grow instead. So a cell's `fit: 'shrink'` is\n * honoured by baking a *reduced literal font size* onto its runs, which both PowerPoint and\n * LibreOffice render identically with no edit or resize. That is what makes these options worth\n * resolving here: the shrink is computed against the cell's effective text, not the table's.\n */\nexport function effectiveCellOpts(cellOpts: TableCellProps, tableOpts: RunOpts): RunOpts {\n\tconst merged = { ...cellOpts } as RunOpts\n\tfor (const k of CELL_INHERITED_TEXT_KEYS) {\n\t\tif (merged[k] === undefined && tableOpts[k] !== undefined) (merged as Record<string, unknown>)[k] = tableOpts[k]\n\t}\n\treturn merged\n}\n\ninterface CellInsetsEmu {\n\tmarL: number\n\tmarR: number\n\tmarT: number\n\tmarB: number\n}\n\n/** Resolve a cell's margins to EMU insets, mirroring `gen/slide/objects/table.ts` (array is `[T,R,B,L]`, inches; see `marginToEmu`). */\nexport function resolveCellInsetsEmu(margin: Margin | undefined): CellInsetsEmu {\n\tconst arr = resolveCellMarginsInches(margin)\n\treturn {\n\t\tmarT: marginToEmu(arr[0]),\n\t\tmarR: marginToEmu(arr[1]),\n\t\tmarB: marginToEmu(arr[2]),\n\t\tmarL: marginToEmu(arr[3]),\n\t}\n}\n\n/**\n * Bake a reduced font size onto a cell's runs by factor `f` (< 1). The cell's options and runs are\n * replaced with scaled copies, never edited in place. The cell itself is the stored slide model,\n * so `applyMeasuredFit` puts the authored options and runs back once the write is built.\n *\n * The shrunk size never goes below {@link MIN_FONT_SIZE_PT}, the emitter's own bound. It used to\n * have no minimum, so a 1pt cell taken to the 25% scale floor was baked as 0.2pt and\n * `clampFontSizeSz` then warned that \"fontSize 0.2 is outside the valid range\" -- a value the\n * caller never stated and cannot act on. Their input was valid; only our scaling was out of range.\n */\nexport function scaleCellFontSizes(cell: TableCellInternal, eff: RunOpts, f: number): void {\n\t// floor: stay on the conservative (smaller) side, then lift to the smallest size a run can carry\n\tconst shrink = (sizePt: number): number => Math.max(MIN_FONT_SIZE_PT, Math.floor(sizePt * f * 10) / 10)\n\tconst baseSize = Number(eff.fontSize ?? DEF_FONT_SIZE)\n\tcell.options = { ...cell.options, fontSize: shrink(baseSize) }\n\tif (Array.isArray(cell.text)) {\n\t\tcell.text = cell.text.map((run) =>\n\t\t\trun && typeof run === 'object' && typeof run.options?.fontSize === 'number'\n\t\t\t\t? { ...run, options: { ...run.options, fontSize: shrink(run.options.fontSize) } }\n\t\t\t\t: run\n\t\t)\n\t}\n}\n\n/**\n * The options {@link resolveTableGridEmu} reads.\n *\n * `cy` is on `ObjectOptions` rather than `TableProps` — it is the already-resolved EMU height\n * the auto-pager and the measured-fit pass stamp on — so the parameter is the intersection\n * rather than either type, and every caller's own bag satisfies it structurally.\n */\ntype TableGridOpts = Pick<TableProps, 'w' | 'h' | 'colW' | 'rowH'> & { cy?: Coord }\n\n/** A table's resolved grid: how many columns, how wide each is, and how tall each row is. */\ninterface TableGridEmu {\n\t/** Grid columns, counting colspans. */\n\tnumCols: number\n\t/** Per-column width in EMU, length {@link numCols}. */\n\tcolWidthsEmu: number[]\n\t/** The table's own height in EMU, or `0` when it has none and every row is auto-height. */\n\ttableHeightEmu: number\n\t/** One row's pinned height in EMU, or `null` when the row grows to fit its content. */\n\trowHeightEmu: (rowIndex: number) => number | null\n}\n\n/**\n * Resolve a table's grid the one way every consumer has to see it.\n *\n * Three sites derived these four things: `pptx.tableLayout()`, the export-time measured-fit\n * pass, and the table emitter (the height alone). They already disagreed — only the fit pass\n * read `cy`, the EMU height the auto-pager and the fit pass itself stamp onto the options, so\n * `addTable(rows, { cy })` with no `h` gave a file whose rows are pinned and a\n * `pptx.tableLayout()` that reported every row auto-height. That is the same drift the one\n * reading of `rowH` closed, arriving through a second option, which is why the answer is a\n * shared resolver rather than a third correction.\n *\n * `w` defaults to `75%` of the slide, matching what the emitter falls back to.\n * @param rows - the table's authored rows\n * @param opts - the table's options\n * @param presLayout - the presentation layout, for resolving percentages\n */\nexport function resolveTableGridEmu(\n\trows: TableCellInternal[][],\n\topts: TableGridOpts,\n\tpresLayout: PresLayout\n): TableGridEmu {\n\tconst numRows = rows.length\n\tconst numCols = tableColCount(rows)\n\tconst cxEmu =\n\t\topts.w != null ? getSmartParseNumber(opts.w, 'X', presLayout) : getSmartParseNumber('75%', 'X', presLayout)\n\t// `cy` is the already-resolved EMU height the auto-pager and `applyMeasuredFit` stamp on;\n\t// it is the table's height just as much as `h` is, and only one of the three readings had it.\n\tconst tableHeightEmu =\n\t\topts.h != null ? getSmartParseNumber(opts.h, 'Y', presLayout) : typeof opts.cy === 'number' ? opts.cy : 0\n\treturn {\n\t\tnumCols,\n\t\tcolWidthsEmu: resolveTableColWidthsEmu(opts.colW, cxEmu, numCols),\n\t\ttableHeightEmu,\n\t\trowHeightEmu: (rowIndex: number) => resolveTableRowHeightEmu(opts.rowH, rowIndex, tableHeightEmu, numRows),\n\t}\n}\n\n/**\n * Compute per-cell geometry (inches) for a table laid out at `opts.x`/`y`/`w` — the\n * engine behind `pptx.tableLayout()`. Column widths come from the same\n * {@link resolveTableColWidthsEmu} the writer uses, so cell x/width are exact. Row\n * heights are exact when pinned by `rowH` (array or scalar) or table `h`; otherwise\n * each auto-height row is estimated with the same conservative (tall) text model as\n * {@link measureText} and flagged `heightExact: false`. Single-slide only —\n * `autoPage` paging across slides is not modeled. Rowspan cells do not drive a row's\n * estimated height (mirrors `gen/table/autopage.ts`, which exempts them from line-height growth).\n */\nexport function computeTableLayout(\n\trows: TableCellInternal[][],\n\topts: TableProps,\n\tpresLayout: PresLayout,\n\tregistry: FontMetricsRegistry\n): TableLayoutResult {\n\tconst empty: TableLayoutResult = { cells: [], widthIn: 0, heightIn: 0, heightExact: true }\n\tif (!rows || rows.length === 0 || !rows[0]) return empty\n\tconst numRows = rows.length\n\tconst grid = resolveTableGridEmu(rows, opts, presLayout)\n\tconst numCols = grid.numCols\n\tif (!(numCols > 0)) return empty\n\t// Reuse TableProps as a bag of inheritable text props; only CELL_INHERITED_TEXT_KEYS are\n\t// read from it. Route through `unknown` because TableProps.columns (per-column cell\n\t// styling, TableCellProps[]) collides by name with TextPropsOptions.columns (text\n\t// column count, number) — the two never overlap here since `columns` isn't inherited.\n\tconst o = opts as unknown as RunOpts\n\n\tconst tableXEmu = opts.x != null ? getSmartParseNumber(opts.x, 'X', presLayout) : 0\n\tconst tableYEmu = opts.y != null ? getSmartParseNumber(opts.y, 'Y', presLayout) : 0\n\tconst colWidthsEmu = grid.colWidthsEmu\n\n\t// Prefix-sum column x offsets (length numCols+1): colXEmu[c] = left edge of column c.\n\tconst colXEmu = new Array<number>(numCols + 1).fill(0)\n\tfor (let c = 0; c < numCols; c++) colXEmu[c + 1] = (colXEmu[c] ?? 0) + (colWidthsEmu[c] ?? 0)\n\n\t// Explicit row height (EMU) or null when the row is auto-height — the same reading the writer\n\t// bakes and the export-time fit pass measures against.\n\tconst explicitRowHEmu = grid.rowHeightEmu\n\tconst resolve = makeRegistryResolver(registry)\n\tconst defLineEmu = autoPageLineHeightEmu(DEF_FONT_SIZE)\n\n\t// Estimate a cell's content height (EMU) at its authored size, conservative/tall,\n\t// with a one-line floor. Mirrors measureText's inflated wrap + height safety.\n\tconst estimateContentHeightEmu = (cell: TableCellInternal, eff: RunOpts, innerWidthPt: number): number => {\n\t\tconst fontSizePt = Number(eff.fontSize ?? DEF_FONT_SIZE) || DEF_FONT_SIZE\n\t\tconst oneLineEmu = autoPageLineHeightEmu(fontSizePt)\n\t\tif (!(innerWidthPt > 0)) return oneLineEmu\n\t\tconst paragraphs = extractParagraphs({ text: cell.text, options: eff })\n\t\tif (!paragraphs) return oneLineEmu\n\t\tconst layout = measureLayout(paragraphs, innerWidthPt, resolve, 100, 0, WIDTH_SAFETY_FACTOR)\n\t\tif (layout === null) return oneLineEmu\n\t\treturn Math.max(Math.round(layout.heightPt * HEIGHT_SAFETY_FACTOR * EMU_PER_POINT), oneLineEmu)\n\t}\n\n\t// PASS 1: place every origin cell and resolve each row's height.\n\tinterface Placed {\n\t\tp: GridPlacement\n\t\tcolStart: number\n\t\tcolEnd: number\n\t}\n\tconst placed: Placed[] = []\n\tconst rowHeightsEmu = new Array<number>(numRows).fill(0)\n\tconst rowExact = new Array<boolean>(numRows).fill(false)\n\tfor (let r = 0; r < numRows; r++) {\n\t\tconst ex = explicitRowHEmu(r)\n\t\tif (ex != null) {\n\t\t\trowHeightsEmu[r] = ex\n\t\t\trowExact[r] = true\n\t\t}\n\t}\n\n\tfor (const p of walkTableGrid(rows, numCols)) {\n\t\tconst colStart = p.col\n\t\tconst colEnd = p.col + p.colSpan\n\t\tplaced.push({ p, colStart, colEnd })\n\n\t\t// Only single-row, auto-height cells drive a row's estimated height.\n\t\tif (p.rowSpan === 1 && !rowExact[p.row]) {\n\t\t\tlet widthEmu = 0\n\t\t\tfor (let c = colStart; c < colEnd; c++) widthEmu += colWidthsEmu[c] ?? 0\n\t\t\tconst eff = effectiveCellOpts(p.cell?.options ?? {}, o)\n\t\t\tconst ins = resolveCellInsetsEmu(eff.margin)\n\t\t\tconst innerWidthPt = (widthEmu - ins.marL - ins.marR) / EMU_PER_POINT\n\t\t\tconst contentEmu = estimateContentHeightEmu(p.cell, eff, innerWidthPt) + ins.marT + ins.marB\n\t\t\tif (contentEmu > (rowHeightsEmu[p.row] ?? 0)) rowHeightsEmu[p.row] = contentEmu\n\t\t}\n\t}\n\n\t// A row touched only by rowspans (no single-row cell, no explicit height) still\n\t// needs a non-zero height: give it one default line. That height is this function's own\n\t// invention, so the row stops being exact — a caller told it was pinned would place the\n\t// next shape against a number nothing in the file agrees with.\n\tfor (let r = 0; r < numRows; r++)\n\t\tif ((rowHeightsEmu[r] ?? 0) <= 0) {\n\t\t\trowHeightsEmu[r] = defLineEmu\n\t\t\trowExact[r] = false\n\t\t}\n\n\t// Prefix-sum row y offsets.\n\tconst rowYEmu = new Array<number>(numRows + 1).fill(0)\n\tfor (let r = 0; r < numRows; r++) rowYEmu[r + 1] = (rowYEmu[r] ?? 0) + (rowHeightsEmu[r] ?? 0)\n\n\t// PASS 2: emit one rect per origin cell.\n\tconst cells: TableCellLayout[] = placed.map(({ p, colStart, colEnd }) => {\n\t\tconst rowEnd = p.row + p.rowSpan\n\t\tlet heightExact = true\n\t\tfor (let rr = p.row; rr < rowEnd; rr++) if (!rowExact[rr]) heightExact = false\n\t\treturn {\n\t\t\trow: p.row,\n\t\t\tcol: p.col,\n\t\t\trowSpan: p.rowSpan,\n\t\t\tcolSpan: p.colSpan,\n\t\t\txIn: emuToInches(tableXEmu + (colXEmu[colStart] ?? 0)),\n\t\t\tyIn: emuToInches(tableYEmu + (rowYEmu[p.row] ?? 0)),\n\t\t\twIn: emuToInches((colXEmu[colEnd] ?? 0) - (colXEmu[colStart] ?? 0)),\n\t\t\thIn: emuToInches((rowYEmu[rowEnd] ?? 0) - (rowYEmu[p.row] ?? 0)),\n\t\t\theightExact,\n\t\t}\n\t})\n\n\treturn {\n\t\tcells,\n\t\twidthIn: emuToInches(colXEmu[numCols] ?? 0),\n\t\theightIn: emuToInches(rowYEmu[numRows] ?? 0),\n\t\theightExact: rowExact.every(Boolean),\n\t}\n}\n","/**\n * ts-pptx: Measured-fit serialization pass\n *\n * Bridges slide text objects to the line-break simulator / shrink solver\n * (`text-fit.ts`). Runs during async export, BEFORE the `gen/` emitter builds the body:\n * for each text box with `fit: 'shrink'` and a registered font, it computes the\n * `fontScale` PowerPoint would have baked and rewrites `options.fit` to the\n * explicit object form (`{ type:'shrink', fontScale }`) so `genXmlNormAutofit`\n * emits `<a:normAutofit fontScale=…/>`. Without metrics it leaves the bare flag\n * untouched (current behavior) and warns once. The rewrite lasts one write: the pass hands back\n * the step that puts the authored values back. See `docs/contributing/design/text-fit.md`.\n */\n\nimport { SlideObjectType } from '../enums.js'\nimport { EMU_PER_POINT, POINTS_PER_INCH } from '../units.js'\nimport { getSmartParseNumber } from '../units-internal.js'\nimport { warn } from '../diagnostics.js'\nimport { InvalidOptionError } from '../errors.js'\nimport { collectUncoveredCodepoints, makeRegistryResolver, type FontMetricsRegistry } from './font-metrics.js'\nimport {\n\tsolveShrink,\n\tsolveResize,\n\tmeasureLayout,\n\tWIDTH_SAFETY_FACTOR,\n\tHEIGHT_SAFETY_FACTOR,\n\ttype FitBox,\n\ttype FitParagraph,\n} from './text-fit.js'\nimport {\n\tanchorTopShareOfDelta,\n\tbuildFitParagraphs,\n\tcomputeBox,\n\textractParagraphs,\n\tresolveBodyInsetsEmu,\n\ttype RunOpts,\n} from './paragraphs.js'\nimport { walkTableGrid } from '../gen/table/grid.js'\nimport { effectiveCellOpts, resolveCellInsetsEmu, resolveTableGridEmu, scaleCellFontSizes } from './table-fit.js'\nimport type { MeasureTextOptions, TextFitShrinkProps, TextMeasurement, TextProps } from '../types/index.js'\nimport type { SlideObject, PresSlideInternal } from '../types/internal.js'\nimport { pickDefined } from '../options-internal.js'\n\n/** Map the public {@link MeasureTextOptions} onto the internal run-option shape. */\nfunction measureOptsToRunOpts(opts: MeasureTextOptions): RunOpts {\n\treturn pickDefined(opts, [\n\t\t'fontSize',\n\t\t'fontFace',\n\t\t'bold',\n\t\t'italic',\n\t\t'charSpacing',\n\t\t'lineSpacing',\n\t\t'lineSpacingMultiple',\n\t\t'paraSpaceBefore',\n\t\t'paraSpaceAfter',\n\t])\n}\n\n/** A fresh result each call: the arrays are caller-owned, so they cannot be shared. */\nconst unmeasurable = (): TextMeasurement => ({\n\theightIn: 0,\n\tlineCount: 0,\n\twidestLineIn: 0,\n\tmeasurable: false,\n\tapproximatedFaces: [],\n\tuncoveredCodepoints: [],\n\tfitsBox: () => false,\n\tshrinkScaleFor: () => 100,\n})\n\n/** Flatten a face → uncovered-code-point map into one sorted, deduplicated list. */\nfunction flattenCodepoints(byFace: Map<string, Set<number>>): number[] {\n\tconst all = new Set<number>()\n\tfor (const cps of byFace.values()) for (const cp of cps) all.add(cp)\n\treturn [...all].sort((a, b) => a - b)\n}\n\n/**\n * Render uncovered code points for a warning as `U+XXXX`, capped so one bad run cannot\n * flood the console with a whole unsupported script.\n */\nfunction formatCodepoints(cps: Set<number>): string {\n\tconst all = [...cps].sort((a, b) => a - b)\n\tconst shown = all.slice(0, 8).map((cp) => `U+${cp.toString(16).toUpperCase().padStart(4, '0')}`)\n\treturn all.length > shown.length ? `${shown.join(' ')} +${all.length - shown.length} more` : shown.join(' ')\n}\n\n/**\n * Layout-time text measurement against registered metrics — the public engine\n * behind `pptx.measureText()`. Uses the **same** calibrated wrap model, resolver\n * semantics, and conservative safety factors as the export-time bake\n * (`applyMeasuredFit` / {@link solveResize} / {@link solveShrink}), so a\n * layout-time prediction matches the value the export would bake **for any deck\n * that opted into measured fit (i.e. registered at least one face)**.\n *\n * With an **empty** registry the two intentionally diverge: `applyMeasuredFit`\n * treats \"no metrics\" as \"not opted in\" and bakes nothing, while this returns\n * heuristic numbers so the API is useful with zero setup. Check\n * `approximatedFaces` if that distinction matters.\n *\n * Synchronous: assumes metrics are pre-registered (lookup is sync). A named face\n * with no exact metrics silently uses the conservative heuristic (same as export)\n * and is reported in `approximatedFaces`; an unnamed theme-default face returns\n * `measurable: false`. Code points a *registered* face has no glyph for are reported\n * in `uncoveredCodepoints`, and are the one case where the height may come back short\n * rather than tall — there is no font fallback here, only the font's `.notdef` advance.\n */\nexport function measureText(\n\tregistry: FontMetricsRegistry,\n\ttext: string | TextProps[],\n\topts: MeasureTextOptions\n): TextMeasurement {\n\t// The box is checked before the text. A `NaN` or missing width passed every comparison the\n\t// layout makes as false, so each word went on a line of its own and the result read as\n\t// measurable; a width inside the insets came back unmeasurable with no reason given.\n\tconst inset = opts.insetIn ?? 0\n\trequireFiniteInches(opts.wIn, 'wIn', 'measureText')\n\trequireFiniteInches(inset, 'insetIn', 'measureText')\n\t// A size that is not a positive number fell back to the default size, and the measurement read as\n\t// the caller's own.\n\tif (opts.fontSize !== undefined && !(Number.isFinite(opts.fontSize) && opts.fontSize > 0))\n\t\tthrow new InvalidOptionError(\n\t\t\t'font/size-not-positive',\n\t\t\t`measureText: \\`fontSize\\` must be a positive number of points, got ${String(opts.fontSize)}.`\n\t\t)\n\tif (!(opts.wIn > 2 * inset))\n\t\tthrow new InvalidOptionError(\n\t\t\t'coord/not-positive',\n\t\t\t`measureText: \\`wIn\\` ${opts.wIn} leaves no width inside an inset of ${inset} on each side.`\n\t\t)\n\n\tconst runs: TextProps[] =\n\t\ttypeof text === 'string' || typeof text === 'number' ? [{ text: String(text) }] : Array.isArray(text) ? text : []\n\tconst paragraphs = buildFitParagraphs(runs, measureOptsToRunOpts(opts))\n\tif (!paragraphs) return unmeasurable()\n\n\tconst innerWidthPt = (opts.wIn - 2 * inset) * POINTS_PER_INCH\n\tconst heuristicFaces = new Set<string>()\n\tconst resolve = makeRegistryResolver(registry, (face) => heuristicFaces.add(face))\n\n\t// Coverage is a property of the runs, not of the layout, so it is audited up front —\n\t// which also keeps it out of the resolver that `shrinkScaleFor()` re-enters.\n\tconst uncoveredByFace = new Map<string, Set<number>>()\n\tcollectUncoveredCodepoints(paragraphs, registry, uncoveredByFace)\n\n\t// Conservative (tall) layout at full size, mirroring solveResize: inflate width\n\t// (earlier wrap) by WIDTH_SAFETY and the height by HEIGHT_SAFETY. The resolver runs\n\t// during layout, so `heuristicFaces` is only populated once this returns.\n\tconst layout = measureLayout(paragraphs, innerWidthPt, resolve, 100, 0, WIDTH_SAFETY_FACTOR)\n\tif (layout === null) return unmeasurable()\n\tconst heightPt = layout.heightPt * HEIGHT_SAFETY_FACTOR\n\tconst heightIn = heightPt / POINTS_PER_INCH\n\n\treturn {\n\t\theightIn,\n\t\tlineCount: layout.lineCount,\n\t\twidestLineIn: layout.widestLineWidthPt / POINTS_PER_INCH,\n\t\tmeasurable: true,\n\t\t// Snapshot: shrinkScaleFor() re-enters the same resolver, so the live set must not leak.\n\t\tapproximatedFaces: [...heuristicFaces],\n\t\tuncoveredCodepoints: flattenCodepoints(uncoveredByFace),\n\t\t// Mirrors solveShrink's fit check at scale 100 (height already inflated).\n\t\tfitsBox: (hIn: number) => {\n\t\t\trequireBoxHeight(hIn, 'fitsBox')\n\t\t\treturn heightPt <= hIn * POINTS_PER_INCH\n\t\t},\n\t\tshrinkScaleFor: (hIn: number) => {\n\t\t\trequireBoxHeight(hIn, 'shrinkScaleFor')\n\t\t\tconst box: FitBox = { innerWidthPt, innerHeightPt: hIn * POINTS_PER_INCH }\n\t\t\tconst outcome = solveShrink(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'shrink') return outcome.result.fontScalePct\n\t\t\treturn 100 // 'fits' (or, defensively, 'unmeasurable') → no shrink\n\t\t},\n\t}\n}\n\n/** Refuse a measure that is not a finite number of inches, naming the option and the call. */\nfunction requireFiniteInches(value: unknown, name: string, call: string): void {\n\tif (typeof value !== 'number' || !Number.isFinite(value))\n\t\tthrow new InvalidOptionError(\n\t\t\t'coord/non-finite',\n\t\t\t`${call}: \\`${name}\\` must be a finite number of inches; got ${String(value)}.`\n\t\t)\n}\n\n/**\n * Refuse a box height a fit cannot be tested against: not a finite number, or not above 0. A `NaN`\n * height made `fitsBox` answer `false` and `shrinkScaleFor` answer `100`, both as if measured.\n * @param hIn - the caller's inner box height, in inches\n * @param call - the method it was passed to, opening the message\n */\nexport function requireBoxHeight(hIn: unknown, call: string): void {\n\trequireFiniteInches(hIn, 'hIn', call)\n\tif (!((hIn as number) > 0))\n\t\tthrow new InvalidOptionError('coord/not-positive', `${call}: \\`hIn\\` must be greater than 0; got ${String(hIn)}.`)\n}\n\n/**\n * Apply measured fit across every slide. For each text box that opts in via\n * `fit:'shrink'` or `fit:'resize'` and whose font has registered metrics, this\n * bakes the computed result before the sync XML pass reads it:\n * - `'shrink'` → rewrites `options.fit` to the object form so `<a:normAutofit\n * fontScale=…/>` is emitted (text renders pre-shrunk).\n * - `'resize'` → rewrites `options.h` (and `options.y` per vertical anchor) so the\n * shape's `a:ext/@cy` is the height the text needs; the `<a:spAutoFit/>` marker is\n * left in place (the renderer draws the baked `cy`).\n *\n * Safe to call with an empty registry (no-op). Warns once if any opted-in box could\n * not be measured (missing metrics), and once if one held code points its registered\n * face has no glyph for, so neither kind of overflow is silently ignored.\n *\n * Every rewrite lands on the stored slide model, because that is what the emitters read.\n * The returned function puts each authored value back; call it once the XML is built. Left\n * baked, a second write found a text box's object-form `fit` and skipped it, and measured a\n * resized box or a shrunk cell from this write's result, so metrics registered in between\n * never reached those shapes.\n * @returns the step that restores every value this pass rewrote\n */\nexport function applyMeasuredFit(slides: PresSlideInternal[], registry: FontMetricsRegistry): () => void {\n\tconst restores: Array<() => void> = []\n\tconst restore = (): void => {\n\t\tfor (const undo of restores.splice(0).reverse()) undo()\n\t}\n\tif (registry.size === 0) return restore\n\n\t// A deck that registered *some* metrics has opted into measured fit, so a named\n\t// face we have no exact metrics for falls back to the conservative heuristic rather\n\t// than degrading to the bare flag — overflow still self-corrects, just less precisely.\n\t// An unnamed (theme-default) face stays unmeasurable: we cannot guess which face it is.\n\tconst heuristicFaces = new Set<string>()\n\tconst resolve = makeRegistryResolver(registry, (face) => heuristicFaces.add(face))\n\tconst unmeasuredShrink = new Set<string>()\n\tconst unmeasuredResize = new Set<string>()\n\tconst uncoveredByFace = new Map<string, Set<number>>()\n\n\tconst collectUnmeasured = (paragraphs: FitParagraph[], into: Set<string>): void => {\n\t\tfor (const para of paragraphs)\n\t\t\tfor (const run of para.runs) if (!resolve(run)) into.add(run.fontFace ?? '(theme default)')\n\t}\n\n\t/** Audit every set of runs the pass is about to measure — see the warning below. */\n\tconst auditCoverage = (paragraphs: FitParagraph[]): void =>\n\t\tcollectUncoveredCodepoints(paragraphs, registry, uncoveredByFace)\n\n\t/**\n\t * Bake measured shrink into a table's cells. Walks the cell grid (accounting for\n\t * colspan/rowspan) to size each cell's box from its column widths and row heights,\n\t * then lowers the run font sizes of any `fit:'shrink'` cell that overflows. Cells\n\t * in auto-height rows (no fixed `rowH`/table `h`) are skipped — the row grows instead.\n\t */\n\tconst measureTableCells = (tableObj: SlideObject, layout: PresSlideInternal['_presLayout']): void => {\n\t\tconst rows = tableObj.arrTabRows\n\t\tif (!rows || rows.length === 0 || !rows[0]) return\n\t\tconst tableOpts = (tableObj.options ?? {}) as RunOpts\n\t\tconst { numCols, colWidthsEmu, rowHeightEmu: pinnedRowHeightEmu } = resolveTableGridEmu(rows, tableOpts, layout)\n\t\tif (!(numCols > 0)) return\n\t\t// `null` is an auto-height row — it grows to fit, so there is nothing to shrink into.\n\t\tconst rowHeightEmu = (rIdx: number): number => pinnedRowHeightEmu(rIdx) ?? 0\n\n\t\tfor (const { cell, row: r, col: colStart, colSpan, rowSpan } of walkTableGrid(rows, numCols)) {\n\t\t\tconst colEnd = colStart + colSpan\n\t\t\tconst cellOpts = cell?.options ?? {}\n\t\t\tconst fit = cellOpts.fit ?? (tableOpts.fit === 'shrink' ? 'shrink' : undefined)\n\t\t\tif (fit !== 'shrink') continue\n\n\t\t\tlet widthEmu = 0\n\t\t\tfor (let c = colStart; c < colEnd; c++) widthEmu += colWidthsEmu[c] ?? 0\n\t\t\tlet heightEmu = 0\n\t\t\tlet autoHeight = false\n\t\t\tfor (let rr = r; rr < r + rowSpan; rr++) {\n\t\t\t\tconst h = rowHeightEmu(rr)\n\t\t\t\tif (h <= 0) {\n\t\t\t\t\tautoHeight = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\theightEmu += h\n\t\t\t}\n\t\t\tif (autoHeight) continue\n\n\t\t\tconst eff = effectiveCellOpts(cellOpts, tableOpts)\n\t\t\tconst ins = resolveCellInsetsEmu(eff.margin)\n\t\t\tconst innerWidthPt = (widthEmu - ins.marL - ins.marR) / EMU_PER_POINT\n\t\t\tconst innerHeightPt = (heightEmu - ins.marT - ins.marB) / EMU_PER_POINT\n\t\t\tif (!(innerWidthPt > 0) || !(innerHeightPt > 0)) continue\n\n\t\t\tconst paragraphs = extractParagraphs({ text: cell.text, options: eff })\n\t\t\tif (!paragraphs) continue\n\t\t\tauditCoverage(paragraphs)\n\t\t\tconst box: FitBox = { innerWidthPt, innerHeightPt }\n\t\t\tconst outcome = solveShrink(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'shrink') {\n\t\t\t\tconst f = outcome.result.fontScalePct / 100\n\t\t\t\tif (f < 1) {\n\t\t\t\t\trestores.push(restorer(cell, 'options'), restorer(cell, 'text'))\n\t\t\t\t\tscaleCellFontSizes(cell, eff, f)\n\t\t\t\t}\n\t\t\t} else if (outcome.kind === 'unmeasurable') {\n\t\t\t\tcollectUnmeasured(paragraphs, unmeasuredShrink)\n\t\t\t}\n\t\t\t// 'fits' → leave the authored size; the text already fits.\n\t\t}\n\t}\n\n\tconst measureObject = (obj: SlideObject, layout: PresSlideInternal['_presLayout']): void => {\n\t\t// Groups keep their children outside slide._slideObjects. Descend through every\n\t\t// nesting level so grouping remains a visual/editability operation and does not\n\t\t// disable the export-time fit pass for contained text.\n\t\tif (obj._type === SlideObjectType.group) {\n\t\t\tfor (const child of obj._groupObjects ?? []) measureObject(child, layout)\n\t\t\treturn\n\t\t}\n\t\tif (obj._type === SlideObjectType.table) {\n\t\t\tmeasureTableCells(obj, layout)\n\t\t\treturn\n\t\t}\n\t\tif (obj._type !== SlideObjectType.text) return\n\t\t// Only the bare string forms opt into measurement; an explicit object form is\n\t\t// already baked by the caller, and 'none' is a no-op.\n\t\tconst options = obj.options\n\t\tif (!options) return\n\t\tconst fit = options.fit\n\t\tif (fit !== 'shrink' && fit !== 'resize') return\n\n\t\tconst paragraphs = extractParagraphs(obj)\n\t\tif (!paragraphs) return\n\t\tauditCoverage(paragraphs)\n\t\tconst box = computeBox(obj, layout)\n\t\tif (!box) return\n\n\t\tif (fit === 'shrink') {\n\t\t\tconst outcome = solveShrink(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'shrink') {\n\t\t\t\tconst { fontScalePct, lnSpcReductionPct } = outcome.result\n\t\t\t\t// `lnSpcReduction` is written only when the solver reduced line spacing: `options.fit`\n\t\t\t\t// lands on a slide object's options, which the emitters spread, and `<a:normAutofit>`\n\t\t\t\t// omits the attribute for an absent one.\n\t\t\t\tconst shrink: TextFitShrinkProps = { type: 'shrink', fontScale: fontScalePct }\n\t\t\t\tif (lnSpcReductionPct) shrink.lnSpcReduction = lnSpcReductionPct\n\t\t\t\trestores.push(restorer(options, 'fit'))\n\t\t\t\toptions.fit = shrink\n\t\t\t} else if (outcome.kind === 'unmeasurable') {\n\t\t\t\tcollectUnmeasured(paragraphs, unmeasuredShrink)\n\t\t\t}\n\t\t\t// 'fits' → leave the bare flag; the text already fits, so no scale is needed.\n\t\t} else {\n\t\t\tconst outcome = solveResize(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'resize') {\n\t\t\t\tconst opts = obj.options as RunOpts\n\t\t\t\tconst { tIns, bIns } = resolveBodyInsetsEmu(opts)\n\t\t\t\tconst oldHeightEmu = getSmartParseNumber(opts.h, 'Y', layout)\n\t\t\t\tconst newHeightEmu = Math.round(outcome.neededInnerHeightPt * EMU_PER_POINT) + tIns + bIns\n\t\t\t\t// Shift the box origin so growth/shrink honors the vertical anchor; `off.y`\n\t\t\t\t// moves up by the anchor's share of the height delta (0 / half / full for t / ctr / b).\n\t\t\t\tconst oldYEmu = getSmartParseNumber(opts.y, 'Y', layout)\n\t\t\t\tconst shiftEmu = Math.round((newHeightEmu - oldHeightEmu) * anchorTopShareOfDelta(opts))\n\t\t\t\trestores.push(restorer(opts, 'h'), restorer(opts, 'y'))\n\t\t\t\topts.h = `${newHeightEmu}emu`\n\t\t\t\tif (shiftEmu !== 0) opts.y = `${oldYEmu - shiftEmu}emu`\n\t\t\t} else {\n\t\t\t\tcollectUnmeasured(paragraphs, unmeasuredResize)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const slide of slides) {\n\t\tfor (const obj of slide._slideObjects ?? []) measureObject(obj, slide._presLayout)\n\t}\n\n\tif (unmeasuredShrink.size > 0) {\n\t\twarn(\n\t\t\t'measure/shrink-unmeasured',\n\t\t\t`fit:'shrink' could not be measured for font(s) [${[...unmeasuredShrink].join(', ')}] — ` +\n\t\t\t\t'no registered metrics. Emitting bare <a:normAutofit/> (text will not pre-shrink in headless renders). ' +\n\t\t\t\t'Call pptx.registerFontMetrics(face, fontFilePathOrBytes) to enable measured fit.'\n\t\t)\n\t}\n\tif (unmeasuredResize.size > 0) {\n\t\twarn(\n\t\t\t'measure/resize-unmeasured',\n\t\t\t`fit:'resize' could not be measured for font(s) [${[...unmeasuredResize].join(', ')}] — ` +\n\t\t\t\t'no registered metrics. Emitting bare <a:spAutoFit/> with the authored height (box will not auto-grow in headless renders). ' +\n\t\t\t\t'Call pptx.registerFontMetrics(face, fontFilePathOrBytes) to enable measured fit.'\n\t\t)\n\t}\n\tif (uncoveredByFace.size > 0) {\n\t\tconst perFace = [...uncoveredByFace].map(([face, cps]) => `${face} → ${formatCodepoints(cps)}`).join('; ')\n\t\twarn(\n\t\t\t'measure/uncovered-codepoints',\n\t\t\t`Measured fit charged the .notdef advance for code point(s) the registered face does not cover (${perFace}) — ` +\n\t\t\t\t'PowerPoint renders those from a substituted font, so the measured width can be wrong in EITHER direction. ' +\n\t\t\t\t'Too narrow drops a line and the text overflows the baked size, the one case measured fit does not err safe. ' +\n\t\t\t\t'Register a face that covers them, or set an explicit fontFace on those runs.'\n\t\t)\n\t}\n\tif (heuristicFaces.size > 0) {\n\t\twarn(\n\t\t\t'measure/heuristic-metrics',\n\t\t\t`Note: measured fit used a conservative average-advance estimate for font(s) [${[...heuristicFaces].join(', ')}] — ` +\n\t\t\t\t'no exact metrics registered. Fit is approximate (may shrink/grow more than necessary). ' +\n\t\t\t\t'Call pptx.registerFontMetrics(face, fontFilePathOrBytes) for an exact fit.'\n\t\t)\n\t}\n\treturn restore\n}\n\n/**\n * The step that puts `target[key]` back as it stands now, an absent key included, so a restored\n * option bag is the authored one rather than one holding an `undefined` the caller never wrote.\n */\nfunction restorer<T extends object>(target: T, key: keyof T): () => void {\n\tconst had = Object.hasOwn(target, key)\n\tconst value = target[key]\n\treturn () => {\n\t\tif (had) target[key] = value\n\t\telse delete (target as Record<PropertyKey, unknown>)[key]\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fit-CcXbg__l.js","names":["resolveMarginInsetsEmu"],"sources":["../src/measure/font-collection.ts","../src/measure/font-metrics.ts","../src/measure/text-fit.ts","../src/measure/paragraphs.ts","../src/gen/table/cell-inherit.ts","../src/measure/table-fit.ts","../src/measure/fit.ts"],"sourcesContent":["/**\n * Font **collection** (`.ttc` / `.otc`) support for the write-side metrics.\n *\n * A collection is a single file holding several fonts that share their heavy tables.\n * `msgothic.ttc` is three fonts (MS Gothic, MS UI Gothic, MS PGothic) over one 5.5 MB\n * `glyf`; `cambria.ttc` is Cambria plus Cambria Math over one outline set. On Windows\n * that is how most of the East Asian faces ship, and Cambria too, so a measurement API\n * that only reads a bare sfnt cannot measure them at all.\n *\n * `opentype.js` does not read the `ttcf` wrapper (it throws `Unsupported OpenType\n * signature ttcf` from `parseBuffer`, still true in 2.0.0), so this module unwraps one\n * member into a standalone sfnt before handing the bytes over. It parses only the two\n * structures that requires: the table directories and the `name` table.\n *\n * Upstream tracks the gap as opentypejs/opentype.js#379, open since 2019, with #866 an\n * unmerged PR implementing it; check both before rewriting any of this.\n *\n * ## Layout\n *\n * ```text\n * 0 'ttcf' uint16 major, uint16 minor, uint32 numFonts, uint32 dirOffset[numFonts]\n * ... per member: uint32 sfntVersion, uint16 numTables, uint16 searchRange,\n * uint16 entrySelector, uint16 rangeShift, then numTables x 16-byte records\n * { char tag[4], uint32 checksum, uint32 offset, uint32 length }\n * ```\n *\n * The record `offset` is **absolute from the start of the file**, which is the whole\n * trick: two members name the same `glyf` bytes by pointing at them. So a member does\n * not have to be *copied out* to be read on its own; it is enough to give the reader a\n * buffer whose first bytes are that member's directory, leaving every table where it\n * already sits. See {@link extractFontFace}.\n */\n\nimport { InvalidOptionError, MediaError } from '../errors.js'\n\n/** `'ttcf'`, the tag that marks a font collection. */\nconst TTC_TAG = 'ttcf'\n\n/** Bytes in one sfnt table record: tag, checksum, offset, length. */\nconst RECORD_SIZE = 16\n\n/** Bytes in an sfnt table directory header, before the first record. */\nconst DIRECTORY_HEADER_SIZE = 12\n\n/** `name` IDs read for face identity: family, subfamily, full name, PostScript name. */\nconst NAME_FAMILY = 1\nconst NAME_SUBFAMILY = 2\nconst NAME_FULL = 4\nconst NAME_POSTSCRIPT = 6\n\n/** Identity of one font inside a font file, as read from its `name` table. */\nexport interface FontFaceInfo {\n\t/** Position in the file: `0` for a plain TTF/OTF, `0..n-1` inside a collection. */\n\treadonly index: number\n\t/** `name` ID 1, e.g. `'MS PGothic'`. Absent when the table has no readable record. */\n\treadonly family?: string\n\t/** `name` ID 2, e.g. `'Regular'`. */\n\treadonly subfamily?: string\n\t/** `name` ID 4, e.g. `'MS PGothic'`. */\n\treadonly fullName?: string\n\t/** `name` ID 6, e.g. `'MS-PGothic'`. */\n\treadonly postScriptName?: string\n}\n\n/** A parsed sfnt table directory: the member's format tag plus its table records. */\ninterface Directory {\n\treadonly sfntVersion: number\n\treadonly tables: readonly TableRecord[]\n}\n\ninterface TableRecord {\n\t/** Four ASCII characters, e.g. `'glyf'`. */\n\treadonly tag: string\n\treadonly checksum: number\n\t/** Absolute from the start of the file, shared between members of a collection. */\n\treadonly offset: number\n\treadonly length: number\n}\n\nfunction view(data: Uint8Array): DataView {\n\treturn new DataView(data.buffer, data.byteOffset, data.byteLength)\n}\n\n/** Four ASCII bytes at `off` as a string, or `''` when they run past the end. */\nfunction tagAt(data: Uint8Array, off: number): string {\n\tif (off < 0 || off + 4 > data.byteLength) return ''\n\tlet s = ''\n\tfor (let i = 0; i < 4; i++) s += String.fromCharCode(data[off + i] as number)\n\treturn s\n}\n\n/** True when `data` starts with the `ttcf` tag, i.e. holds more than one font. */\nexport function isFontCollection(data: Uint8Array): boolean {\n\treturn tagAt(data, 0) === TTC_TAG\n}\n\n/**\n * Offsets of every member's table directory, in file order. A plain sfnt has exactly\n * one, at 0.\n */\nfunction directoryOffsets(data: Uint8Array): number[] {\n\tif (!isFontCollection(data)) return [0]\n\tconst dv = view(data)\n\tif (data.byteLength < 12) throw new MediaError('font/parse-failed', 'Font collection header is truncated')\n\tconst numFonts = dv.getUint32(8)\n\t// A collection with no members, or one whose offset table cannot fit, is malformed\n\t// rather than merely unsupported: there is nothing to select from.\n\tif (numFonts === 0) throw new MediaError('font/parse-failed', 'Font collection declares 0 fonts')\n\tif (12 + numFonts * 4 > data.byteLength)\n\t\tthrow new MediaError(\n\t\t\t'font/parse-failed',\n\t\t\t`Font collection declares ${numFonts} fonts but the offset table is truncated`\n\t\t)\n\tconst offsets: number[] = []\n\tfor (let i = 0; i < numFonts; i++) offsets.push(dv.getUint32(12 + i * 4))\n\treturn offsets\n}\n\n/** Read the table directory at `dirOff`, materializing every record before any write. */\nfunction readDirectory(data: Uint8Array, dirOff: number): Directory {\n\tconst dv = view(data)\n\tif (dirOff + DIRECTORY_HEADER_SIZE > data.byteLength)\n\t\tthrow new MediaError('font/parse-failed', `Font table directory at ${dirOff} is truncated`)\n\tconst sfntVersion = dv.getUint32(dirOff)\n\tconst numTables = dv.getUint16(dirOff + 4)\n\tif (numTables === 0) throw new MediaError('font/parse-failed', `Font at ${dirOff} declares 0 tables`)\n\tconst end = dirOff + DIRECTORY_HEADER_SIZE + numTables * RECORD_SIZE\n\tif (end > data.byteLength)\n\t\tthrow new MediaError(\n\t\t\t'font/parse-failed',\n\t\t\t`Font at ${dirOff} declares ${numTables} tables but the directory is truncated`\n\t\t)\n\tconst tables: TableRecord[] = []\n\tfor (let i = 0; i < numTables; i++) {\n\t\tconst rec = dirOff + DIRECTORY_HEADER_SIZE + i * RECORD_SIZE\n\t\ttables.push({\n\t\t\ttag: tagAt(data, rec),\n\t\t\tchecksum: dv.getUint32(rec + 4),\n\t\t\toffset: dv.getUint32(rec + 8),\n\t\t\tlength: dv.getUint32(rec + 12),\n\t\t})\n\t}\n\treturn { sfntVersion, tables }\n}\n\n/**\n * Decode one `name` record's string. Windows (platform 3) and Unicode (platform 0)\n * records are UTF-16BE; Macintosh (platform 1) Roman is byte-per-character and\n * coincides with Latin-1 over the ASCII range these names use.\n */\nfunction decodeNameString(data: Uint8Array, off: number, length: number, platformID: number): string {\n\tif (off < 0 || off + length > data.byteLength) return ''\n\tif (platformID === 1) {\n\t\tlet s = ''\n\t\tfor (let i = 0; i < length; i++) s += String.fromCharCode(data[off + i] as number)\n\t\treturn s\n\t}\n\tlet s = ''\n\tfor (let i = 0; i + 1 < length; i += 2)\n\t\ts += String.fromCharCode(((data[off + i] as number) << 8) | (data[off + i + 1] as number))\n\treturn s\n}\n\n/**\n * How much a `name` record is preferred when several carry the same ID. Windows English\n * wins, then any Windows or Unicode record, then Macintosh. The ranking matters because\n * `msgothic.ttc` carries both `'MS Gothic'` (0x409) and the Japanese localized name for\n * the same ID, and a caller selecting by name types the former.\n */\nfunction nameRecordRank(platformID: number, languageID: number): number {\n\tif (platformID === 3) return languageID === 0x409 ? 3 : 2\n\tif (platformID === 0) return 2\n\tif (platformID === 1) return languageID === 0 ? 1 : 0\n\treturn 0\n}\n\n/** Read the wanted IDs out of a `name` table, keeping the best-ranked record for each. */\nfunction readNames(data: Uint8Array, base: number, length: number): Map<number, string> {\n\tconst out = new Map<number, string>()\n\tconst ranks = new Map<number, number>()\n\tif (base + 6 > data.byteLength || base + length > data.byteLength) return out\n\tconst dv = view(data)\n\tconst count = dv.getUint16(base + 2)\n\tconst storage = base + dv.getUint16(base + 4)\n\tfor (let i = 0; i < count; i++) {\n\t\tconst rec = base + 6 + i * 12\n\t\tif (rec + 12 > data.byteLength) break\n\t\tconst nameID = dv.getUint16(rec + 6)\n\t\tif (nameID !== NAME_FAMILY && nameID !== NAME_SUBFAMILY && nameID !== NAME_FULL && nameID !== NAME_POSTSCRIPT)\n\t\t\tcontinue\n\t\tconst platformID = dv.getUint16(rec)\n\t\tconst languageID = dv.getUint16(rec + 4)\n\t\tconst rank = nameRecordRank(platformID, languageID)\n\t\tif (rank <= (ranks.get(nameID) ?? -1)) continue\n\t\tconst text = decodeNameString(data, storage + dv.getUint16(rec + 10), dv.getUint16(rec + 8), platformID)\n\t\tif (!text) continue\n\t\tout.set(nameID, text)\n\t\tranks.set(nameID, rank)\n\t}\n\treturn out\n}\n\n/**\n * The fonts inside `data`, in file order. A plain TTF/OTF yields exactly one entry, so a\n * caller never has to branch on the container format.\n *\n * Identity comes from each member's own `name` table, which is one of the tables a\n * collection does *not* share. A field is absent when the table carries no readable\n * record for it; a font whose `name` table is missing or malformed still yields an entry\n * (with only `index`), because the metrics do not depend on it.\n * @param {Uint8Array} data - the font file's bytes\n * @returns {FontFaceInfo[]} one entry per font, index-ordered\n * @example listFontFaces(readFileSync('C:/Windows/Fonts/msgothic.ttc')).map((f) => f.family)\n */\nexport function listFontFaces(data: Uint8Array): FontFaceInfo[] {\n\treturn directoryOffsets(data).map((dirOff, index) => {\n\t\tconst { tables } = readDirectory(data, dirOff)\n\t\tconst name = tables.find((t) => t.tag === 'name')\n\t\tconst names = name ? readNames(data, name.offset, name.length) : new Map<number, string>()\n\t\tconst family = names.get(NAME_FAMILY)\n\t\tconst subfamily = names.get(NAME_SUBFAMILY)\n\t\tconst fullName = names.get(NAME_FULL)\n\t\tconst postScriptName = names.get(NAME_POSTSCRIPT)\n\t\treturn {\n\t\t\tindex,\n\t\t\t...(family ? { family } : {}),\n\t\t\t...(subfamily ? { subfamily } : {}),\n\t\t\t...(fullName ? { fullName } : {}),\n\t\t\t...(postScriptName ? { postScriptName } : {}),\n\t\t}\n\t})\n}\n\n/** A face's names, lowercased, for case-insensitive selection. */\nfunction selectableNames(face: FontFaceInfo): string[] {\n\treturn [face.family, face.fullName, face.postScriptName]\n\t\t.filter((n): n is string => typeof n === 'string' && n.length > 0)\n\t\t.map((n) => n.toLowerCase())\n}\n\n/** Render the available faces for an error message, e.g. ``0 `MS Gothic`, 1 `MS PGothic` ``. */\nfunction describeFaces(faces: readonly FontFaceInfo[]): string {\n\treturn faces.map((f) => `${f.index} \\`${f.family ?? f.fullName ?? '(unnamed)'}\\``).join(', ')\n}\n\n/**\n * Resolve a `font` selector against the faces in `data`.\n *\n * The selector means the same thing whatever the container: a plain TTF/OTF is a\n * one-entry list, so `{ font: 1 }` or a name that does not match is an error there too\n * rather than being quietly ignored. Silently falling back to the only/first font is the\n * failure mode worth refusing: it measures one face's advances while the caller believes\n * it registered another's, and nothing downstream can tell.\n * @param {Uint8Array} data - the font file's bytes\n * @param {number | string} [font] - 0-based index, or a name matched case-insensitively\n * against the family, full, and PostScript names. Absent selects index 0.\n * @returns {number} the index of the selected font\n */\nexport function resolveFontFace(data: Uint8Array, font?: number | string): number {\n\tif (font === undefined) return 0\n\tconst faces = listFontFaces(data)\n\tif (typeof font === 'number') {\n\t\tif (!Number.isInteger(font) || font < 0 || font >= faces.length)\n\t\t\tthrow new InvalidOptionError(\n\t\t\t\t'font/collection-index-out-of-range',\n\t\t\t\t`Font index ${font} is out of range: the file holds ${faces.length} font(s) (${describeFaces(faces)})`\n\t\t\t)\n\t\treturn font\n\t}\n\tconst wanted = font.toLowerCase()\n\tconst hit = faces.find((f) => selectableNames(f).includes(wanted))\n\tif (!hit)\n\t\tthrow new InvalidOptionError(\n\t\t\t'font/collection-face-not-found',\n\t\t\t`No font named \"${font}\" in this file. It holds: ${describeFaces(faces)}`\n\t\t)\n\treturn hit.index\n}\n\n/**\n * Bytes for one font of `data` as a standalone sfnt, ready for a parser that does not\n * read the `ttcf` wrapper.\n *\n * A plain TTF/OTF at index 0 is returned as-is. For a collection the member's tables are\n * **not copied out**: the file is copied once and the member's directory is written over\n * the prologue at offset 0, so every record keeps the absolute offset it already had and\n * the shared `glyf` is neither duplicated nor moved. The prologue is always large enough\n * to hold that directory, because a well-formed collection places the first table after\n * the `ttcf` header *and* every member's directory, which already includes this one.\n * That is asserted rather than assumed: a file that violates it would otherwise have its\n * first table silently overwritten.\n * @param {Uint8Array} data - the font file's bytes\n * @param {number} index - which font, as resolved by {@link resolveFontFace}\n * @returns {Uint8Array} a buffer whose first bytes are a plain sfnt table directory\n */\nexport function extractFontFace(data: Uint8Array, index: number): Uint8Array {\n\tconst offsets = directoryOffsets(data)\n\tconst dirOff = offsets[index]\n\tif (dirOff === undefined)\n\t\tthrow new InvalidOptionError(\n\t\t\t'font/collection-index-out-of-range',\n\t\t\t`Font index ${index} is out of range: the file holds ${offsets.length} font(s)`\n\t\t)\n\tif (!isFontCollection(data)) return data\n\n\tconst { sfntVersion, tables } = readDirectory(data, dirOff)\n\tconst prologue = DIRECTORY_HEADER_SIZE + tables.length * RECORD_SIZE\n\tconst firstTable = Math.min(...tables.map((t) => t.offset))\n\tif (prologue > firstTable)\n\t\tthrow new MediaError(\n\t\t\t'font/parse-failed',\n\t\t\t`Font ${index} in this collection cannot be unwrapped: its ${tables.length}-table directory needs ${prologue} bytes but the first table starts at ${firstTable}`\n\t\t)\n\n\t// Copy first, then overwrite: `dirOff` frequently sits *inside* the region about to be\n\t// written (member 0 of msgothic.ttc has its directory at 36, and the prologue is 380),\n\t// which is safe only because `readDirectory` already materialized every record.\n\tconst out = new Uint8Array(data)\n\tconst dv = new DataView(out.buffer, out.byteOffset, out.byteLength)\n\tconst entrySelector = Math.floor(Math.log2(tables.length))\n\tconst searchRange = RECORD_SIZE * 2 ** entrySelector\n\tdv.setUint32(0, sfntVersion)\n\tdv.setUint16(4, tables.length)\n\tdv.setUint16(6, searchRange)\n\tdv.setUint16(8, entrySelector)\n\tdv.setUint16(10, tables.length * RECORD_SIZE - searchRange)\n\tlet p = DIRECTORY_HEADER_SIZE\n\tfor (const t of tables) {\n\t\tfor (let i = 0; i < 4; i++) out[p + i] = t.tag.charCodeAt(i) & 0xff\n\t\tdv.setUint32(p + 4, t.checksum)\n\t\tdv.setUint32(p + 8, t.offset)\n\t\tdv.setUint32(p + 12, t.length)\n\t\tp += RECORD_SIZE\n\t}\n\t// `head.checkSumAdjustment` now describes the collection rather than this buffer. No\n\t// consumer here validates it, and recomputing it would mean check-summing the whole\n\t// file to produce a number only a validator reads.\n\treturn out\n}\n","/**\n * Write-side font metrics.\n *\n * Provides per-glyph advance widths for measured text fit (see `text-fit.ts`).\n * The library has no write-side font registration otherwise; consumers register\n * a face's font file via `pptx.registerFontMetrics(...)` and the measured-fit\n * pass uses these advances to compute a baked `fontScale` for `fit: 'shrink'`.\n *\n * Width is summed from **raw `hmtx` advances with no kerning/shaping** (GPOS/GSUB\n * are deliberately ignored): kerning almost always narrows a line, so raw advances\n * over-estimate width — the conservative direction (shrink a touch too much, never\n * overflow). See `docs/contributing/design/text-fit.md` (\"Font metrics provider\").\n */\n\nimport { InvalidOptionError, MediaError, UnsupportedFeatureError } from '../errors.js'\nimport { extractFontFace, resolveFontFace } from './font-collection.js'\nimport type { FitParagraph, MetricsResolver } from './text-fit.js'\n\n/** Per-(face,bold,italic) advance-width source backed by a parsed font file. */\nexport interface FontMetrics {\n\t/** Font design units per em (advances are in these units). */\n\treadonly unitsPerEm: number\n\t/**\n\t * Advance width of `text` at `sizePt`, in points. Sums raw glyph advances\n\t * (no kerning) and adds `charSpacingPt` after every character, matching how\n\t * PowerPoint widens runs with character spacing.\n\t */\n\tadvanceWidthPt: (text: string, sizePt: number, charSpacingPt?: number) => number\n\t/**\n\t * True if this face's cmap maps code point `cp` to a real glyph (not the\n\t * `.notdef` fallback). Use it to flag source code points the face cannot\n\t * render. Authoritative only for file-backed metrics; the unregistered-font\n\t * heuristic has no cmap and reports every code point as covered.\n\t */\n\thasCodepoint: (cp: number) => boolean\n}\n\n/** Minimal slice of an opentype.js `Font` that `OpentypeFontMetrics` relies on. */\ninterface OpentypeFontLike {\n\tunitsPerEm: number\n\tcharToGlyph: (ch: string) => { advanceWidth?: number } | undefined\n\thasChar: (ch: string) => boolean\n}\n\nclass OpentypeFontMetrics implements FontMetrics {\n\tprivate readonly font: OpentypeFontLike\n\tconstructor(font: OpentypeFontLike) {\n\t\tthis.font = font\n\t}\n\n\tget unitsPerEm(): number {\n\t\treturn this.font.unitsPerEm\n\t}\n\n\tadvanceWidthPt(text: string, sizePt: number, charSpacingPt = 0): number {\n\t\tif (!text) return 0\n\t\t// Sum raw per-glyph `hmtx` advances via cmap (charToGlyph) — deliberately\n\t\t// NOT getAdvanceWidth(), which runs GPOS/GSUB shaping (kerning narrows lines,\n\t\t// and some lookups even throw). Raw advances over-estimate width, the\n\t\t// conservative direction. `for..of` iterates code points (astral-safe).\n\t\tconst scale = sizePt / this.font.unitsPerEm\n\t\tlet width = 0\n\t\tlet count = 0\n\t\tfor (const ch of text) {\n\t\t\tconst glyph = this.font.charToGlyph(ch)\n\t\t\twidth += (glyph?.advanceWidth ?? 0) * scale\n\t\t\tcount++\n\t\t}\n\t\tif (charSpacingPt) width += charSpacingPt * count\n\t\treturn width\n\t}\n\n\thasCodepoint(cp: number): boolean {\n\t\t// opentype's charToGlyph() falls back to .notdef for uncovered code points,\n\t\t// so it can't answer coverage; hasChar() keys on the cmap (glyph index > 0).\n\t\treturn this.font.hasChar(String.fromCodePoint(cp))\n\t}\n}\n\nconst HEURISTIC_UNITS_PER_EM = 1000\n\n/**\n * Advance width of an ASCII/Unicode code point as a fraction of em, for the\n * unregistered-font fallback. Values are biased to **over-estimate** a typical\n * proportional Latin face: over-estimating width is the conservative direction for\n * both solvers (shrink a touch too much / grow a touch too tall, never overflow).\n * Non-Latin code points are treated as full-em (safe for CJK, which is otherwise\n * out of scope; slightly over-wide for accented Latin, which is harmless).\n */\nfunction heuristicCharRatio(ch: string): number {\n\tconst cp = ch.codePointAt(0) ?? 0\n\tif (cp > 0x2e7f) return 1.0 // CJK / full-width and beyond\n\tif (cp > 0xff) return 0.62 // Latin-Extended / accented / misc symbols\n\tif (ch === ' ' || ch === '\\t') return 0.3\n\tif (\"ijl.,'`!|:;\".includes(ch)) return 0.3\n\tif ('ftr()[]{}/\\\\I'.includes(ch)) return 0.4\n\tif (ch === 'm' || ch === 'w') return 0.9\n\tif (ch === 'M' || ch === 'W') return 0.98\n\tif (ch === '@' || ch === '%') return 1.0\n\tif (ch >= 'A' && ch <= 'Z') return 0.72\n\treturn 0.58 // lowercase, digits, default punctuation\n}\n\nclass HeuristicFontMetrics implements FontMetrics {\n\treadonly unitsPerEm = HEURISTIC_UNITS_PER_EM\n\tadvanceWidthPt(text: string, sizePt: number, charSpacingPt = 0): number {\n\t\tif (!text) return 0\n\t\tlet width = 0\n\t\tlet count = 0\n\t\tfor (const ch of text) {\n\t\t\twidth += heuristicCharRatio(ch) * sizePt\n\t\t\tcount++\n\t\t}\n\t\tif (charSpacingPt) width += charSpacingPt * count\n\t\treturn width\n\t}\n\n\thasCodepoint(): boolean {\n\t\treturn true // no cmap to consult; never fabricate a 'missing' glyph\n\t}\n}\n\nlet heuristicSingleton: FontMetrics | undefined\n\n/**\n * Shared, font-independent `FontMetrics` used when a named face has no registered\n * metrics but the deck has opted into measured fit (some other face is registered).\n * Approximate but conservative — see `heuristicCharRatio`. A deck with no\n * registered metrics at all does not engage measured fit, so this never fires there.\n */\nexport function getHeuristicFontMetrics(): FontMetrics {\n\tif (!heuristicSingleton) heuristicSingleton = new HeuristicFontMetrics()\n\treturn heuristicSingleton\n}\n\n/** Options for {@link parseFontMetrics}. */\nexport interface ParseFontMetricsOptions {\n\t/**\n\t * Which font to read out of a file that holds several: a 0-based index, or a name\n\t * matched case-insensitively against the family, full, and PostScript names\n\t * (`listFontFaces` lists them). Omitted selects the first.\n\t *\n\t * Collections (`.ttc`/`.otc`) are why this exists: `msgothic.ttc` is three fonts and\n\t * `cambria.ttc` is two. The selector means the same thing for a plain TTF/OTF, which\n\t * is a one-entry list, so a wrong index or an unmatched name is an error there rather\n\t * than being ignored.\n\t */\n\treadonly font?: number | string\n}\n\n/**\n * Parse a font file into a `FontMetrics`. Lazily imports opentype.js.\n *\n * Reads plain TTF/OTF and **font collections** (`.ttc`/`.otc`); for a collection, pass\n * `font` to say which member, since a collection has no single answer. The underlying\n * parser does not read the `ttcf` wrapper, so the selected member is unwrapped into a\n * standalone sfnt first (see `measure/font-collection.ts`).\n * @param {Uint8Array} data - the font file's bytes\n * @param {ParseFontMetricsOptions} [opts] - which font, for a file holding several\n * @returns {Promise<FontMetrics>} advance widths and cmap coverage for that font\n * @example await parseFontMetrics(bytes) // a plain .ttf\n * @example await parseFontMetrics(ttcBytes, { font: 'MS PGothic' })\n */\nexport async function parseFontMetrics(data: Uint8Array, opts?: ParseFontMetricsOptions): Promise<FontMetrics> {\n\t// Dynamic import keeps opentype.js off the critical/browser path until a\n\t// consumer actually registers metrics.\n\tconst mod = (await import('opentype.js')) as unknown as {\n\t\tparse?: (buf: ArrayBuffer) => OpentypeFontLike\n\t\tdefault?: { parse: (buf: ArrayBuffer) => OpentypeFontLike }\n\t}\n\tconst parse = mod.parse ?? mod.default?.parse\n\tif (typeof parse !== 'function')\n\t\tthrow new UnsupportedFeatureError('font/opentype-unavailable', 'opentype.js: parse() not found in module exports')\n\tconst sfnt = extractFontFace(data, resolveFontFace(data, opts?.font))\n\t// opentype.parse needs a standalone ArrayBuffer view of exactly the font bytes.\n\tconst buf = sfnt.buffer.slice(sfnt.byteOffset, sfnt.byteOffset + sfnt.byteLength) as ArrayBuffer\n\ttry {\n\t\treturn new OpentypeFontMetrics(parse(buf))\n\t} catch (ex) {\n\t\t// The parser throws bare `Error`s. Reclassify so a consumer can catch this by the\n\t\t// same taxonomy as every other library failure instead of matching on a message.\n\t\tthrow new MediaError('font/parse-failed', `Unable to parse font file: ${String(ex)}`, { cause: ex })\n\t}\n}\n\n/**\n * Registry of `FontMetrics` keyed by `(face, bold, italic)`. Variant advances\n * differ, so bold/italic are stored separately; lookup falls back to the regular\n * variant (then any registered variant of the face) so a deck that only registers\n * the regular weight still measures bold runs approximately rather than not at all.\n */\nexport class FontMetricsRegistry {\n\tprivate readonly map = new Map<string, FontMetrics>()\n\n\tprivate key(face: string, bold: boolean, italic: boolean): string {\n\t\treturn `${face.toLowerCase()}\\0${bold ? 1 : 0}\\0${italic ? 1 : 0}`\n\t}\n\n\tset(face: string, metrics: FontMetrics, opts?: { bold?: boolean; italic?: boolean }): void {\n\t\t// An empty name registers under a key no `fontFace` resolves to, so the metrics would sit unused.\n\t\tif (typeof face !== 'string' || face.trim() === '') {\n\t\t\tthrow new InvalidOptionError(\n\t\t\t\t'font/missing-typeface',\n\t\t\t\t`registerFontMetrics: \\`face\\` must be the non-empty family name your fontFace options use, got ${JSON.stringify(face)}.`\n\t\t\t)\n\t\t}\n\t\tthis.map.set(this.key(face, !!opts?.bold, !!opts?.italic), metrics)\n\t}\n\n\t/** True if any variant of `face` has registered metrics. */\n\thasFace(face: string): boolean {\n\t\tconst prefix = `${face.toLowerCase()}\\0`\n\t\tfor (const k of this.map.keys()) if (k.startsWith(prefix)) return true\n\t\treturn false\n\t}\n\n\t/**\n\t * Coverage of code point `cp` for `face`, read from the registered font's cmap:\n\t * `true`/`false` when a variant of `face` is registered (see {@link get} for the\n\t * exact→regular→any-variant fallback), or `undefined` when the face has **no**\n\t * registered metrics — \"unknown\", deliberately distinct from a `false`\n\t * \"registered but not covered\". A coverage audit must not treat an unregistered\n\t * face as fully covered, so callers get `undefined` here rather than the per-face\n\t * {@link FontMetrics.hasCodepoint} boolean (which, for the heuristic fallback,\n\t * always reports covered). Register the face via {@link parseFontMetrics} +\n\t * {@link set} first.\n\t */\n\thasCodepoint(\n\t\tface: string | undefined | null,\n\t\tcp: number,\n\t\topts?: { bold?: boolean; italic?: boolean }\n\t): boolean | undefined {\n\t\treturn this.get(face, opts?.bold, opts?.italic)?.hasCodepoint(cp)\n\t}\n\n\t/** Resolve metrics for a run, falling back from exact variant → regular → any variant. */\n\tget(face: string | undefined | null, bold = false, italic = false): FontMetrics | undefined {\n\t\t// A run with no explicit face inherits the theme font, which we cannot resolve\n\t\t// reliably here — treat as unregistered so measured fit degrades gracefully.\n\t\tif (typeof face !== 'string' || face.length === 0) return undefined\n\t\tconst exact = this.map.get(this.key(face, bold, italic))\n\t\tif (exact) return exact\n\t\tconst regular = this.map.get(this.key(face, false, false))\n\t\tif (regular) return regular\n\t\tconst prefix = `${face.toLowerCase()}\\0`\n\t\tfor (const [k, v] of this.map) if (k.startsWith(prefix)) return v\n\t\treturn undefined\n\t}\n\n\tget size(): number {\n\t\treturn this.map.size\n\t}\n}\n\n/**\n * A {@link MetricsResolver} backed by a registry: exact metrics for a registered face, otherwise\n * the shared heuristic fallback (with `onHeuristic` told which face it stood in for). A run with\n * no `fontFace` at all resolves to `undefined`, which the callers treat as unmeasurable.\n */\nexport function makeRegistryResolver(\n\tregistry: FontMetricsRegistry,\n\tonHeuristic?: (face: string) => void\n): MetricsResolver {\n\treturn (run) => {\n\t\tconst exact = registry.get(run.fontFace, run.bold, run.italic)\n\t\tif (exact) return exact\n\t\tif (typeof run.fontFace === 'string' && run.fontFace.length > 0) {\n\t\t\tonHeuristic?.(run.fontFace)\n\t\t\treturn getHeuristicFontMetrics()\n\t\t}\n\t\treturn undefined\n\t}\n}\n\n/**\n * Accumulate, per face, the code points `paragraphs` uses that the run's **registered**\n * metrics have no glyph for.\n *\n * This is the one thing the width arithmetic cannot see. PowerPoint substitutes another\n * face per code point and lays the run out in *that* font's advances; the model has no\n * fallback and charges the registered font's `.notdef` advance instead, which is a single\n * flat number unrelated to the glyph that actually paints. Unlike the other approximations\n * here it is **not** conservative in a fixed direction: a `.notdef` wider than the real\n * glyph over-reports (a phantom line, which is safe), a narrower one under-reports and can drop a\n * line, which is the overflow direction the resize bake has no safety net for. So it is\n * surfaced rather than absorbed. See `docs/contributing/design/text-fit.md` (\"Font fallback\").\n *\n * Runs whose face has no registered metrics at all are skipped: they measure through the\n * cmap-less heuristic, which has no coverage to report, and the caller already flags them\n * as approximated faces.\n * @param paragraphs - the runs to audit, as handed to the layout\n * @param registry - the metrics the layout resolved against\n * @param into - face → uncovered code points, added to in place\n */\nexport function collectUncoveredCodepoints(\n\tparagraphs: FitParagraph[],\n\tregistry: FontMetricsRegistry,\n\tinto: Map<string, Set<number>>\n): void {\n\tfor (const para of paragraphs) {\n\t\tfor (const run of para.runs) {\n\t\t\tconst face = run.fontFace\n\t\t\tif (typeof face !== 'string' || face.length === 0) continue\n\t\t\tconst metrics = registry.get(face, run.bold, run.italic)\n\t\t\tif (!metrics) continue\n\t\t\tlet missing: Set<number> | undefined\n\t\t\t// `for..of` iterates code points, so an astral character is audited whole\n\t\t\t// rather than as two uncovered surrogates.\n\t\t\tfor (const ch of run.text) {\n\t\t\t\tconst cp = ch.codePointAt(0)\n\t\t\t\tif (cp === undefined || metrics.hasCodepoint(cp)) continue\n\t\t\t\tmissing ??= into.get(face) ?? new Set<number>()\n\t\t\t\tmissing.add(cp)\n\t\t\t}\n\t\t\tif (missing) into.set(face, missing)\n\t\t}\n\t}\n}\n","/**\n * pptx-ts: Measured text fit (line-break simulator + shrink solver)\n *\n * Computes a baked `fontScale` for `fit: 'shrink'` so overflowing text renders\n * pre-shrunk in headless renderers (and on plain file-open) without a manual\n * edit/resize. See `docs/contributing/design/text-fit.md`.\n *\n * Calibration: every constant here is pinned against PowerPoint-authored fixtures\n * (`test/read/fixtures/autofit-calibration.json`). The model errs **conservative**\n * — it over-estimates width (raw advances, no kerning) and uses the calibrated\n * line pitch — so the computed `fontScale` is ≤ PowerPoint's and the text never\n * overflows in either PowerPoint or LibreOffice.\n */\n\nimport type { FontMetrics } from './font-metrics.js'\n\n/**\n * PowerPoint single-spacing line pitch as a multiple of font size.\n *\n * Calibrated from `autofit-calibration.json` (Deck 1, `autofit-line-metrics`):\n * the per-line `cy` delta is a **font-independent** 1.2117× at 12/18/32 pt across\n * {Aptos, Aptos SemiBold, Calibri, Tahoma, Arial}, and PowerPoint vs LibreOffice\n * agree to ≤ 0.041 pt. See \"Findings behind the constants\" in\n * `docs/contributing/design/text-fit.md`.\n */\nexport const SINGLE_LINE_PITCH = 1.2117\n\n/** PowerPoint's `fontScale` search grid: discrete 2.5% steps (`docs/contributing/design/text-fit.md`). */\nexport const FONT_SCALE_STEP_PCT = 2.5\n\n/** Floor for the shrink search (see `docs/contributing/design/text-fit.md` → Wrap simulator and solvers). */\nexport const MIN_FONT_SCALE_PCT = 25\n\n/**\n * Conservative safety factors applied by the shrink solver (not by the pure\n * `measureHeightPt`). Raw `hmtx` advances summed without shaping still pack a line\n * a little tighter than PowerPoint, which lays text out at a device DPI and rounds\n * each glyph advance up — so PowerPoint wraps marginally earlier and its fitted\n * box is marginally taller. Inflating measured width and height by these factors\n * makes the computed `fontScale` ≤ PowerPoint's across the calibration oracle\n * (`test/read/autofit-calibration-oracle.test.ts`: 0 violations over the Aptos\n * cases). They err on the side of shrinking slightly too much, never overflowing.\n */\nexport const WIDTH_SAFETY_FACTOR = 1.03\nexport const HEIGHT_SAFETY_FACTOR = 1.04\n\n/** One text run with the inputs measurement needs. */\nexport interface FitRun {\n\ttext: string\n\tsizePt: number\n\tbold?: boolean\n\titalic?: boolean\n\tfontFace?: string | undefined\n\t/** Character spacing in points (PowerPoint `spc`/1200). */\n\tcharSpacingPt?: number | undefined\n}\n\n/**\n * One paragraph: its runs plus vertical-rhythm options.\n *\n * The three `| undefined` members here are deliberate, and the exception to the rule the\n * generator's option bags follow (`options-internal.ts`): these are measurement records, built in\n * one place by `paragraphs.ts` and read in one place by the solver below, with `??` and\n * truthiness. Nothing spreads or enumerates them, so a key holding `undefined` cannot mean\n * anything different from an absent one — and the builder does produce every key on every run.\n * Saying so is more honest than making the builder omit keys nothing distinguishes.\n */\nexport interface FitParagraph {\n\truns: FitRun[]\n\t/** Line spacing as a percent of single (100 = single). Ignored if `lineSpacingPts` set. */\n\tlineSpacingPct?: number\n\t/** Exact line spacing in points (overrides `lineSpacingPct`). */\n\tlineSpacingPts?: number | undefined\n\tspaceBeforePts?: number\n\tspaceAfterPts?: number\n}\n\n/** Inner box (shape minus insets) the text must fit, in points. */\nexport interface FitBox {\n\tinnerWidthPt: number\n\tinnerHeightPt: number\n\t/**\n\t * `false` when the frame does not wrap (`wrap:false` / `wrap=\"none\"`): text lays\n\t * out as one line per paragraph (no width-wrapping), and the shrink solver must\n\t * additionally keep the widest line within `innerWidthPt`. A too-wide line\n\t * overflows HORIZONTALLY — `normAutofit`'s vertical shrink never catches it, so\n\t * without this check a non-wrapping line is never shrunk and spills out of the box\n\t * in PowerPoint. Defaults to wrapping (`true`), so table cells and `measureText`\n\t * are unaffected.\n\t */\n\twrap?: boolean\n}\n\n/** Resolve the metrics for a run, or `undefined` if the face is not registered. */\nexport type MetricsResolver = (run: FitRun) => FontMetrics | undefined\n\nexport interface ShrinkResult {\n\tfontScalePct: number\n\tlnSpcReductionPct: number\n}\n\nexport type ShrinkOutcome =\n\t| { kind: 'fits' } // already fits at 100% — no shrink needed\n\t| { kind: 'unmeasurable' } // a run's face has no registered metrics — caller degrades\n\t| { kind: 'shrink'; result: ShrinkResult }\n\ninterface WordToken {\n\tkind: 'word'\n\tw: number\n\tcharWidths: number[]\n}\ntype Token = WordToken | { kind: 'space'; w: number } | { kind: 'newline'; w: 0 }\n\nconst isWhitespace = (ch: string): boolean => ch === ' ' || ch === '\\t' || ch === ' ' || /\\s/.test(ch)\n\n/**\n * A code point that is its own wrap opportunity: a line may break either side of\n * it, with no whitespace involved. Latin words break only at whitespace, but\n * Chinese and Japanese text breaks between any two characters, so treating one\n * long run of them as a single unbreakable \"word\" moves the whole run to the next\n * line, over-reports the laid-out line count, and shrinks text that actually fits.\n *\n * **Hangul is deliberately absent.** UAX #14 makes Hangul breakable between\n * syllables, but PowerPoint does not: Korean is written with spaces between words\n * and the app breaks it like Latin. `autofit-cjk-wrap.pptx` pins that directly —\n * the same box that lays out in 2 lines in Han or Kana takes 3 in Hangul, because\n * the run moves down whole. A Hangul run longer than one line still breaks between\n * syllables, but that is the over-long-token character-wrap fallback in\n * `countLines`, which handles it without a break class. Adding Hangul here would\n * *under*-report the line count for Korean, which is the direction that overflows.\n *\n * Backed by `autofit-cjk-wrap.pptx` (PowerPoint-authored, one case per claim):\n * CJK Unified Ideographs, Hiragana/Katakana, fullwidth Latin, halfwidth Katakana\n * and Plane 2 all break per character; Hangul syllables do not. The remaining\n * ranges are the sibling blocks of the same UAX #14 class ID, generalized from\n * those cases rather than pinned one by one.\n *\n * Known gap: no kinsoku (line-break prohibition) rules. PowerPoint will not start\n * a line with `。` or `、` and hangs them past the right inset instead; this model\n * breaks before them. That is a widest-line difference, not a line-count one, and\n * `docs/contributing/design/text-fit.md` records it.\n */\nexport function isCjkBreakCharacter(ch: string): boolean {\n\tconst cp = ch.codePointAt(0) ?? 0\n\treturn (\n\t\t// U+3000 IDEOGRAPHIC SPACE falls in this first range but never reaches here:\n\t\t// `isWhitespace` claims it first, so it stays a space token.\n\t\t(cp >= 0x2e80 && cp <= 0x303f) || // CJK Radicals / Kangxi / IDC / CJK Symbols and Punctuation\n\t\t(cp >= 0x3040 && cp <= 0x30ff) || // Hiragana / Katakana (fixture)\n\t\t// Bopomofo and Bopomofo Extended sit either side of the Hangul Compatibility\n\t\t// Jamo block excluded below, but they are Chinese phonetic notation, not Korean:\n\t\t// same UAX #14 class as Han, and PowerPoint breaks them the same way.\n\t\t(cp >= 0x3100 && cp <= 0x312f) || // Bopomofo\n\t\t(cp >= 0x3190 && cp <= 0x319f) || // Kanbun\n\t\t(cp >= 0x31a0 && cp <= 0x31ff) || // Bopomofo Extended / CJK Strokes / Katakana Phonetic Extensions\n\t\t(cp >= 0x3200 && cp <= 0x4dbf) || // Enclosed CJK / CJK Compatibility / Ideographs Ext A\n\t\t(cp >= 0x4e00 && cp <= 0x9fff) || // CJK Unified Ideographs (fixture)\n\t\t(cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs\n\t\t(cp >= 0xfe10 && cp <= 0xfe1f) || // Vertical Forms\n\t\t(cp >= 0xfe30 && cp <= 0xfe4f) || // CJK Compatibility Forms\n\t\t// Halfwidth and Fullwidth Forms, minus U+FFA0..U+FFDF (halfwidth Hangul jamo),\n\t\t// which follows the Hangul rule above. Fullwidth Latin and halfwidth Katakana\n\t\t// are both fixture-backed.\n\t\t(cp >= 0xff00 && cp <= 0xff9f) ||\n\t\t(cp >= 0xffe0 && cp <= 0xffef) ||\n\t\t(cp >= 0x1b000 && cp <= 0x1b16f) || // Kana Supplement / Kana Extended-A / Small Kana Extension\n\t\t(cp >= 0x20000 && cp <= 0x2fffd) || // CJK Ideographs Extension B..F + Compatibility Supplement (fixture)\n\t\t(cp >= 0x30000 && cp <= 0x323af) // CJK Ideographs Extension G, H, I (Plane 3)\n\t)\n}\n\n/**\n * Tokenize one paragraph at a given `fontScalePct`. Words can span run boundaries\n * (a break is only allowed at whitespace, or either side of a per-character\n * breaking code point — see `isCjkBreakCharacter`). Returns `null` if any run's\n * face has no registered metrics (the paragraph cannot be measured).\n */\nfunction tokenizeParagraph(\n\tpara: FitParagraph,\n\tresolve: MetricsResolver,\n\tfontScalePct: number,\n\twidthSafety: number\n): Token[] | null {\n\tconst tokens: Token[] = []\n\tlet curWord: WordToken | null = null\n\tconst flushWord = (): void => {\n\t\tif (curWord) {\n\t\t\ttokens.push(curWord)\n\t\t\tcurWord = null\n\t\t}\n\t}\n\tfor (const run of para.runs) {\n\t\tconst metrics = resolve(run)\n\t\tif (!metrics) return null\n\t\tconst scaledSize = run.sizePt * (fontScalePct / 100)\n\t\tconst charSpacingPt = run.charSpacingPt ?? 0\n\t\tfor (const ch of run.text ?? '') {\n\t\t\tif (ch === '\\n') {\n\t\t\t\tflushWord()\n\t\t\t\ttokens.push({ kind: 'newline', w: 0 })\n\t\t\t} else if (isWhitespace(ch)) {\n\t\t\t\tflushWord()\n\t\t\t\t// Tabs are approximated as a single space-width gap (documented P1 gap).\n\t\t\t\tconst w = metrics.advanceWidthPt(ch === '\\t' ? ' ' : ch, scaledSize, charSpacingPt) * widthSafety\n\t\t\t\ttokens.push({ kind: 'space', w })\n\t\t\t} else {\n\t\t\t\tconst w = metrics.advanceWidthPt(ch, scaledSize, charSpacingPt) * widthSafety\n\t\t\t\tif (isCjkBreakCharacter(ch)) {\n\t\t\t\t\tflushWord()\n\t\t\t\t\ttokens.push({ kind: 'word', w, charWidths: [w] })\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (!curWord) curWord = { kind: 'word', w: 0, charWidths: [] }\n\t\t\t\tcurWord.w += w\n\t\t\t\tcurWord.charWidths.push(w)\n\t\t\t}\n\t\t}\n\t}\n\tflushWord()\n\treturn tokens\n}\n\n/** Greedy `wrap=square` line layout for a tokenized paragraph. */\ninterface LineLayout {\n\tlines: number\n\t/** Width (points) of the widest laid-out line — for natural/widest-line measurement. */\n\tmaxLineWidthPt: number\n}\n\n/**\n * Greedy `wrap=square` line layout: the wrapped line count plus the widest\n * laid-out line width. `maxLineWidthPt` tracks the running line width and records\n * it whenever a line completes (a wrap or the final line), so callers can measure\n * the actual text extent, not just the box width. Trailing whitespace counts\n * toward width, as PowerPoint counts it, which slightly over-reports — the\n * conservative direction, consistent with the wrap model erring wide. The\n * PowerPoint behaviour this follows is tabled in `docs/contributing/design/text-fit.md`.\n */\nfunction countLines(tokens: Token[], innerWidthPt: number): LineLayout {\n\tlet lines = 1\n\tlet lineW = 0\n\tlet maxLineWidthPt = 0\n\tconst finishLine = (): void => {\n\t\tif (lineW > maxLineWidthPt) maxLineWidthPt = lineW\n\t}\n\tfor (const tok of tokens) {\n\t\tif (tok.kind === 'newline') {\n\t\t\tfinishLine()\n\t\t\tlines++\n\t\t\tlineW = 0\n\t\t} else if (tok.kind === 'space') {\n\t\t\t// Trailing whitespace counts toward line width, as in PowerPoint; if it\n\t\t\t// overflows, the line wraps and the space is consumed at the break.\n\t\t\tif (lineW + tok.w > innerWidthPt && lineW > 0) {\n\t\t\t\tfinishLine()\n\t\t\t\tlines++\n\t\t\t\tlineW = 0\n\t\t\t} else {\n\t\t\t\tlineW += tok.w\n\t\t\t}\n\t\t} else if (tok.w <= innerWidthPt) {\n\t\t\tif (lineW + tok.w > innerWidthPt && lineW > 0) {\n\t\t\t\tfinishLine()\n\t\t\t\tlines++\n\t\t\t\tlineW = tok.w\n\t\t\t} else {\n\t\t\t\tlineW += tok.w\n\t\t\t}\n\t\t} else {\n\t\t\t// Over-long unbreakable word → character-wrap, as PowerPoint does at wrap=square.\n\t\t\tif (lineW > 0) {\n\t\t\t\tfinishLine()\n\t\t\t\tlines++\n\t\t\t\tlineW = 0\n\t\t\t}\n\t\t\tfor (const cw of tok.charWidths) {\n\t\t\t\tif (lineW + cw > innerWidthPt && lineW > 0) {\n\t\t\t\t\tfinishLine()\n\t\t\t\t\tlines++\n\t\t\t\t\tlineW = cw\n\t\t\t\t} else {\n\t\t\t\t\tlineW += cw\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfinishLine()\n\treturn { lines, maxLineWidthPt }\n}\n\n/** Max run size in a paragraph (PowerPoint's line height follows the tallest run). */\nfunction maxRunSizePt(para: FitParagraph): number {\n\tlet max = 0\n\tfor (const run of para.runs) if (run.sizePt > max) max = run.sizePt\n\treturn max\n}\n\n/** Laid-out result of {@link measureLayout}: total height (points) + wrapped line count. */\nexport interface LayoutResult {\n\theightPt: number\n\tlineCount: number\n\t/**\n\t * Width (points) of the widest laid-out line across all paragraphs. Useful for\n\t * tightening a box to the actual text extent or measuring a natural (single-line)\n\t * width. Carries the same `widthSafety` inflation as the wrap decision, so a box\n\t * set to this width will not re-wrap. Conservative (slightly wide).\n\t */\n\twidestLineWidthPt: number\n}\n\n/**\n * Lay out `paragraphs` at a given scale/reduction and return the total height\n * (points) and wrapped line count, or `null` if any paragraph is unmeasurable.\n * Errs tall (conservative): includes space-before/after and the calibrated line\n * pitch. The single source of truth for both {@link measureHeightPt} (the solvers)\n * and the public layout-time measure API.\n */\nexport function measureLayout(\n\tparagraphs: FitParagraph[],\n\tinnerWidthPt: number,\n\tresolve: MetricsResolver,\n\tfontScalePct: number,\n\tlnSpcReductionPct: number,\n\twidthSafety = 1\n): LayoutResult | null {\n\t// Negated so `NaN` is refused too; `Infinity` still passes, for a layout that does not wrap.\n\tif (!(innerWidthPt > 0)) return null\n\tlet total = 0\n\tlet lineCount = 0\n\tlet widestLineWidthPt = 0\n\tfor (const para of paragraphs) {\n\t\tconst tokens = tokenizeParagraph(para, resolve, fontScalePct, widthSafety)\n\t\tif (tokens === null) return null\n\t\tconst { lines, maxLineWidthPt } = countLines(tokens, innerWidthPt)\n\t\tlineCount += lines\n\t\tif (maxLineWidthPt > widestLineWidthPt) widestLineWidthPt = maxLineWidthPt\n\t\tconst scaledMax = maxRunSizePt(para) * (fontScalePct / 100)\n\t\tlet lineHeight =\n\t\t\tpara.lineSpacingPts != null && para.lineSpacingPts > 0\n\t\t\t\t? para.lineSpacingPts\n\t\t\t\t: SINGLE_LINE_PITCH * scaledMax * ((para.lineSpacingPct ?? 100) / 100)\n\t\tlineHeight *= 1 - lnSpcReductionPct / 100\n\t\ttotal += lines * lineHeight + (para.spaceBeforePts ?? 0) + (para.spaceAfterPts ?? 0)\n\t}\n\treturn { heightPt: total, lineCount, widestLineWidthPt }\n}\n\n/**\n * Total laid-out height (points) at a given scale/reduction, or `null` if any\n * paragraph is unmeasurable. Thin wrapper over {@link measureLayout}.\n */\nexport function measureHeightPt(\n\tparagraphs: FitParagraph[],\n\tinnerWidthPt: number,\n\tresolve: MetricsResolver,\n\tfontScalePct: number,\n\tlnSpcReductionPct: number,\n\twidthSafety = 1\n): number | null {\n\tconst result = measureLayout(paragraphs, innerWidthPt, resolve, fontScalePct, lnSpcReductionPct, widthSafety)\n\treturn result === null ? null : result.heightPt\n}\n\n/** What the resize solver concluded: it could not measure, or the inner height the text needs. */\nexport type ResizeOutcome =\n\t| { kind: 'unmeasurable' } // a run's face has no registered metrics — caller degrades\n\t| { kind: 'resize'; neededInnerHeightPt: number }\n\n/**\n * Width used for wrap layout: the inner box width when wrapping, or unbounded for a\n * non-wrapping frame (`wrap:false`) so each paragraph lays out as a single line. A\n * non-wrapping frame's width constraint is enforced separately, against the widest\n * laid-out line — see {@link solveShrink}.\n */\nfunction layoutWidthPt(box: FitBox): number {\n\treturn box.wrap === false ? Infinity : box.innerWidthPt\n}\n\n/**\n * Inner height (points) the text needs at full size — the value to bake into the\n * shape's `a:ext/@cy` for `fit: 'resize'` (`spAutoFit`). Unlike shrink, resize has\n * **no safety net**: an under-estimate overflows (there is no text scaling\n * fallback), so this errs **tall** — width is inflated (earlier wrap ⇒ more lines)\n * and the laid-out height by the calibrated height factor, so the computed `cy` is\n * ≥ PowerPoint's and ≥ the LibreOffice-rendered height across the resize oracle.\n */\nexport function solveResize(paragraphs: FitParagraph[], box: FitBox, resolve: MetricsResolver): ResizeOutcome {\n\tconst h = measureHeightPt(paragraphs, layoutWidthPt(box), resolve, 100, 0, WIDTH_SAFETY_FACTOR)\n\tif (h === null) return { kind: 'unmeasurable' }\n\treturn { kind: 'resize', neededInnerHeightPt: h * HEIGHT_SAFETY_FACTOR }\n}\n\n/**\n * Largest `fontScale` (on PowerPoint's 2.5% grid) at which the text fits the box.\n * Width and height both re-measured per scale. Conservative: because the model\n * over-estimates, the returned scale is ≤ PowerPoint's and the text never overflows.\n *\n * `lnSpcReduction` is left at 0 — dropping `fontScale` alone is provably\n * conservative (PowerPoint trades line-spacing reduction to keep the font *larger*,\n * so a reduction-free fit is always ≤ PowerPoint's scale). The reduction ramp\n * PowerPoint applies is recorded in `docs/contributing/design/text-fit.md`.\n */\nexport function solveShrink(paragraphs: FitParagraph[], box: FitBox, resolve: MetricsResolver): ShrinkOutcome {\n\tconst width = layoutWidthPt(box)\n\tconst noWrap = box.wrap === false\n\t// Inflate measured width (earlier wrap) and height by the calibrated safety\n\t// factors so the fit threshold is conservative against PowerPoint. For a\n\t// non-wrapping frame the single line always fits the box HEIGHT, so height alone\n\t// never triggers a shrink: also require the widest (unwrapped) line to fit the box\n\t// WIDTH. `widestLineWidthPt` already carries the WIDTH_SAFETY_FACTOR inflation, so\n\t// comparing it straight to `innerWidthPt` stays on the conservative (shrink-more) side.\n\tconst fits = (scale: number): boolean | null => {\n\t\tconst layout = measureLayout(paragraphs, width, resolve, scale, 0, WIDTH_SAFETY_FACTOR)\n\t\tif (layout === null) return null\n\t\tif (layout.heightPt * HEIGHT_SAFETY_FACTOR > box.innerHeightPt) return false\n\t\tif (noWrap && layout.widestLineWidthPt > box.innerWidthPt) return false\n\t\treturn true\n\t}\n\n\tconst at100 = fits(100)\n\tif (at100 === null) return { kind: 'unmeasurable' }\n\tif (at100) return { kind: 'fits' }\n\n\tfor (let scale = 100 - FONT_SCALE_STEP_PCT; scale >= MIN_FONT_SCALE_PCT; scale -= FONT_SCALE_STEP_PCT) {\n\t\tif (fits(scale)) return { kind: 'shrink', result: { fontScalePct: scale, lnSpcReductionPct: 0 } }\n\t}\n\t// Even at the floor it overflows our conservative model — bake the floor as best effort.\n\treturn { kind: 'shrink', result: { fontScalePct: MIN_FONT_SCALE_PCT, lnSpcReductionPct: 0 } }\n}\n","/**\n * pptx-ts: turning a slide text object into the simulator's inputs\n *\n * The lower half of the measured-fit pass: normalize a text object's runs into `FitParagraph`s,\n * resolve its body insets and box, and work out how a height change is shared between `off.y` and\n * `ext.cy` for a given anchor. Everything here is about *reading* an authored object; the solving\n * and the rewriting live in the siblings (`table-fit.ts`, `fit.ts`).\n */\n\nimport { DEF_FONT_SIZE } from '../constants-internal.js'\nimport { EMU_PER_POINT } from '../units.js'\nimport { getSmartParseNumber, resolveInsetsEmu as resolveMarginInsetsEmu } from '../units-internal.js'\nimport { BODY_INSET_DEFAULTS_EMU } from '../ooxml/body-insets.js'\nimport type { FitBox, FitParagraph, FitRun } from './text-fit.js'\nimport { TextAnchor } from '../enums.js'\nimport type { TextProps, TextPropsOptions } from '../types/index.js'\nimport type { ObjectOptionsInternal, SlideObject, PresSlideInternal } from '../types/internal.js'\nimport { pickDefined } from '../options-internal.js'\n\nconst CRLF_RE = /\\r*\\n/g\n\nexport type RunOpts = TextPropsOptions & ObjectOptionsInternal\n\n/**\n * The two fields a run list is read from, and the whole contract {@link normalizeRuns} and\n * {@link extractParagraphs} have.\n *\n * Both used to take a full `SlideObject`, which is why both of their table call sites had to\n * write `{ text: cell.text, options: eff } as unknown as SlideObject` — a cell's `text` is\n * `string | TableCellInternal[]` and a slide object's is `TextProps[]`, so nothing weaker than a\n * double cast would fit. Naming the two fields these functions actually read makes a table\n * cell an ordinary argument, and a `SlideObject` still one too.\n *\n * `text` is deliberately loose: `normalizeRuns` accepts a bare string, a number, one\n * `TextProps`, or an array of them, and branches on the shape at runtime.\n */\ninterface RunSource {\n\ttext?: unknown\n\toptions?: RunOpts\n}\n\n/** Normalize `slideObj.text` (string | TextProps | TextProps[]) to a run list. */\nexport function normalizeRuns(obj: RunSource): TextProps[] {\n\tconst opts = obj.options ?? {}\n\tconst text = obj.text\n\tif (text == null) return []\n\tif (typeof text === 'string' || typeof text === 'number') return [{ text: String(text), options: opts }]\n\t// `pickDefined` for `text`: a run that carries none keeps the key off, which is what the\n\t// `TextProps` the generator builds do — this list is handed straight to `extractParagraphs`\n\t// and, from the table path, compared against runs that came from there.\n\tif (!Array.isArray(text) && typeof text === 'object' && 'text' in text) {\n\t\tconst t = text as TextProps\n\t\treturn [{ ...pickDefined(t, ['text']), options: t.options ?? opts }]\n\t}\n\tif (Array.isArray(text))\n\t\treturn (text as TextProps[]).map((t) => ({ ...pickDefined(t, ['text']), options: t.options ?? opts }))\n\treturn []\n}\n\n/** Build a measurable `FitParagraph[]` from a text object, or null if not measurable. */\nexport function extractParagraphs(obj: RunSource): FitParagraph[] | null {\n\tconst opts = obj.options ?? {}\n\tconst runs = normalizeRuns(obj)\n\tif (runs.length === 0) return null\n\treturn buildFitParagraphs(runs, opts)\n}\n\n/**\n * Convert a run list (+ box-level default options) into a measurable\n * `FitParagraph[]`, or null if empty. The single converter shared by the\n * export-time pass (`extractParagraphs`) and the public layout-time\n * `measureText` API, so a layout-time prediction and the baked export never drift.\n */\nexport function buildFitParagraphs(runs: TextProps[], opts: RunOpts): FitParagraph[] | null {\n\tif (runs.length === 0) return null\n\n\t// Expand \"\\n\" inside a run into separate pieces, flagging the paragraph break\n\t// after each (mirrors `gen/slide/objects/table.ts` STEP 4). `breakLine` ends a paragraph too.\n\tinterface Piece {\n\t\ttext: string\n\t\toptions: RunOpts\n\t\tbreakAfter: boolean\n\t}\n\tconst pieces: Piece[] = []\n\tfor (const run of runs) {\n\t\tconst ro = (run.options ?? opts) as RunOpts\n\t\tconst raw = String(run.text ?? '').replace(CRLF_RE, '\\n')\n\t\tif (raw.includes('\\n')) {\n\t\t\tconst lines = raw.split('\\n')\n\t\t\tlines.forEach((line, i) => {\n\t\t\t\tconst isLast = i === lines.length - 1\n\t\t\t\tpieces.push({ text: line, options: ro, breakAfter: isLast ? !!ro.breakLine : true })\n\t\t\t})\n\t\t} else {\n\t\t\tpieces.push({ text: raw, options: ro, breakAfter: !!ro.breakLine })\n\t\t}\n\t}\n\n\tconst toRun = (p: Piece): FitRun => {\n\t\tconst ro = p.options\n\t\tconst sizePt = Number(ro.fontSize ?? opts.fontSize ?? DEF_FONT_SIZE)\n\t\treturn {\n\t\t\ttext: p.text,\n\t\t\tsizePt: Number.isFinite(sizePt) && sizePt > 0 ? sizePt : DEF_FONT_SIZE,\n\t\t\tbold: !!(ro.bold ?? opts.bold),\n\t\t\titalic: !!(ro.italic ?? opts.italic),\n\t\t\tfontFace: ro.fontFace ?? opts.fontFace,\n\t\t\tcharSpacingPt: (ro.charSpacing ?? opts.charSpacing) || undefined,\n\t\t}\n\t}\n\tconst toPara = (runsForPara: FitRun[], paraOpts: RunOpts): FitParagraph => {\n\t\tconst lineSpacing = paraOpts.lineSpacing ?? opts.lineSpacing\n\t\tconst lineSpacingMultiple = paraOpts.lineSpacingMultiple ?? opts.lineSpacingMultiple\n\t\treturn {\n\t\t\truns: runsForPara,\n\t\t\tlineSpacingPts: typeof lineSpacing === 'number' && lineSpacing > 0 ? lineSpacing : undefined,\n\t\t\tlineSpacingPct:\n\t\t\t\ttypeof lineSpacingMultiple === 'number' && lineSpacingMultiple > 0 ? lineSpacingMultiple * 100 : 100,\n\t\t\tspaceBeforePts: Number(paraOpts.paraSpaceBefore ?? opts.paraSpaceBefore ?? 0) || 0,\n\t\t\tspaceAfterPts: Number(paraOpts.paraSpaceAfter ?? opts.paraSpaceAfter ?? 0) || 0,\n\t\t}\n\t}\n\n\tconst paras: FitParagraph[] = []\n\tlet cur: FitRun[] = []\n\tlet curParaOpts: RunOpts = opts\n\tfor (const piece of pieces) {\n\t\tcur.push(toRun(piece))\n\t\tcurParaOpts = piece.options\n\t\tif (piece.breakAfter) {\n\t\t\tparas.push(toPara(cur, curParaOpts))\n\t\t\tcur = []\n\t\t}\n\t}\n\tif (cur.length > 0) paras.push(toPara(cur, curParaOpts))\n\treturn paras.length > 0 ? paras : null\n}\n\ninterface InsetsEmu {\n\tlIns: number\n\trIns: number\n\ttIns: number\n\tbIns: number\n}\n\n/**\n * Resolve a text frame's insets (EMU): explicit `_bodyProp` (from `inset`) → `margin` →\n * PowerPoint's defaults.\n *\n * Named for the question it answers, which is not the one `units-internal.resolveInsetsEmu`\n * answers: that one takes a `margin` alone and returns `null` when the caller stated none, so\n * an emitter can leave the attributes off. This one takes the whole option bag, consults\n * `_bodyProp` first, and always produces four numbers, because a solver has to measure against\n * something. Two exported functions with one name, imported from two places, was a coin-flip\n * for anyone reading a call site.\n *\n * The `[T, R, B, L]` shuffle and the defaults both come from the modules that own them rather\n * than being spelled again here.\n */\nexport function resolveBodyInsetsEmu(opts: RunOpts): InsetsEmu {\n\tconst bp = opts._bodyProp ?? {}\n\tlet lIns = bp.lIns\n\tlet rIns = bp.rIns\n\tlet tIns = bp.tIns\n\tlet bIns = bp.bIns\n\tif (lIns == null && rIns == null && tIns == null && bIns == null) {\n\t\tconst insets = resolveMarginInsetsEmu(opts.margin)\n\t\tif (insets) ({ l: lIns, r: rIns, t: tIns, b: bIns } = insets)\n\t}\n\treturn {\n\t\tlIns: lIns ?? BODY_INSET_DEFAULTS_EMU.left,\n\t\trIns: rIns ?? BODY_INSET_DEFAULTS_EMU.right,\n\t\ttIns: tIns ?? BODY_INSET_DEFAULTS_EMU.top,\n\t\tbIns: bIns ?? BODY_INSET_DEFAULTS_EMU.bottom,\n\t}\n}\n\n/**\n * Resolve the inner box (shape minus insets) in points; null if degenerate.\n *\n * Reads the object's own `opts.w/h` with no ancestor walk — correct only because a group keeps an\n * identity child coordinate space (`chOff/chExt == off/ext`, see the `gen/slide/object.ts` group renderer and\n * `docs/groups.md`), so a group never scales its children and a grouped text box's authored w/h is its\n * true rendered size. `applyMeasuredFit` reaches here for grouped text via its explicit group descent\n * (`measureObject`). If `addGroup` ever authored a scaled group (non-identity `chExt`), this would need\n * the same ancestor-scale composition `Shape.absoluteFrame` performs on the read path.\n */\nexport function computeBox(obj: SlideObject, presLayout: PresSlideInternal['_presLayout']): FitBox | null {\n\tconst opts = (obj.options ?? {}) as RunOpts\n\tconst wEmu = getSmartParseNumber(opts.w, 'X', presLayout)\n\tconst hEmu = getSmartParseNumber(opts.h, 'Y', presLayout)\n\tif (!(wEmu > 0) || !(hEmu > 0)) return null\n\n\tconst { lIns, rIns, tIns, bIns } = resolveBodyInsetsEmu(opts)\n\n\t// wrap=none lays text out one line per paragraph (no width-wrapping, handled by\n\t// the solver via the wrap flag), but the box width is still a real constraint:\n\t// solveShrink enforces it against the widest line so an over-wide non-wrapping\n\t// line shrinks to fit horizontally instead of spilling out of the box.\n\tconst wrap = (opts._bodyProp ?? {}).wrap !== false\n\tconst innerWidthPt = (wEmu - lIns - rIns) / EMU_PER_POINT\n\tconst innerHeightPt = (hEmu - tIns - bIns) / EMU_PER_POINT\n\tif (!(innerHeightPt > 0)) return null\n\tif (!(innerWidthPt > 0)) return null\n\treturn { innerWidthPt, innerHeightPt, wrap }\n}\n\n/** Vertical-anchor share of a height change that moves the box top up (`off.y` shift). */\nexport function anchorTopShareOfDelta(opts: RunOpts): number {\n\t// `_bodyProp.anchor` is the resolved valign ('t' | 'ctr' | 'b'); default 'ctr'.\n\tconst anchor = (opts._bodyProp ?? {}).anchor\n\tif (anchor === TextAnchor.t) return 0 // grow downward — top fixed\n\tif (anchor === TextAnchor.b) return 1 // grow upward — bottom fixed\n\treturn 0.5 // centered growth (default)\n}\n","/**\n * pptx-ts: what a table cell inherits from its table.\n *\n * A cell that states nothing takes the table's value, and two paths resolve that: the emitter,\n * building the bag it hands to the text-body writer, and the measured-fit pass, building the\n * effective text it lays out. They inherited **different lists** -- the measure side named\n * `italic`, `charSpacing`, `lineSpacing` and `lineSpacingMultiple` that the emitter did not,\n * while its docstring claimed to mirror the emitter's -- so a table-level `italic` was measured\n * with italic metrics and emitted upright, and on `fit: 'shrink'` a table-level line spacing\n * made the solver compute a taller layout and bake a smaller font that the cell then rendered\n * at default spacing. `pptx.tableLayout()` reported geometry the file disagreed with.\n *\n * So the text keys are one list, shared. The second list is the emitter's alone, and is a\n * statement rather than an omission: those keys either paint (`fill`, `color`, `border`,\n * `underline`) or are not modelled by the fitter (`textDirection`, which does change how text\n * lays out -- the measured-fit pass does not read it on a cell either way, and widening the\n * fitter to handle vertical cell text is its own change).\n */\n\n/**\n * The keys both paths inherit: everything that decides how a cell's text is laid out.\n *\n * `margin` and `valign` are here rather than below because the fitter reads them -- insets\n * shrink the box the text has to fit, and the anchor decides where a short line sits in it.\n */\nexport const CELL_INHERITED_TEXT_KEYS = [\n\t'align',\n\t'bold',\n\t'charSpacing',\n\t'fontFace',\n\t'fontSize',\n\t'italic',\n\t'lineSpacing',\n\t'lineSpacingMultiple',\n\t'margin',\n\t'valign',\n] as const\n\n/** The keys only the emitter inherits: they paint, or the fitter does not model them. */\nconst CELL_INHERITED_EMIT_KEYS = ['border', 'color', 'fill', 'textDirection', 'underline'] as const\n\n/** Every key the emitter inherits from the table onto a cell. */\nexport const CELL_INHERITED_KEYS = [...CELL_INHERITED_TEXT_KEYS, ...CELL_INHERITED_EMIT_KEYS] as const\n","/**\n * pptx-ts: measuring a table's row heights and cell fits\n *\n * A table is measured cell by cell against its resolved grid: each cell inherits the table's text\n * options where it sets none, gets its own margins resolved to EMU insets, and is laid out inside\n * the column span it actually occupies. A merged region is measured once, at its origin, across\n * the columns it covers — which is what `walkTableGrid` exists to hand out.\n */\n\nimport { DEF_FONT_SIZE, MIN_FONT_SIZE_PT } from '../constants-internal.js'\nimport { type GridPlacement, tableColCount, walkTableGrid } from '../gen/table/grid.js'\nimport { EMU_PER_POINT, emuToInches } from '../units.js'\nimport {\n\tautoPageLineHeightEmu,\n\tgetSmartParseNumber,\n\tmarginToEmu,\n\tresolveCellMarginsInches,\n\tresolveTableColWidthsEmu,\n\tresolveTableRowHeightEmu,\n} from '../units-internal.js'\nimport { measureLayout, WIDTH_SAFETY_FACTOR, HEIGHT_SAFETY_FACTOR } from './text-fit.js'\nimport { makeRegistryResolver, type FontMetricsRegistry } from './font-metrics.js'\nimport { extractParagraphs, type RunOpts } from './paragraphs.js'\nimport { CELL_INHERITED_TEXT_KEYS } from '../gen/table/cell-inherit.js'\nimport type { TableCellInternal } from '../types/internal.js'\nimport type {\n\tCoord,\n\tMargin,\n\tPresLayout,\n\tTableCellLayout,\n\tTableCellProps,\n\tTableLayoutResult,\n\tTableProps,\n} from '../types/index.js'\n\n/**\n * Effective cell options: the cell's own values, with table-level values filled in where unset.\n *\n * The keys are `CELL_INHERITED_TEXT_KEYS` (`gen/table/cell-inherit.ts`), the half of the\n * emitter's list that decides how text lays out. This used to be its own list, claiming in its\n * docstring to mirror the emitter's while naming four keys the emitter did not.\n *\n * PowerPoint has no text-autofit for a table cell — `a:tcPr` carries no autofit, and the app\n * ignores a `normAutofit` inside one; rows auto-grow instead. So a cell's `fit: 'shrink'` is\n * honoured by baking a *reduced literal font size* onto its runs, which both PowerPoint and\n * LibreOffice render identically with no edit or resize. That is what makes these options worth\n * resolving here: the shrink is computed against the cell's effective text, not the table's.\n */\nexport function effectiveCellOpts(cellOpts: TableCellProps, tableOpts: RunOpts): RunOpts {\n\tconst merged = { ...cellOpts } as RunOpts\n\tfor (const k of CELL_INHERITED_TEXT_KEYS) {\n\t\tif (merged[k] === undefined && tableOpts[k] !== undefined) (merged as Record<string, unknown>)[k] = tableOpts[k]\n\t}\n\treturn merged\n}\n\ninterface CellInsetsEmu {\n\tmarL: number\n\tmarR: number\n\tmarT: number\n\tmarB: number\n}\n\n/** Resolve a cell's margins to EMU insets, mirroring `gen/slide/objects/table.ts` (array is `[T,R,B,L]`, inches; see `marginToEmu`). */\nexport function resolveCellInsetsEmu(margin: Margin | undefined): CellInsetsEmu {\n\tconst arr = resolveCellMarginsInches(margin)\n\treturn {\n\t\tmarT: marginToEmu(arr[0]),\n\t\tmarR: marginToEmu(arr[1]),\n\t\tmarB: marginToEmu(arr[2]),\n\t\tmarL: marginToEmu(arr[3]),\n\t}\n}\n\n/**\n * Bake a reduced font size onto a cell's runs by factor `f` (< 1). The cell's options and runs are\n * replaced with scaled copies, never edited in place. The cell itself is the stored slide model,\n * so `applyMeasuredFit` puts the authored options and runs back once the write is built.\n *\n * The shrunk size never goes below {@link MIN_FONT_SIZE_PT}, the emitter's own bound. It used to\n * have no minimum, so a 1pt cell taken to the 25% scale floor was baked as 0.2pt and\n * `clampFontSizeSz` then warned that \"fontSize 0.2 is outside the valid range\" -- a value the\n * caller never stated and cannot act on. Their input was valid; only our scaling was out of range.\n */\nexport function scaleCellFontSizes(cell: TableCellInternal, eff: RunOpts, f: number): void {\n\t// floor: stay on the conservative (smaller) side, then lift to the smallest size a run can carry\n\tconst shrink = (sizePt: number): number => Math.max(MIN_FONT_SIZE_PT, Math.floor(sizePt * f * 10) / 10)\n\tconst baseSize = Number(eff.fontSize ?? DEF_FONT_SIZE)\n\tcell.options = { ...cell.options, fontSize: shrink(baseSize) }\n\tif (Array.isArray(cell.text)) {\n\t\tcell.text = cell.text.map((run) =>\n\t\t\trun && typeof run === 'object' && typeof run.options?.fontSize === 'number'\n\t\t\t\t? { ...run, options: { ...run.options, fontSize: shrink(run.options.fontSize) } }\n\t\t\t\t: run\n\t\t)\n\t}\n}\n\n/**\n * The options {@link resolveTableGridEmu} reads.\n *\n * `cy` is on `ObjectOptions` rather than `TableProps` — it is the already-resolved EMU height\n * the auto-pager and the measured-fit pass stamp on — so the parameter is the intersection\n * rather than either type, and every caller's own bag satisfies it structurally.\n */\ntype TableGridOpts = Pick<TableProps, 'w' | 'h' | 'colW' | 'rowH'> & { cy?: Coord }\n\n/** A table's resolved grid: how many columns, how wide each is, and how tall each row is. */\ninterface TableGridEmu {\n\t/** Grid columns, counting colspans. */\n\tnumCols: number\n\t/** Per-column width in EMU, length {@link numCols}. */\n\tcolWidthsEmu: number[]\n\t/** The table's own height in EMU, or `0` when it has none and every row is auto-height. */\n\ttableHeightEmu: number\n\t/** One row's pinned height in EMU, or `null` when the row grows to fit its content. */\n\trowHeightEmu: (rowIndex: number) => number | null\n}\n\n/**\n * Resolve a table's grid the one way every consumer has to see it.\n *\n * Three sites derived these four things: `pptx.tableLayout()`, the export-time measured-fit\n * pass, and the table emitter (the height alone). They already disagreed — only the fit pass\n * read `cy`, the EMU height the auto-pager and the fit pass itself stamp onto the options, so\n * `addTable(rows, { cy })` with no `h` gave a file whose rows are pinned and a\n * `pptx.tableLayout()` that reported every row auto-height. That is the same drift the one\n * reading of `rowH` closed, arriving through a second option, which is why the answer is a\n * shared resolver rather than a third correction.\n *\n * `w` defaults to `75%` of the slide, matching what the emitter falls back to.\n * @param rows - the table's authored rows\n * @param opts - the table's options\n * @param presLayout - the presentation layout, for resolving percentages\n */\nexport function resolveTableGridEmu(\n\trows: TableCellInternal[][],\n\topts: TableGridOpts,\n\tpresLayout: PresLayout\n): TableGridEmu {\n\tconst numRows = rows.length\n\tconst numCols = tableColCount(rows)\n\tconst cxEmu =\n\t\topts.w != null ? getSmartParseNumber(opts.w, 'X', presLayout) : getSmartParseNumber('75%', 'X', presLayout)\n\t// `cy` is the already-resolved EMU height the auto-pager and `applyMeasuredFit` stamp on;\n\t// it is the table's height just as much as `h` is, and only one of the three readings had it.\n\tconst tableHeightEmu =\n\t\topts.h != null ? getSmartParseNumber(opts.h, 'Y', presLayout) : typeof opts.cy === 'number' ? opts.cy : 0\n\treturn {\n\t\tnumCols,\n\t\tcolWidthsEmu: resolveTableColWidthsEmu(opts.colW, cxEmu, numCols),\n\t\ttableHeightEmu,\n\t\trowHeightEmu: (rowIndex: number) => resolveTableRowHeightEmu(opts.rowH, rowIndex, tableHeightEmu, numRows),\n\t}\n}\n\n/**\n * Compute per-cell geometry (inches) for a table laid out at `opts.x`/`y`/`w` — the\n * engine behind `pptx.tableLayout()`. Column widths come from the same\n * {@link resolveTableColWidthsEmu} the writer uses, so cell x/width are exact. Row\n * heights are exact when pinned by `rowH` (array or scalar) or table `h`; otherwise\n * each auto-height row is estimated with the same conservative (tall) text model as\n * {@link measureText} and flagged `heightExact: false`. Single-slide only —\n * `autoPage` paging across slides is not modeled. Rowspan cells do not drive a row's\n * estimated height (mirrors `gen/table/autopage.ts`, which exempts them from line-height growth).\n */\nexport function computeTableLayout(\n\trows: TableCellInternal[][],\n\topts: TableProps,\n\tpresLayout: PresLayout,\n\tregistry: FontMetricsRegistry\n): TableLayoutResult {\n\tconst empty: TableLayoutResult = { cells: [], widthIn: 0, heightIn: 0, heightExact: true }\n\tif (!rows || rows.length === 0 || !rows[0]) return empty\n\tconst numRows = rows.length\n\tconst grid = resolveTableGridEmu(rows, opts, presLayout)\n\tconst numCols = grid.numCols\n\tif (!(numCols > 0)) return empty\n\t// Reuse TableProps as a bag of inheritable text props; only CELL_INHERITED_TEXT_KEYS are\n\t// read from it. Route through `unknown` because TableProps.columns (per-column cell\n\t// styling, TableCellProps[]) collides by name with TextPropsOptions.columns (text\n\t// column count, number) — the two never overlap here since `columns` isn't inherited.\n\tconst o = opts as unknown as RunOpts\n\n\tconst tableXEmu = opts.x != null ? getSmartParseNumber(opts.x, 'X', presLayout) : 0\n\tconst tableYEmu = opts.y != null ? getSmartParseNumber(opts.y, 'Y', presLayout) : 0\n\tconst colWidthsEmu = grid.colWidthsEmu\n\n\t// Prefix-sum column x offsets (length numCols+1): colXEmu[c] = left edge of column c.\n\tconst colXEmu = new Array<number>(numCols + 1).fill(0)\n\tfor (let c = 0; c < numCols; c++) colXEmu[c + 1] = (colXEmu[c] ?? 0) + (colWidthsEmu[c] ?? 0)\n\n\t// Explicit row height (EMU) or null when the row is auto-height — the same reading the writer\n\t// bakes and the export-time fit pass measures against.\n\tconst explicitRowHEmu = grid.rowHeightEmu\n\tconst resolve = makeRegistryResolver(registry)\n\tconst defLineEmu = autoPageLineHeightEmu(DEF_FONT_SIZE)\n\n\t// Estimate a cell's content height (EMU) at its authored size, conservative/tall,\n\t// with a one-line floor. Mirrors measureText's inflated wrap + height safety.\n\tconst estimateContentHeightEmu = (cell: TableCellInternal, eff: RunOpts, innerWidthPt: number): number => {\n\t\tconst fontSizePt = Number(eff.fontSize ?? DEF_FONT_SIZE) || DEF_FONT_SIZE\n\t\tconst oneLineEmu = autoPageLineHeightEmu(fontSizePt)\n\t\tif (!(innerWidthPt > 0)) return oneLineEmu\n\t\tconst paragraphs = extractParagraphs({ text: cell.text, options: eff })\n\t\tif (!paragraphs) return oneLineEmu\n\t\tconst layout = measureLayout(paragraphs, innerWidthPt, resolve, 100, 0, WIDTH_SAFETY_FACTOR)\n\t\tif (layout === null) return oneLineEmu\n\t\treturn Math.max(Math.round(layout.heightPt * HEIGHT_SAFETY_FACTOR * EMU_PER_POINT), oneLineEmu)\n\t}\n\n\t// PASS 1: place every origin cell and resolve each row's height.\n\tinterface Placed {\n\t\tp: GridPlacement\n\t\tcolStart: number\n\t\tcolEnd: number\n\t}\n\tconst placed: Placed[] = []\n\tconst rowHeightsEmu = new Array<number>(numRows).fill(0)\n\tconst rowExact = new Array<boolean>(numRows).fill(false)\n\tfor (let r = 0; r < numRows; r++) {\n\t\tconst ex = explicitRowHEmu(r)\n\t\tif (ex != null) {\n\t\t\trowHeightsEmu[r] = ex\n\t\t\trowExact[r] = true\n\t\t}\n\t}\n\n\tfor (const p of walkTableGrid(rows, numCols)) {\n\t\tconst colStart = p.col\n\t\tconst colEnd = p.col + p.colSpan\n\t\tplaced.push({ p, colStart, colEnd })\n\n\t\t// Only single-row, auto-height cells drive a row's estimated height.\n\t\tif (p.rowSpan === 1 && !rowExact[p.row]) {\n\t\t\tlet widthEmu = 0\n\t\t\tfor (let c = colStart; c < colEnd; c++) widthEmu += colWidthsEmu[c] ?? 0\n\t\t\tconst eff = effectiveCellOpts(p.cell?.options ?? {}, o)\n\t\t\tconst ins = resolveCellInsetsEmu(eff.margin)\n\t\t\tconst innerWidthPt = (widthEmu - ins.marL - ins.marR) / EMU_PER_POINT\n\t\t\tconst contentEmu = estimateContentHeightEmu(p.cell, eff, innerWidthPt) + ins.marT + ins.marB\n\t\t\tif (contentEmu > (rowHeightsEmu[p.row] ?? 0)) rowHeightsEmu[p.row] = contentEmu\n\t\t}\n\t}\n\n\t// A row touched only by rowspans (no single-row cell, no explicit height) still\n\t// needs a non-zero height: give it one default line. That height is this function's own\n\t// invention, so the row stops being exact — a caller told it was pinned would place the\n\t// next shape against a number nothing in the file agrees with.\n\tfor (let r = 0; r < numRows; r++)\n\t\tif ((rowHeightsEmu[r] ?? 0) <= 0) {\n\t\t\trowHeightsEmu[r] = defLineEmu\n\t\t\trowExact[r] = false\n\t\t}\n\n\t// Prefix-sum row y offsets.\n\tconst rowYEmu = new Array<number>(numRows + 1).fill(0)\n\tfor (let r = 0; r < numRows; r++) rowYEmu[r + 1] = (rowYEmu[r] ?? 0) + (rowHeightsEmu[r] ?? 0)\n\n\t// PASS 2: emit one rect per origin cell.\n\tconst cells: TableCellLayout[] = placed.map(({ p, colStart, colEnd }) => {\n\t\tconst rowEnd = p.row + p.rowSpan\n\t\tlet heightExact = true\n\t\tfor (let rr = p.row; rr < rowEnd; rr++) if (!rowExact[rr]) heightExact = false\n\t\treturn {\n\t\t\trow: p.row,\n\t\t\tcol: p.col,\n\t\t\trowSpan: p.rowSpan,\n\t\t\tcolSpan: p.colSpan,\n\t\t\txIn: emuToInches(tableXEmu + (colXEmu[colStart] ?? 0)),\n\t\t\tyIn: emuToInches(tableYEmu + (rowYEmu[p.row] ?? 0)),\n\t\t\twIn: emuToInches((colXEmu[colEnd] ?? 0) - (colXEmu[colStart] ?? 0)),\n\t\t\thIn: emuToInches((rowYEmu[rowEnd] ?? 0) - (rowYEmu[p.row] ?? 0)),\n\t\t\theightExact,\n\t\t}\n\t})\n\n\treturn {\n\t\tcells,\n\t\twidthIn: emuToInches(colXEmu[numCols] ?? 0),\n\t\theightIn: emuToInches(rowYEmu[numRows] ?? 0),\n\t\theightExact: rowExact.every(Boolean),\n\t}\n}\n","/**\n * pptx-ts: Measured-fit serialization pass\n *\n * Bridges slide text objects to the line-break simulator / shrink solver\n * (`text-fit.ts`). Runs during async export, BEFORE the `gen/` emitter builds the body:\n * for each text box with `fit: 'shrink'` and a registered font, it computes the\n * `fontScale` PowerPoint would have baked and rewrites `options.fit` to the\n * explicit object form (`{ type:'shrink', fontScale }`) so `genXmlNormAutofit`\n * emits `<a:normAutofit fontScale=…/>`. Without metrics it leaves the bare flag\n * untouched (current behavior) and warns once. The rewrite lasts one write: the pass hands back\n * the step that puts the authored values back. See `docs/contributing/design/text-fit.md`.\n */\n\nimport { SlideObjectType } from '../enums.js'\nimport { EMU_PER_POINT, POINTS_PER_INCH } from '../units.js'\nimport { getSmartParseNumber } from '../units-internal.js'\nimport { warn } from '../diagnostics.js'\nimport { InvalidOptionError } from '../errors.js'\nimport { collectUncoveredCodepoints, makeRegistryResolver, type FontMetricsRegistry } from './font-metrics.js'\nimport {\n\tsolveShrink,\n\tsolveResize,\n\tmeasureLayout,\n\tWIDTH_SAFETY_FACTOR,\n\tHEIGHT_SAFETY_FACTOR,\n\ttype FitBox,\n\ttype FitParagraph,\n} from './text-fit.js'\nimport {\n\tanchorTopShareOfDelta,\n\tbuildFitParagraphs,\n\tcomputeBox,\n\textractParagraphs,\n\tresolveBodyInsetsEmu,\n\ttype RunOpts,\n} from './paragraphs.js'\nimport { walkTableGrid } from '../gen/table/grid.js'\nimport { effectiveCellOpts, resolveCellInsetsEmu, resolveTableGridEmu, scaleCellFontSizes } from './table-fit.js'\nimport type { MeasureTextOptions, TextFitShrinkProps, TextMeasurement, TextProps } from '../types/index.js'\nimport type { SlideObject, PresSlideInternal } from '../types/internal.js'\nimport { pickDefined } from '../options-internal.js'\n\n/** Map the public {@link MeasureTextOptions} onto the internal run-option shape. */\nfunction measureOptsToRunOpts(opts: MeasureTextOptions): RunOpts {\n\treturn pickDefined(opts, [\n\t\t'fontSize',\n\t\t'fontFace',\n\t\t'bold',\n\t\t'italic',\n\t\t'charSpacing',\n\t\t'lineSpacing',\n\t\t'lineSpacingMultiple',\n\t\t'paraSpaceBefore',\n\t\t'paraSpaceAfter',\n\t])\n}\n\n/** A fresh result each call: the arrays are caller-owned, so they cannot be shared. */\nconst unmeasurable = (): TextMeasurement => ({\n\theightIn: 0,\n\tlineCount: 0,\n\twidestLineIn: 0,\n\tmeasurable: false,\n\tapproximatedFaces: [],\n\tuncoveredCodepoints: [],\n\tfitsBox: () => false,\n\tshrinkScaleFor: () => 100,\n})\n\n/** Flatten a face → uncovered-code-point map into one sorted, deduplicated list. */\nfunction flattenCodepoints(byFace: Map<string, Set<number>>): number[] {\n\tconst all = new Set<number>()\n\tfor (const cps of byFace.values()) for (const cp of cps) all.add(cp)\n\treturn [...all].sort((a, b) => a - b)\n}\n\n/**\n * Render uncovered code points for a warning as `U+XXXX`, capped so one bad run cannot\n * flood the console with a whole unsupported script.\n */\nfunction formatCodepoints(cps: Set<number>): string {\n\tconst all = [...cps].sort((a, b) => a - b)\n\tconst shown = all.slice(0, 8).map((cp) => `U+${cp.toString(16).toUpperCase().padStart(4, '0')}`)\n\treturn all.length > shown.length ? `${shown.join(' ')} +${all.length - shown.length} more` : shown.join(' ')\n}\n\n/**\n * Layout-time text measurement against registered metrics — the public engine\n * behind `pptx.measureText()`. Uses the **same** calibrated wrap model, resolver\n * semantics, and conservative safety factors as the export-time bake\n * (`applyMeasuredFit` / {@link solveResize} / {@link solveShrink}), so a\n * layout-time prediction matches the value the export would bake **for any deck\n * that opted into measured fit (i.e. registered at least one face)**.\n *\n * With an **empty** registry the two intentionally diverge: `applyMeasuredFit`\n * treats \"no metrics\" as \"not opted in\" and bakes nothing, while this returns\n * heuristic numbers so the API is useful with zero setup. Check\n * `approximatedFaces` if that distinction matters.\n *\n * Synchronous: assumes metrics are pre-registered (lookup is sync). A named face\n * with no exact metrics silently uses the conservative heuristic (same as export)\n * and is reported in `approximatedFaces`; an unnamed theme-default face returns\n * `measurable: false`. Code points a *registered* face has no glyph for are reported\n * in `uncoveredCodepoints`, and are the one case where the height may come back short\n * rather than tall — there is no font fallback here, only the font's `.notdef` advance.\n */\nexport function measureText(\n\tregistry: FontMetricsRegistry,\n\ttext: string | TextProps[],\n\topts: MeasureTextOptions\n): TextMeasurement {\n\t// The box is checked before the text. A `NaN` or missing width passed every comparison the\n\t// layout makes as false, so each word went on a line of its own and the result read as\n\t// measurable; a width inside the insets came back unmeasurable with no reason given.\n\tconst inset = opts.insetIn ?? 0\n\trequireFiniteInches(opts.wIn, 'wIn', 'measureText')\n\trequireFiniteInches(inset, 'insetIn', 'measureText')\n\t// A size that is not a positive number fell back to the default size, and the measurement read as\n\t// the caller's own.\n\tif (opts.fontSize !== undefined && !(Number.isFinite(opts.fontSize) && opts.fontSize > 0))\n\t\tthrow new InvalidOptionError(\n\t\t\t'font/size-not-positive',\n\t\t\t`measureText: \\`fontSize\\` must be a positive number of points, got ${String(opts.fontSize)}.`\n\t\t)\n\tif (!(opts.wIn > 2 * inset))\n\t\tthrow new InvalidOptionError(\n\t\t\t'coord/not-positive',\n\t\t\t`measureText: \\`wIn\\` ${opts.wIn} leaves no width inside an inset of ${inset} on each side.`\n\t\t)\n\n\tconst runs: TextProps[] =\n\t\ttypeof text === 'string' || typeof text === 'number' ? [{ text: String(text) }] : Array.isArray(text) ? text : []\n\tconst paragraphs = buildFitParagraphs(runs, measureOptsToRunOpts(opts))\n\tif (!paragraphs) return unmeasurable()\n\n\tconst innerWidthPt = (opts.wIn - 2 * inset) * POINTS_PER_INCH\n\tconst heuristicFaces = new Set<string>()\n\tconst resolve = makeRegistryResolver(registry, (face) => heuristicFaces.add(face))\n\n\t// Coverage is a property of the runs, not of the layout, so it is audited up front —\n\t// which also keeps it out of the resolver that `shrinkScaleFor()` re-enters.\n\tconst uncoveredByFace = new Map<string, Set<number>>()\n\tcollectUncoveredCodepoints(paragraphs, registry, uncoveredByFace)\n\n\t// Conservative (tall) layout at full size, mirroring solveResize: inflate width\n\t// (earlier wrap) by WIDTH_SAFETY and the height by HEIGHT_SAFETY. The resolver runs\n\t// during layout, so `heuristicFaces` is only populated once this returns.\n\tconst layout = measureLayout(paragraphs, innerWidthPt, resolve, 100, 0, WIDTH_SAFETY_FACTOR)\n\tif (layout === null) return unmeasurable()\n\tconst heightPt = layout.heightPt * HEIGHT_SAFETY_FACTOR\n\tconst heightIn = heightPt / POINTS_PER_INCH\n\n\treturn {\n\t\theightIn,\n\t\tlineCount: layout.lineCount,\n\t\twidestLineIn: layout.widestLineWidthPt / POINTS_PER_INCH,\n\t\tmeasurable: true,\n\t\t// Snapshot: shrinkScaleFor() re-enters the same resolver, so the live set must not leak.\n\t\tapproximatedFaces: [...heuristicFaces],\n\t\tuncoveredCodepoints: flattenCodepoints(uncoveredByFace),\n\t\t// Mirrors solveShrink's fit check at scale 100 (height already inflated).\n\t\tfitsBox: (hIn: number) => {\n\t\t\trequireBoxHeight(hIn, 'fitsBox')\n\t\t\treturn heightPt <= hIn * POINTS_PER_INCH\n\t\t},\n\t\tshrinkScaleFor: (hIn: number) => {\n\t\t\trequireBoxHeight(hIn, 'shrinkScaleFor')\n\t\t\tconst box: FitBox = { innerWidthPt, innerHeightPt: hIn * POINTS_PER_INCH }\n\t\t\tconst outcome = solveShrink(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'shrink') return outcome.result.fontScalePct\n\t\t\treturn 100 // 'fits' (or, defensively, 'unmeasurable') → no shrink\n\t\t},\n\t}\n}\n\n/** Refuse a measure that is not a finite number of inches, naming the option and the call. */\nfunction requireFiniteInches(value: unknown, name: string, call: string): void {\n\tif (typeof value !== 'number' || !Number.isFinite(value))\n\t\tthrow new InvalidOptionError(\n\t\t\t'coord/non-finite',\n\t\t\t`${call}: \\`${name}\\` must be a finite number of inches; got ${String(value)}.`\n\t\t)\n}\n\n/**\n * Refuse a box height a fit cannot be tested against: not a finite number, or not above 0. A `NaN`\n * height made `fitsBox` answer `false` and `shrinkScaleFor` answer `100`, both as if measured.\n * @param hIn - the caller's inner box height, in inches\n * @param call - the method it was passed to, opening the message\n */\nexport function requireBoxHeight(hIn: unknown, call: string): void {\n\trequireFiniteInches(hIn, 'hIn', call)\n\tif (!((hIn as number) > 0))\n\t\tthrow new InvalidOptionError('coord/not-positive', `${call}: \\`hIn\\` must be greater than 0; got ${String(hIn)}.`)\n}\n\n/**\n * Apply measured fit across every slide. For each text box that opts in via\n * `fit:'shrink'` or `fit:'resize'` and whose font has registered metrics, this\n * bakes the computed result before the sync XML pass reads it:\n * - `'shrink'` → rewrites `options.fit` to the object form so `<a:normAutofit\n * fontScale=…/>` is emitted (text renders pre-shrunk).\n * - `'resize'` → rewrites `options.h` (and `options.y` per vertical anchor) so the\n * shape's `a:ext/@cy` is the height the text needs; the `<a:spAutoFit/>` marker is\n * left in place (the renderer draws the baked `cy`).\n *\n * Safe to call with an empty registry (no-op). Warns once if any opted-in box could\n * not be measured (missing metrics), and once if one held code points its registered\n * face has no glyph for, so neither kind of overflow is silently ignored.\n *\n * Every rewrite lands on the stored slide model, because that is what the emitters read.\n * The returned function puts each authored value back; call it once the XML is built. Left\n * baked, a second write found a text box's object-form `fit` and skipped it, and measured a\n * resized box or a shrunk cell from this write's result, so metrics registered in between\n * never reached those shapes.\n * @returns the step that restores every value this pass rewrote\n */\nexport function applyMeasuredFit(slides: PresSlideInternal[], registry: FontMetricsRegistry): () => void {\n\tconst restores: Array<() => void> = []\n\tconst restore = (): void => {\n\t\tfor (const undo of restores.splice(0).reverse()) undo()\n\t}\n\tif (registry.size === 0) return restore\n\n\t// A deck that registered *some* metrics has opted into measured fit, so a named\n\t// face we have no exact metrics for falls back to the conservative heuristic rather\n\t// than degrading to the bare flag — overflow still self-corrects, just less precisely.\n\t// An unnamed (theme-default) face stays unmeasurable: we cannot guess which face it is.\n\tconst heuristicFaces = new Set<string>()\n\tconst resolve = makeRegistryResolver(registry, (face) => heuristicFaces.add(face))\n\tconst unmeasuredShrink = new Set<string>()\n\tconst unmeasuredResize = new Set<string>()\n\tconst uncoveredByFace = new Map<string, Set<number>>()\n\n\tconst collectUnmeasured = (paragraphs: FitParagraph[], into: Set<string>): void => {\n\t\tfor (const para of paragraphs)\n\t\t\tfor (const run of para.runs) if (!resolve(run)) into.add(run.fontFace ?? '(theme default)')\n\t}\n\n\t/** Audit every set of runs the pass is about to measure — see the warning below. */\n\tconst auditCoverage = (paragraphs: FitParagraph[]): void =>\n\t\tcollectUncoveredCodepoints(paragraphs, registry, uncoveredByFace)\n\n\t/**\n\t * Bake measured shrink into a table's cells. Walks the cell grid (accounting for\n\t * colspan/rowspan) to size each cell's box from its column widths and row heights,\n\t * then lowers the run font sizes of any `fit:'shrink'` cell that overflows. Cells\n\t * in auto-height rows (no fixed `rowH`/table `h`) are skipped — the row grows instead.\n\t */\n\tconst measureTableCells = (tableObj: SlideObject, layout: PresSlideInternal['_presLayout']): void => {\n\t\tconst rows = tableObj.arrTabRows\n\t\tif (!rows || rows.length === 0 || !rows[0]) return\n\t\tconst tableOpts = (tableObj.options ?? {}) as RunOpts\n\t\tconst { numCols, colWidthsEmu, rowHeightEmu: pinnedRowHeightEmu } = resolveTableGridEmu(rows, tableOpts, layout)\n\t\tif (!(numCols > 0)) return\n\t\t// `null` is an auto-height row — it grows to fit, so there is nothing to shrink into.\n\t\tconst rowHeightEmu = (rIdx: number): number => pinnedRowHeightEmu(rIdx) ?? 0\n\n\t\tfor (const { cell, row: r, col: colStart, colSpan, rowSpan } of walkTableGrid(rows, numCols)) {\n\t\t\tconst colEnd = colStart + colSpan\n\t\t\tconst cellOpts = cell?.options ?? {}\n\t\t\tconst fit = cellOpts.fit ?? (tableOpts.fit === 'shrink' ? 'shrink' : undefined)\n\t\t\tif (fit !== 'shrink') continue\n\n\t\t\tlet widthEmu = 0\n\t\t\tfor (let c = colStart; c < colEnd; c++) widthEmu += colWidthsEmu[c] ?? 0\n\t\t\tlet heightEmu = 0\n\t\t\tlet autoHeight = false\n\t\t\tfor (let rr = r; rr < r + rowSpan; rr++) {\n\t\t\t\tconst h = rowHeightEmu(rr)\n\t\t\t\tif (h <= 0) {\n\t\t\t\t\tautoHeight = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\theightEmu += h\n\t\t\t}\n\t\t\tif (autoHeight) continue\n\n\t\t\tconst eff = effectiveCellOpts(cellOpts, tableOpts)\n\t\t\tconst ins = resolveCellInsetsEmu(eff.margin)\n\t\t\tconst innerWidthPt = (widthEmu - ins.marL - ins.marR) / EMU_PER_POINT\n\t\t\tconst innerHeightPt = (heightEmu - ins.marT - ins.marB) / EMU_PER_POINT\n\t\t\tif (!(innerWidthPt > 0) || !(innerHeightPt > 0)) continue\n\n\t\t\tconst paragraphs = extractParagraphs({ text: cell.text, options: eff })\n\t\t\tif (!paragraphs) continue\n\t\t\tauditCoverage(paragraphs)\n\t\t\tconst box: FitBox = { innerWidthPt, innerHeightPt }\n\t\t\tconst outcome = solveShrink(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'shrink') {\n\t\t\t\tconst f = outcome.result.fontScalePct / 100\n\t\t\t\tif (f < 1) {\n\t\t\t\t\trestores.push(restorer(cell, 'options'), restorer(cell, 'text'))\n\t\t\t\t\tscaleCellFontSizes(cell, eff, f)\n\t\t\t\t}\n\t\t\t} else if (outcome.kind === 'unmeasurable') {\n\t\t\t\tcollectUnmeasured(paragraphs, unmeasuredShrink)\n\t\t\t}\n\t\t\t// 'fits' → leave the authored size; the text already fits.\n\t\t}\n\t}\n\n\tconst measureObject = (obj: SlideObject, layout: PresSlideInternal['_presLayout']): void => {\n\t\t// Groups keep their children outside slide._slideObjects. Descend through every\n\t\t// nesting level so grouping remains a visual/editability operation and does not\n\t\t// disable the export-time fit pass for contained text.\n\t\tif (obj._type === SlideObjectType.group) {\n\t\t\tfor (const child of obj._groupObjects ?? []) measureObject(child, layout)\n\t\t\treturn\n\t\t}\n\t\tif (obj._type === SlideObjectType.table) {\n\t\t\tmeasureTableCells(obj, layout)\n\t\t\treturn\n\t\t}\n\t\tif (obj._type !== SlideObjectType.text) return\n\t\t// Only the bare string forms opt into measurement; an explicit object form is\n\t\t// already baked by the caller, and 'none' is a no-op.\n\t\tconst options = obj.options\n\t\tif (!options) return\n\t\tconst fit = options.fit\n\t\tif (fit !== 'shrink' && fit !== 'resize') return\n\n\t\tconst paragraphs = extractParagraphs(obj)\n\t\tif (!paragraphs) return\n\t\tauditCoverage(paragraphs)\n\t\tconst box = computeBox(obj, layout)\n\t\tif (!box) return\n\n\t\tif (fit === 'shrink') {\n\t\t\tconst outcome = solveShrink(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'shrink') {\n\t\t\t\tconst { fontScalePct, lnSpcReductionPct } = outcome.result\n\t\t\t\t// `lnSpcReduction` is written only when the solver reduced line spacing: `options.fit`\n\t\t\t\t// lands on a slide object's options, which the emitters spread, and `<a:normAutofit>`\n\t\t\t\t// omits the attribute for an absent one.\n\t\t\t\tconst shrink: TextFitShrinkProps = { type: 'shrink', fontScale: fontScalePct }\n\t\t\t\tif (lnSpcReductionPct) shrink.lnSpcReduction = lnSpcReductionPct\n\t\t\t\trestores.push(restorer(options, 'fit'))\n\t\t\t\toptions.fit = shrink\n\t\t\t} else if (outcome.kind === 'unmeasurable') {\n\t\t\t\tcollectUnmeasured(paragraphs, unmeasuredShrink)\n\t\t\t}\n\t\t\t// 'fits' → leave the bare flag; the text already fits, so no scale is needed.\n\t\t} else {\n\t\t\tconst outcome = solveResize(paragraphs, box, resolve)\n\t\t\tif (outcome.kind === 'resize') {\n\t\t\t\tconst opts = obj.options as RunOpts\n\t\t\t\tconst { tIns, bIns } = resolveBodyInsetsEmu(opts)\n\t\t\t\tconst oldHeightEmu = getSmartParseNumber(opts.h, 'Y', layout)\n\t\t\t\tconst newHeightEmu = Math.round(outcome.neededInnerHeightPt * EMU_PER_POINT) + tIns + bIns\n\t\t\t\t// Shift the box origin so growth/shrink honors the vertical anchor; `off.y`\n\t\t\t\t// moves up by the anchor's share of the height delta (0 / half / full for t / ctr / b).\n\t\t\t\tconst oldYEmu = getSmartParseNumber(opts.y, 'Y', layout)\n\t\t\t\tconst shiftEmu = Math.round((newHeightEmu - oldHeightEmu) * anchorTopShareOfDelta(opts))\n\t\t\t\trestores.push(restorer(opts, 'h'), restorer(opts, 'y'))\n\t\t\t\topts.h = `${newHeightEmu}emu`\n\t\t\t\tif (shiftEmu !== 0) opts.y = `${oldYEmu - shiftEmu}emu`\n\t\t\t} else {\n\t\t\t\tcollectUnmeasured(paragraphs, unmeasuredResize)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const slide of slides) {\n\t\tfor (const obj of slide._slideObjects ?? []) measureObject(obj, slide._presLayout)\n\t}\n\n\tif (unmeasuredShrink.size > 0) {\n\t\twarn(\n\t\t\t'measure/shrink-unmeasured',\n\t\t\t`fit:'shrink' could not be measured for font(s) [${[...unmeasuredShrink].join(', ')}] — ` +\n\t\t\t\t'no registered metrics. Emitting bare <a:normAutofit/> (text will not pre-shrink in headless renders). ' +\n\t\t\t\t'Call pptx.registerFontMetrics(face, fontFilePathOrBytes) to enable measured fit.'\n\t\t)\n\t}\n\tif (unmeasuredResize.size > 0) {\n\t\twarn(\n\t\t\t'measure/resize-unmeasured',\n\t\t\t`fit:'resize' could not be measured for font(s) [${[...unmeasuredResize].join(', ')}] — ` +\n\t\t\t\t'no registered metrics. Emitting bare <a:spAutoFit/> with the authored height (box will not auto-grow in headless renders). ' +\n\t\t\t\t'Call pptx.registerFontMetrics(face, fontFilePathOrBytes) to enable measured fit.'\n\t\t)\n\t}\n\tif (uncoveredByFace.size > 0) {\n\t\tconst perFace = [...uncoveredByFace].map(([face, cps]) => `${face} → ${formatCodepoints(cps)}`).join('; ')\n\t\twarn(\n\t\t\t'measure/uncovered-codepoints',\n\t\t\t`Measured fit charged the .notdef advance for code point(s) the registered face does not cover (${perFace}) — ` +\n\t\t\t\t'PowerPoint renders those from a substituted font, so the measured width can be wrong in EITHER direction. ' +\n\t\t\t\t'Too narrow drops a line and the text overflows the baked size, the one case measured fit does not err safe. ' +\n\t\t\t\t'Register a face that covers them, or set an explicit fontFace on those runs.'\n\t\t)\n\t}\n\tif (heuristicFaces.size > 0) {\n\t\twarn(\n\t\t\t'measure/heuristic-metrics',\n\t\t\t`Note: measured fit used a conservative average-advance estimate for font(s) [${[...heuristicFaces].join(', ')}] — ` +\n\t\t\t\t'no exact metrics registered. Fit is approximate (may shrink/grow more than necessary). ' +\n\t\t\t\t'Call pptx.registerFontMetrics(face, fontFilePathOrBytes) for an exact fit.'\n\t\t)\n\t}\n\treturn restore\n}\n\n/**\n * The step that puts `target[key]` back as it stands now, an absent key included, so a restored\n * option bag is the authored one rather than one holding an `undefined` the caller never wrote.\n */\nfunction restorer<T extends object>(target: T, key: keyof T): () => void {\n\tconst had = Object.hasOwn(target, key)\n\tconst value = target[key]\n\treturn () => {\n\t\tif (had) target[key] = value\n\t\telse delete (target as Record<PropertyKey, unknown>)[key]\n\t}\n}\n"],"mappings":"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"}
|