@shbernal/ts-pptx 4.1.0 → 4.2.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 +11 -11
- package/dist/anim-presets-Qbgh8uut.js +55 -0
- package/dist/anim-presets-Qbgh8uut.js.map +1 -0
- package/dist/{autopage-D4kyVp11.js → autopage-DqZ37VpL.js} +11 -12
- package/dist/autopage-DqZ37VpL.js.map +1 -0
- package/dist/{binary-string-CKVAYI3M.js → binary-string-Ba8VM3b9.js} +3 -4
- package/dist/binary-string-Ba8VM3b9.js.map +1 -0
- package/dist/{body-insets-kVHmjGc6.js → body-insets-BDHymJvz.js} +7 -9
- package/dist/body-insets-BDHymJvz.js.map +1 -0
- package/dist/browser.d.ts +24 -16
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +19 -19
- package/dist/browser.js.map +1 -1
- package/dist/{image-size-DwDbakcl.js → chart-metadata-CwiTTcJq.js} +576 -538
- package/dist/chart-metadata-CwiTTcJq.js.map +1 -0
- package/dist/{clip-DHDlnHUq.d.ts → clip-ISfCMtWA.d.ts} +6 -10
- package/dist/clip-ISfCMtWA.d.ts.map +1 -0
- package/dist/{notes-BcT571R4.js → comments-CKIZYRbZ.js} +517 -389
- package/dist/comments-CKIZYRbZ.js.map +1 -0
- package/dist/{diagnostics-DiMmBU8P.d.ts → diagnostics-MoA4MBq5.d.ts} +52 -50
- package/dist/diagnostics-MoA4MBq5.d.ts.map +1 -0
- package/dist/{embedded-fonts-CI_YGW2d.d.ts → embedded-fonts-U7HIIhPO.d.ts} +4 -6
- package/dist/embedded-fonts-U7HIIhPO.d.ts.map +1 -0
- package/dist/{entry-compose-6hF9aTmT.d.ts → entry-compose-CiakSt-f.d.ts} +53 -74
- package/dist/entry-compose-CiakSt-f.d.ts.map +1 -0
- package/dist/{errors-Da2nXCJm.js → entry-errors-JMthgJ2g.js} +41 -25
- package/dist/entry-errors-JMthgJ2g.js.map +1 -0
- package/dist/{table-cell-margins-PDshga8T.js → enums-BP9wsb9Q.js} +42 -45
- package/dist/enums-BP9wsb9Q.js.map +1 -0
- package/dist/{enums-DQRpVOLh.d.ts → enums-PcXr3o3J.d.ts} +11 -12
- package/dist/{enums-DQRpVOLh.d.ts.map → enums-PcXr3o3J.d.ts.map} +1 -1
- package/dist/families.d.ts +24 -26
- package/dist/families.d.ts.map +1 -1
- package/dist/families.js +3 -4
- package/dist/{fit-CcXbg__l.js → fit-Bpmzep6O.js} +60 -52
- package/dist/fit-Bpmzep6O.js.map +1 -0
- package/dist/{font-metrics-CBGmhLo0.d.ts → font-metrics-DTppw4t3.d.ts} +61 -37
- package/dist/font-metrics-DTppw4t3.d.ts.map +1 -0
- package/dist/{grid-9B2w5EaY.js → grid-DUIMxjfl.js} +23 -26
- package/dist/grid-DUIMxjfl.js.map +1 -0
- package/dist/{html-dom-DvJmuHt2.js → html-dom-LZCgntnJ.js} +42 -43
- package/dist/html-dom-LZCgntnJ.js.map +1 -0
- package/dist/html.d.ts +53 -9
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +12 -13
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +21 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -15
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +14 -16
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +18 -19
- package/dist/inspect.js.map +1 -1
- package/dist/{text-anchor-BgLPbwbL.js → lock-attrs-CSQnFDHP.js} +62 -12
- package/dist/lock-attrs-CSQnFDHP.js.map +1 -0
- package/dist/math.d.ts +2 -4
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +12 -13
- package/dist/math.js.map +1 -1
- package/dist/measure.d.ts +23 -12
- package/dist/measure.d.ts.map +1 -1
- package/dist/measure.js +3 -3
- package/dist/node.d.ts +21 -13
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +12 -12
- package/dist/node.js.map +1 -1
- package/dist/{options-internal-WqgMf720.js → options-internal-BWgmLPdx.js} +4 -5
- package/dist/options-internal-BWgmLPdx.js.map +1 -0
- package/dist/{package-KoEgVwII.d.ts → package-CANBWuSm.d.ts} +4 -12
- package/dist/package-CANBWuSm.d.ts.map +1 -0
- package/dist/{playbtn-CUqQdoDf.js → playbtn-BQZFJir9.js} +4 -5
- package/dist/playbtn-BQZFJir9.js.map +1 -0
- package/dist/{pres-BA9_lJbY.d.ts → pres-BkEkUAEM.d.ts} +383 -230
- package/dist/pres-BkEkUAEM.d.ts.map +1 -0
- package/dist/{presentation-Cyl74rq2.js → presentation-4Ggq0_Xa.js} +408 -288
- package/dist/presentation-4Ggq0_Xa.js.map +1 -0
- package/dist/{presentation-types-B3VQH4Bz.d.ts → presentation-types-BgnZR-0a.d.ts} +1104 -457
- package/dist/presentation-types-BgnZR-0a.d.ts.map +1 -0
- package/dist/read.d.ts +18 -13
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +4 -4
- package/dist/script.d.ts +116 -65
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +2697 -777
- package/dist/script.js.map +1 -1
- package/dist/{shapes-BcyFdZpp.js → shapes-CAPOjU0Q.js} +1556 -487
- package/dist/shapes-CAPOjU0Q.js.map +1 -0
- package/dist/{slide-BqPtyKmb.d.ts → slide-BmT4kMoO.d.ts} +94 -86
- package/dist/slide-BmT4kMoO.d.ts.map +1 -0
- package/dist/{slide-size-BalTjFuv.js → slide-size-SkScz1ig.js} +2 -3
- package/dist/{slide-size-BalTjFuv.js.map → slide-size-SkScz1ig.js.map} +1 -1
- package/dist/{table-dom-CVbvUfgh.js → table-dom-BYga4FYY.js} +3 -4
- package/dist/{table-dom-CVbvUfgh.js.map → table-dom-BYga4FYY.js.map} +1 -1
- package/dist/{text-BvFFMMFQ.js → text-CU08xJGs.js} +365 -318
- package/dist/text-CU08xJGs.js.map +1 -0
- package/dist/{transition-speed-kUEWDWTx.js → transition-speed-CNJ0fSpQ.js} +2 -3
- package/dist/{transition-speed-kUEWDWTx.js.map → transition-speed-CNJ0fSpQ.js.map} +1 -1
- package/dist/{units-internal-DFcUYjh3.js → units-internal-BR3a4cIi.js} +26 -29
- package/dist/units-internal-BR3a4cIi.js.map +1 -0
- package/dist/{zip-CYZ0F6BV.js → zip-7JTh61LX.js} +8 -10
- package/dist/zip-7JTh61LX.js.map +1 -0
- package/dist/{zip-CTll_dr0.d.ts → zip-uUjs9Cqx.d.ts} +4 -6
- package/dist/zip-uUjs9Cqx.d.ts.map +1 -0
- package/dist/zip.d.ts +3 -3
- package/dist/zip.js +3 -3
- package/dist/{zoom-BoNyOlPm.js → zoom-CSSeOwM8.js} +1153 -583
- package/dist/zoom-CSSeOwM8.js.map +1 -0
- package/package.json +20 -21
- package/skills/{ts-pptx-upstream → pptx-ts-upstream}/SKILL.md +27 -74
- package/dist/autopage-D4kyVp11.js.map +0 -1
- package/dist/binary-string-CKVAYI3M.js.map +0 -1
- package/dist/body-insets-kVHmjGc6.js.map +0 -1
- package/dist/clip-DHDlnHUq.d.ts.map +0 -1
- package/dist/diagnostics-DiMmBU8P.d.ts.map +0 -1
- package/dist/embedded-fonts-CI_YGW2d.d.ts.map +0 -1
- package/dist/entry-compose-6hF9aTmT.d.ts.map +0 -1
- package/dist/errors-Da2nXCJm.js.map +0 -1
- package/dist/fit-CcXbg__l.js.map +0 -1
- package/dist/font-metrics-CBGmhLo0.d.ts.map +0 -1
- package/dist/grid-9B2w5EaY.js.map +0 -1
- package/dist/html-dom-DvJmuHt2.js.map +0 -1
- package/dist/image-size-DwDbakcl.js.map +0 -1
- package/dist/notes-BcT571R4.js.map +0 -1
- package/dist/options-internal-WqgMf720.js.map +0 -1
- package/dist/package-KoEgVwII.d.ts.map +0 -1
- package/dist/playbtn-CUqQdoDf.js.map +0 -1
- package/dist/pres-BA9_lJbY.d.ts.map +0 -1
- package/dist/presentation-Cyl74rq2.js.map +0 -1
- package/dist/presentation-types-B3VQH4Bz.d.ts.map +0 -1
- package/dist/shapes-BcyFdZpp.js.map +0 -1
- package/dist/slide-BqPtyKmb.d.ts.map +0 -1
- package/dist/table-cell-margins-PDshga8T.js.map +0 -1
- package/dist/text-BvFFMMFQ.js.map +0 -1
- package/dist/text-anchor-BgLPbwbL.js.map +0 -1
- package/dist/units-internal-DFcUYjh3.js.map +0 -1
- package/dist/zip-CTll_dr0.d.ts.map +0 -1
- package/dist/zip-CYZ0F6BV.js.map +0 -1
- package/dist/zoom-BoNyOlPm.js.map +0 -1
package/dist/fit-CcXbg__l.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"font-metrics-CBGmhLo0.d.ts","names":[],"sources":["../src/types/internal.ts","../src/measure/text-fit.ts","../src/measure/font-metrics.ts"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"grid-9B2w5EaY.js","names":[],"sources":["../src/gen/table/spans.ts","../src/gen/table/grid.ts"],"sourcesContent":["/**\n * pptx-ts: table `colspan`/`rowspan` range checking.\n *\n * The spans decide two allocations, on two different paths, and both used to trust the caller:\n * the merge grid's `new Array(colspan - 1)` in `gen/slide/objects/table.ts`, and the auto-pager's\n * per-column depth array, sized from a column count that is a sum of colspans\n * (`gen/table/autopage.ts`). `new Array(4294967294).fill(undefined)` is not a slow path — V8\n * aborts on the allocation and there is no exception to catch — so a table built with\n * `autoPage: true` and one without needed the same guard, which is why it lives here rather than\n * in either of them.\n *\n * This is the write side, so the bad number comes from the calling program rather than from a\n * hostile file, which makes it far less serious than the read-side twin in the chart point caches\n * (`read/oxml/point-cache.ts`, the model this copies). It is still the project's stated line: warn\n * on out-of-range input rather than emit a degenerate result.\n */\n\nimport type { TableCellInternal } from '../../types/internal.js'\nimport { warn } from '../../diagnostics.js'\n\n/**\n * The largest `colspan`/`rowspan` this library will honour.\n *\n * Unlike the read side's point-cache ceiling there is no format number to borrow: `a:tc@gridSpan`\n * is a bare `xsd:int`. So this is a sanity bound rather than a schema one, and it is set an order\n * of magnitude past PowerPoint's own maximum table (its Insert Table dialog stops at 75 columns\n * and 75 rows), which is what makes it something no authored table can reach. What it stops is\n * the other end, where the allocation takes the host process with it.\n */\nexport const MAX_TABLE_SPAN = 1000\n\n/**\n * Validate one cell's `colspan`/`rowspan`, warning and falling back to `1` when it is not a whole\n * number in `1..MAX_TABLE_SPAN`.\n *\n * `undefined` is the common case and means \"no span\" — it warns about nothing and returns `1`.\n * Everything else is caller error: `NaN`, a negative, a fraction and a span past the ceiling all\n * describe a table that cannot be built (a fractional span silently truncates, a negative one\n * shifts every column after it, an enormous one is the allocation above).\n *\n * The parameter is typed `unknown` because this is also **the** reading of a span for the six\n * sites that consume one after {@link withCheckedSpans} has run. Those had six different\n * coercions — `Number(x) ? … : 1`, `Math.max(1, Number(x) || 1)`, `x ?? 1` — which agreed only\n * on the values that were already valid, and one of them let a non-numeric span reach a grid\n * column count as `NaN`. Reading a span through one function is what stops them drifting apart\n * again if the up-front check is ever moved.\n * @param value - the raw option value, as the caller wrote it\n * @param kind - `'colspan'` or `'rowspan'`, for the diagnostic\n * @returns the span to use, at least 1\n */\nexport function resolveSpan(value: unknown, kind: 'colspan' | 'rowspan'): number {\n\tif (value === undefined || value === null || value === '') return 1\n\tif (typeof value !== 'number') {\n\t\twarn(\n\t\t\t'table/span-out-of-range',\n\t\t\t`table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`\n\t\t)\n\t\treturn 1\n\t}\n\tif (!Number.isInteger(value) || value < 1 || value > MAX_TABLE_SPAN) {\n\t\twarn(\n\t\t\t'table/span-out-of-range',\n\t\t\t`table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`\n\t\t)\n\t\treturn 1\n\t}\n\treturn value\n}\n\n/**\n * Re-clone `rows` with every out-of-range `colspan`/`rowspan` corrected to `1`.\n *\n * Runs once, up front, so the column count, the `_hmerge`/`_vmerge` dummies, the auto-pager's\n * grid and the emitted `gridSpan`/`rowSpan` attributes all read the same number — checking at\n * each of those sites instead would warn several times per bad cell and could still disagree.\n *\n * A cell whose spans are fine is passed through by identity, not copied: `_spanOrigin` links the\n * merge dummies back to the origin *object*, and the all-valid path is every real table, which\n * must stay allocation-free and byte-identical.\n * @param rows - the rows to check; row arrays are never mutated\n * @returns the same rows with only the offending cells replaced\n */\nexport function withCheckedSpans(rows: TableCellInternal[][]): TableCellInternal[][] {\n\treturn rows.map((cells) =>\n\t\tcells.map((cell) => {\n\t\t\tconst opts = cell?.options\n\t\t\tif (!opts) return cell\n\t\t\tconst colspan = resolveSpan(opts.colspan, 'colspan')\n\t\t\tconst rowspan = resolveSpan(opts.rowspan, 'rowspan')\n\t\t\tconst colspanOk = opts.colspan === undefined || opts.colspan === colspan\n\t\t\tconst rowspanOk = opts.rowspan === undefined || opts.rowspan === rowspan\n\t\t\tif (colspanOk && rowspanOk) return cell\n\t\t\treturn {\n\t\t\t\t...cell,\n\t\t\t\toptions: {\n\t\t\t\t\t...opts,\n\t\t\t\t\t...(opts.colspan === undefined ? {} : { colspan }),\n\t\t\t\t\t...(opts.rowspan === undefined ? {} : { rowspan }),\n\t\t\t\t},\n\t\t\t}\n\t\t})\n\t)\n}\n\n/**\n * Whether any cell in the grid carries a hyperlink — on the cell itself, or on any run of a\n * cell whose `text` is a run array.\n *\n * `addTable` uses this to decide whether to stand its black text default down: the default is\n * direct formatting on the table, so it would paint the words *after* a link black rather than\n * letting them follow the link colour. The test used to be\n * `JSON.stringify({ arrRows }).includes('hyperlink')`, which matched the literal word anywhere\n * in the grid's *content* — a cell reading \"see the hyperlink docs\" suppressed the default for\n * the whole table — and serialized every cell on every `addTable` to ask.\n * @param rows - the table's rows\n */\nexport function tableHasHyperlink(rows: TableCellInternal[][]): boolean {\n\treturn rows.some((cells) =>\n\t\tcells.some((cell) => {\n\t\t\tif (!cell) return false\n\t\t\tif (cell.options?.hyperlink) return true\n\t\t\tif (!Array.isArray(cell.text)) return false\n\t\t\treturn cell.text.some((run) => !!run?.options?.hyperlink)\n\t\t})\n\t)\n}\n","/**\n * pptx-ts: a table's cell grid.\n *\n * Rows arrive lopsided -- `row1: [A, B, C]`, `row2: [D]` when the first two columns are held by\n * a rowspan from above -- so a cell's position in its row array is not its column. Four places\n * needed to know where a cell actually lands (the auto-pager, twice, in one function; the\n * measured-fit pass; the table emitter) and each walked the grid itself, tracking rowspan\n * occupancy in its own array with its own off-by-one convention.\n *\n * This is that traversal, once. It lives beside {@link resolveSpan} rather than in `measure/`\n * because the grid is a fact about the authored table, not a measurement of it -- the pager and\n * the emitter want it as much as the fitter does, and `measure/table-fit.ts` was already\n * reaching into `gen/table/` for the span reader it is built on.\n */\n\nimport type { TableCellInternal } from '../../types/internal.js'\nimport { resolveSpan } from './spans.js'\n\n/**\n * How many grid columns a table has: the sum of the first row's colspans.\n *\n * The count cannot come from `rows[0].length` -- a colspan makes one cell occupy several\n * columns -- and it is read off the first row alone, which is the writer's standing rule: a\n * later row wider than the first is ragged input, and the grid it is measured, paged and\n * emitted against is the one `a:tblGrid` declares.\n */\nexport function tableColCount(rows: TableCellInternal[][]): number {\n\tconst first = rows[0]\n\treturn first ? first.reduce((n, c) => n + resolveSpan(c?.options?.colspan, 'colspan'), 0) : 0\n}\n\n/** The bookkeeping a row-major grid walk needs to route around rowspans; see {@link createRowSpanOccupancy}. */\ninterface RowSpanOccupancy {\n\t/** The first column at or after `col` that no rowspan from above is holding. */\n\tnextFree: (col: number) => number\n\t/** Record that `colSpan` columns from `col` are held for `rowSpan` rows, this one included. */\n\thold: (col: number, colSpan: number, rowSpan: number) => void\n\t/** Close the current row: every held column has one fewer row left to hold. */\n\tendRow: () => void\n}\n\n/**\n * The rowspan-occupancy rule, stated once.\n *\n * A row states only the cells it *starts*: a column held by a `rowspan` from above is filled\n * without the row mentioning it, so a cell's position in its row array is not its column. Tracking\n * that is three operations -- skip what is held, mark what this cell holds, age the holds by a row\n * -- and getting the ageing off by one silently shifts every column below.\n *\n * It has two callers asking different questions on different input. {@link walkTableGrid} places\n * authored `TableCell`s into a grid whose width `a:tblGrid` already declares; `measureGridColumns`\n * (`gen/table/html-dom.ts`) measures how wide an imported HTML table's grid *is*, reading spans off\n * HTML attributes, with no width known up front. Neither can be expressed as the other without\n * giving one of them a mode it does not want -- but the rule underneath is the same rule, and it is\n * here rather than in both.\n *\n * The array is sparse and unbounded on purpose: a caller that knows its width clamps what it\n * `hold`s, and then nothing past that width is ever held, so an unbounded `nextFree` returns the\n * same answer a bounded one would.\n */\nexport function createRowSpanOccupancy(): RowSpanOccupancy {\n\t// held[c] = rows still covered by a rowspan started at or above the current row.\n\tconst held: number[] = []\n\treturn {\n\t\tnextFree(col) {\n\t\t\tlet free = col\n\t\t\twhile ((held[free] ?? 0) > 0) free++\n\t\t\treturn free\n\t\t},\n\t\thold(col, colSpan, rowSpan) {\n\t\t\tfor (let idx = 0; idx < colSpan; idx++) held[col + idx] = rowSpan\n\t\t},\n\t\tendRow() {\n\t\t\tfor (let idx = 0; idx < held.length; idx++) {\n\t\t\t\tconst rows = held[idx] ?? 0\n\t\t\t\tif (rows > 0) held[idx] = rows - 1\n\t\t\t}\n\t\t},\n\t}\n}\n\n/** A placed (non-merged origin) cell yielded by {@link walkTableGrid}. */\nexport interface GridPlacement {\n\tcell: TableCellInternal\n\t/** Zero-based grid row of the cell's top-left origin. */\n\trow: number\n\t/** Zero-based grid column of the cell's top-left origin. */\n\tcol: number\n\t/** Rows spanned, clamped to the available rows. */\n\trowSpan: number\n\t/** Columns spanned, clamped to the grid width. */\n\tcolSpan: number\n}\n\n/**\n * Walk a table's cell grid in row-major order, resolving each authored cell to its\n * grid origin (`row`/`col`) and clamped colspan/rowspan. Tracks rowspan occupancy so\n * a cell never lands beneath one spanned from above. This is the single traversal the\n * auto-pager, the measured-fit shrink pass, {@link computeTableLayout} and the table emitter's\n * merge grid all read, so the table that is paged and measured is the table that is written.\n *\n * A cell that starts past the last grid column is not yielded: a row longer than the first is\n * ragged input, and the grid is the one `a:tblGrid` declares.\n */\nexport function* walkTableGrid(rows: TableCellInternal[][], numCols: number): Generator<GridPlacement> {\n\tconst occupancy = createRowSpanOccupancy()\n\tfor (let r = 0; r < rows.length; r++) {\n\t\tconst row = rows[r]\n\t\tif (!row) continue\n\t\tlet col = 0\n\t\tfor (const cell of row) {\n\t\t\tcol = occupancy.nextFree(col)\n\t\t\tif (col >= numCols) break\n\t\t\tconst colspan = resolveSpan(cell?.options?.colspan, 'colspan')\n\t\t\tconst rowspan = Math.min(resolveSpan(cell?.options?.rowspan, 'rowspan'), rows.length - r)\n\t\t\tconst colStart = col\n\t\t\t// Clamped to the declared width, which is also what keeps `nextFree` unbounded and still\n\t\t\t// correct: nothing past `numCols` is ever held, so it never has a reason to walk past it.\n\t\t\tconst colEnd = Math.min(colStart + colspan, numCols)\n\t\t\toccupancy.hold(colStart, colEnd - colStart, rowspan)\n\t\t\tcol = colEnd\n\t\t\tyield { cell, row: r, col: colStart, rowSpan: rowspan, colSpan: colEnd - colStart }\n\t\t}\n\t\toccupancy.endRow()\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"html-dom-DvJmuHt2.js","names":[],"sources":["../src/gen/table/html-dom.ts"],"sourcesContent":["/**\n * pptx-ts: HTML-table → slides (browser DOM path)\n *\n * The tableToSlides() flow: reproduce an HTML table as a PowerPoint table across as many\n * slides as needed. The DOM-independent parts are factored into pure helpers\n * (`resolveHtmlColWidth`, `pickColWidthBasis`, `htmlBorderToProps`, `cssColorToHex`) that\n * are unit-tested directly, and the whole flow runs anywhere there is a DOM.\n *\n * Only real *measurement* is out of active scope (see AGENTS.md): without a layout engine\n * `offsetWidth` is `0`, so widths fall back to computed CSS then to an equal split. A fallback\n * rather than a degradation, and the distinction is load-bearing — see {@link pickColWidthBasis},\n * whose two bases measure different boxes.\n *\n * **Coverage.** This file used to be excluded from the report, on the grounds that only the\n * browser entry imported it and the `dist/browser*.js` globs therefore swallowed it. Both\n * halves of that are stale: `pptx-ts/html` imports it too, so tsdown emits it as its own\n * `dist/html-dom-*.js` chunk, and those globs are gone from `vitest.config.ts` entirely. It\n * is covered code now — against happy-dom by the Node suite\n * (test/regression/html/html-to-slides-node.test.ts) and, for the measured width basis that no\n * Node DOM can produce, in a real Chromium (test/browser/table-widths.spec.ts).\n */\n\nimport { SlideObjectType } from '../../enums.js'\nimport type {\n\tAddSlideProps,\n\tBorderProps,\n\tHAlign,\n\tPositionProps,\n\tPresLayout,\n\tTableProps,\n\tTableToSlidesDocument,\n\tTableToSlidesElement,\n\tTableToSlidesProps,\n\tTableCellProps,\n\tVAlign,\n} from '../../types/index.js'\nimport type { Slide } from '../../types/slide.js'\nimport type { SlideLayoutInternal, TableCellInternal, TableToSlidesPropsInternal } from '../../types/internal.js'\nimport { getSmartParseNumber, inch2Emu, resolveSlideMarginsInches, usableTableWidthEmu } from '../../units-internal.js'\nimport { warn } from '../../diagnostics.js'\nimport { DEFAULT_PX_PER_INCH, EMU_PER_INCH, POINTS_PER_INCH } from '../../units.js'\nimport { createRowSpanOccupancy } from './grid.js'\nimport { MAX_TABLE_SPAN, resolveSpan } from './spans.js'\nimport { getSlidesForTableRows } from './autopage.js'\nimport { InvalidOptionError } from '../../errors.js'\n\n/**\n * CSS `text-align` / `vertical-align` values this converter can express as a table cell's own\n * alignment. The two logical values map onto the physical pair; everything else — `justify`,\n * `initial`, a value the browser did not resolve — is absent here and so leaves the cell's\n * alignment alone.\n */\nconst CSS_TEXT_ALIGN: Record<string, HAlign> = {\n\tleft: 'left',\n\tcenter: 'center',\n\tright: 'right',\n\tstart: 'left',\n\tend: 'right',\n}\nconst CSS_VERTICAL_ALIGN: Record<string, VAlign> = { top: 'top', middle: 'middle', bottom: 'bottom' }\n\ntype MarginTuple = [number, number, number, number]\ntype BorderTuple = [BorderProps, BorderProps, BorderProps, BorderProps]\n/**\n * What `tableToSlides` needs a presentation to be: somewhere to put slides, and a layout to\n * size them against. Structural on purpose — stating the two members rather than naming the\n * class is what lets the free function on `pptx-ts/html` take any presentation instance\n * (Node, browser, or standalone) without the entry importing one.\n */\nexport type TableToSlidesHost = {\n\taddSlide: (options?: AddSlideProps) => Slide\n\tpresLayout: PresLayout\n}\n\n/**\n * The whole DOM surface `genTableToSlides` needs: the table element, and a way to read a\n * cell's computed style.\n *\n * Resolving this once up front is what decouples the flow from `window`/`document`. Given the\n * element itself, both halves come from the element's own `ownerDocument`/`defaultView`, so no\n * global is read at all — which is what lets the same implementation run outside a browser.\n */\ntype DomContext = {\n\ttable: Element\n\tgetComputedStyle: (el: Element) => CSSStyleDeclaration\n}\n\n/**\n * Stand-in for `getComputedStyle` on a document that has no view — a document produced by\n * parsing rather than by a browsing context has a `null` `defaultView` and therefore no\n * cascade to compute against. Every property reads as `''`, which every consumer below\n * already treats as \"not set\", so styling degrades to defaults instead of throwing.\n */\nconst NO_COMPUTED_STYLE = {\n\tgetPropertyValue: () => '',\n} as unknown as CSSStyleDeclaration\n\n/**\n * Bind a style reader to the document's own view, falling back to {@link NO_COMPUTED_STYLE}.\n * @param {Document | null} doc - the table's owner document\n * @returns {(el: Element) => CSSStyleDeclaration} computed-style reader\n */\nfunction resolveStyleReader(doc: Document | null): (el: Element) => CSSStyleDeclaration {\n\tconst view = doc?.defaultView\n\treturn view ? view.getComputedStyle.bind(view) : () => NO_COMPUTED_STYLE\n}\n\n/**\n * Resolve the table element and its style reader from whatever the caller passed.\n *\n * An **element** needs no ambient DOM: the document and its view are reached through\n * `ownerDocument`/`defaultView`. A **string id** does need one, taken from `options.document`\n * when supplied and otherwise from `globalThis.document`; with neither, the error names both\n * remedies rather than surfacing a bare `document is not defined`.\n *\n * This is the one place the public structural element type ({@link TableToSlidesElement},\n * which any DOM satisfies) is narrowed to `lib.dom`'s `Element`, so the rest of the flow can\n * be written against ordinary DOM types. The cast is safe in the only sense that matters here:\n * everything downstream reads standard members and tolerates them being absent — that is what\n * makes the conversion portable in the first place.\n * @param {TableToSlidesElement | string} target - the table element, or the id of one\n * @param {TableToSlidesProps} options - generation options (may carry an explicit `document`)\n * @returns {DomContext} resolved DOM context\n */\nfunction resolveDomContext(target: TableToSlidesElement | string, options: TableToSlidesProps): DomContext {\n\tconst asElement = (element: TableToSlidesElement): Element => element as unknown as Element\n\n\tif (typeof target !== 'string') {\n\t\tconst table = asElement(target)\n\t\treturn { table, getComputedStyle: resolveStyleReader(table.ownerDocument) }\n\t}\n\n\tconst doc = options.document ?? (globalThis as { document?: TableToSlidesDocument }).document\n\tif (!doc) {\n\t\tthrow new InvalidOptionError(\n\t\t\t'html/no-document',\n\t\t\t'tableToSlides: no DOM available to resolve the table id \"' +\n\t\t\t\ttarget +\n\t\t\t\t'\" — pass the <table> element itself, or supply a document via `options.document`.'\n\t\t)\n\t}\n\tconst found = doc.getElementById(target)\n\tif (!found)\n\t\tthrow new InvalidOptionError('html/table-not-found', 'tableToSlides: Table ID \"' + target + '\" does not exist!')\n\tconst table = asElement(found)\n\treturn { table, getComputedStyle: resolveStyleReader(table.ownerDocument) }\n}\n\n// ===== DOM-table helpers (browser path) =====\n// DOM-independent helpers factored out of the browser-only tableToSlides() flow\n// so they can be unit-tested without a rendered page (see AGENTS.md scope note).\n\n/**\n * Convert one 0-255 RGB component to its two-digit hex form.\n *\n * Lives here rather than beside the other color code in `gen/drawingml/color.ts` because\n * `getComputedStyle` colors are the only thing in the package that arrives as RGB\n * components — nothing else in the library calls this.\n * @param {number} c - component color\n * @returns {string} hex string\n */\nfunction componentToHex(c: number): string {\n\tconst hex = c.toString(16)\n\treturn hex.length === 1 ? '0' + hex : hex\n}\n\n/**\n * Converts RGB colors from css selectors to Hex for Presentation colors\n * @param {number} r - red value\n * @param {number} g - green value\n * @param {number} b - blue value\n * @returns {string} XML string\n */\nfunction rgbToHex(r: number, g: number, b: number): string {\n\treturn (componentToHex(r) + componentToHex(g) + componentToHex(b)).toUpperCase()\n}\n\n/**\n * Convert a computed CSS border (width string + color string) from `getComputedStyle` into a\n * pptx `BorderProps`.\n *\n * `StrokeProps.width` is in **points**, so the px magnitude is converted through\n * {@link htmlCssPxToPoints} rather than copied across: a `1px` CSS border is 0.75pt, not 1pt.\n * This was the third read in this file to make that mistake and the last one left — the font\n * size and the cell padding were each corrected against `DEFAULT_PX_PER_INCH` on their own, and\n * routing this one through the same converter is what stops a fourth from drifting apart again.\n *\n * Preserves *fractional* widths: a hairline CSS border such as `0.5px` must not be rounded to\n * `0pt` and silently vanish — the table serializer (`ptsToEmuLenient`) emits fractional points just\n * fine, so there is no reason to integer-round here. A\n * computed width of `0` (or a non-finite value) yields `{ type: 'none' }` so we never emit a\n * zero-width line. `''`, `auto` and `3em` are non-finite for the same reason\n * {@link parseCssPx} says they are, and take the same exit.\n * @param {string} widthStr - computed `border-<side>-width`, e.g. `\"0.5px\"`\n * @param {string} colorStr - computed `border-<side>-color`, e.g. `\"rgb(102, 102, 102)\"`\n * @returns {BorderProps} border props for the cell side\n */\nexport function htmlBorderToProps(widthStr: string, colorStr: string): BorderProps {\n\tconst pt = htmlCssPxToPoints(widthStr)\n\tif (!Number.isFinite(pt) || pt <= 0) return { type: 'none' }\n\treturn { width: pt, color: cssColorToHex(colorStr) ?? '000000' }\n}\n\n/**\n * Convert a computed CSS color to a pptx hex color, or report that it has none.\n *\n * A browser normalizes every computed color to `rgb()`/`rgba()`, which is why the flow below\n * originally only parsed that form. Outside a browser there is no normalization step, so a\n * computed color comes back however the stylesheet wrote it — `#ff0000` is what happy-dom\n * returns. Feeding that to the `rgb()` parser produced `Number('#ff0000')` → `NaN` → the\n * literal color string `\"NANNANNAN\"`, an invalid value emitted without complaint.\n *\n * Handles `rgb()`/`rgba()` and `#rgb`/`#rrggbb`. Everything else — a named color, a `color()`\n * function, an empty string — returns `undefined` rather than a guess, so the caller can\n * apply its own default instead of emitting nonsense.\n *\n * A fully transparent color (`alpha === 0`) also returns `undefined`: it states the absence of\n * a color, and pptx has no way to say \"transparent\" in a solid fill.\n * @param {string | null | undefined} value - computed CSS color, e.g. `\"rgb(255, 0, 0)\"` or `\"#ff0000\"`; nullish reads as absent\n * @returns {string | undefined} six-digit uppercase hex, or `undefined` when unparseable\n */\nexport function cssColorToHex(value: string | null | undefined): string | undefined {\n\tconst raw = String(value ?? '').trim()\n\n\tconst rgbMatch = /^rgba?\\(([^)]*)\\)$/i.exec(raw)\n\tif (rgbMatch) {\n\t\tconst parts = (rgbMatch[1] ?? '').split(/[,/\\s]+/).filter((part) => part.length > 0)\n\t\tif (parts.length < 3) return undefined\n\t\tconst channels = parts.slice(0, 3).map((part) => Number(part.replace('%', '')))\n\t\tif (channels.some((channel) => !Number.isFinite(channel))) return undefined\n\t\tif (parts.length > 3 && Number(parts[3]) === 0) return undefined\n\t\t// Clamp and round before hex conversion: a browser always computes whole 0-255\n\t\t// channels, but nothing guarantees another DOM does, and `(255.5).toString(16)`\n\t\t// is `\"ff.8\"` — a malformed color rather than a wrong one.\n\t\tconst [r = 0, g = 0, b = 0] = channels.map((channel) => Math.max(0, Math.min(255, Math.round(channel))))\n\t\treturn rgbToHex(r, g, b)\n\t}\n\n\tconst hexMatch = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(raw)\n\tif (hexMatch) {\n\t\tconst digits = hexMatch[1] ?? ''\n\t\tconst full =\n\t\t\tdigits.length === 3\n\t\t\t\t? digits\n\t\t\t\t\t\t.split('')\n\t\t\t\t\t\t.map((digit) => digit + digit)\n\t\t\t\t\t\t.join('')\n\t\t\t\t: digits\n\t\treturn full.toUpperCase()\n\t}\n\n\treturn undefined\n}\n\n/**\n * Resolve a single HTML-table column width for `tableToSlides`.\n *\n * Precedence: an explicit `data-pptx-width` wins outright; otherwise the proportional width\n * derived from the live table is used, raised to `data-pptx-min-width` when that floor is larger.\n *\n * Hidden tables report `offsetWidth` 0 for every cell, which makes `calcWidth` non-finite (a 0/0\n * proportional calc). Fall back to `0` there so an explicit `data-pptx-width` / `data-pptx-min-width`\n * override still drives the column instead of emitting a `NaN` width.\n * @param {number} calcWidth - proportional width derived from `offsetWidth` (may be `NaN` for hidden tables)\n * @param {number} setWidth - `data-pptx-width` override (`0`/`NaN` when absent or invalid)\n * @param {number} minWidth - `data-pptx-min-width` floor (`0`/`NaN` when absent or invalid)\n * @returns {number} resolved column width\n */\nexport function resolveHtmlColWidth(calcWidth: number, setWidth: number, minWidth: number): number {\n\tconst safeCalc = Number.isFinite(calcWidth) ? calcWidth : 0\n\tif (Number.isFinite(setWidth) && setWidth > 0) return setWidth\n\treturn Number.isFinite(minWidth) && minWidth > safeCalc ? minWidth : safeCalc\n}\n\n/** A CSS value that is a bare number, or a number with a `px`/`%` unit. Nothing else parses. */\nconst CSS_LENGTH = /^\\s*(-?(?:\\d+\\.?\\d*|\\.\\d+))\\s*(px|%)?\\s*$/i\n\n/**\n * Parse a single computed CSS length in **px** to its numeric magnitude.\n *\n * A bare number is read as px (computed styles do not emit one, but an inline `style` read\n * back by a non-browser DOM can). Everything else — `''`, `auto`, `3em`, and deliberately\n * `30%` — is `NaN`: a percentage is meaningful only relative to something, so it cannot be\n * turned into an absolute length here. (Percentages *are* usable as a proportional column\n * basis; that is {@link parseCssWidthBasis}'s job, not this one's.) Callers decide what a\n * `NaN` means for them.\n * @param {string | null | undefined} value - computed CSS value, e.g. `\"1.5px\"`; nullish reads as absent\n * @returns {number} magnitude in px, or `NaN` when the value is not an absolute px length\n */\nexport function parseCssPx(value: string | null | undefined): number {\n\tconst match = CSS_LENGTH.exec(String(value ?? ''))\n\tif (!match || match[2] === '%') return NaN\n\treturn Number(match[1])\n}\n\n/**\n * A computed CSS px length as the points every `pt`-measured table property is in, or `NaN` when\n * the value is not an absolute px length.\n *\n * This is the file's **one** px→pt conversion, and it is one because the same mistake was made\n * three separate times under the same stale \"px to pt 1:1\" note. A default `16px` cell emitted\n * `sz=\"1600\"` — 16pt, a third larger than the 12pt the browser rendered; the cell padding read\n * a px magnitude as the inches `TableCellProps.margin` wants, until 2026-07-31; and a `1px`\n * border was emitted as 1pt, a third too thick. Each was found and corrected on its own, and\n * the next went on being wrong, because there was no shared converter for a sweep to land on.\n * Now there is, for the two properties measured in points. The padding is not one of them --\n * it resolves to inches -- so it divides by `DEFAULT_PX_PER_INCH` at its own site and this\n * comment is the link between them.\n *\n * CSS defines the reference pixel as 1/96in, so the conversion is the same density the `\"<n>px\"`\n * coordinate unit uses. An `em`, a `%` or a keyword has no absolute size here and comes back\n * `NaN`, which each caller reads as its own kind of absence — the font size is left off the\n * cell, and a border becomes `{ type: 'none' }`.\n * @param value - computed CSS value, e.g. `\"16px\"`\n * @returns the length in points, or `NaN` when the value is not an absolute px length\n */\nfunction htmlCssPxToPoints(value: string): number {\n\treturn (parseCssPx(value) * POINTS_PER_INCH) / DEFAULT_PX_PER_INCH\n}\n\n/**\n * Parse a whole row of computed CSS widths into a column basis, or reject the set.\n *\n * The result is only ever used *proportionally* (each column's share of the total), so the\n * unit does not have to be absolute — it only has to be the same for every column. Hence:\n *\n * - all `px` (or bare numbers) → their magnitudes\n * - all `%` → their magnitudes; `[25%, 25%, 50%]` is a perfectly good 1:1:2 basis\n * - anything else, or a **mix** of units, or a single unparseable entry (`auto`, `''`,\n * `3em`) → `[]`, meaning \"no usable basis\"\n *\n * Rejecting the whole set on one bad entry is deliberate: a partial basis would silently\n * give the unparseable columns zero width, which is worse than falling back to an equal\n * split. Negative magnitudes reject for the same reason.\n * @param {readonly string[]} values - computed `width` per column, in column order\n * @returns {number[]} per-column basis, or `[]` when the set is not usable\n */\nexport function parseCssWidthBasis(values: readonly string[]): number[] {\n\tconst basis: number[] = []\n\tlet unit = ''\n\tfor (const value of values) {\n\t\tconst match = CSS_LENGTH.exec(String(value ?? ''))\n\t\tif (!match) return []\n\t\tconst magnitude = Number(match[1])\n\t\tif (!Number.isFinite(magnitude) || magnitude < 0) return []\n\t\tconst valueUnit = (match[2] ?? 'px').toLowerCase()\n\t\tif (!unit) unit = valueUnit\n\t\telse if (unit !== valueUnit) return []\n\t\tbasis.push(magnitude)\n\t}\n\treturn basis\n}\n\n/**\n * Choose which vector the proportional column math runs on, falling back as bases run out.\n *\n * `offsetWidth` is the ideal basis — it is the width the table actually rendered at — but it\n * requires a layout engine, and reports `0` for every cell both in a hidden table and on any\n * DOM outside a browser. So:\n *\n * 1. **measured** (`offsetWidth`) when it carries any width at all — the browser path, unchanged\n * 2. **CSS widths** when the stylesheet states them (see {@link parseCssWidthBasis})\n * 3. **equal split** otherwise — a basis of all-ones, which the existing proportional math\n * turns into equal columns for free\n *\n * Only the basis changes; `data-pptx-width` / `data-pptx-min-width` overrides still apply\n * downstream via {@link resolveHtmlColWidth} and still win outright.\n *\n * **The first two bases do not measure the same box, and the docs used to imply they did.**\n * `offsetWidth` is the border box; a computed `width` is the content box. Padding alone\n * separates them — `test/browser/harness/table.html` is built so it does, giving 1:1 measured\n * against 2:1 from CSS on one table — so choosing arm 2 over arm 1 can change a table's column\n * *proportions*, not just their precision. That is why the fixture discriminates at all, and why\n * \"degrades to computed CSS\" was the wrong word for it everywhere it appeared.\n *\n * Left as-is rather than reconciled. Normalizing arm 2 to the border box would need the computed\n * padding and border widths, which the DOMs that reach arm 2 need not resolve either (a `%`\n * padding computes to nothing usable without layout), so it would converge the two only\n * sometimes — and it would collapse the one discriminator the browser lane has, turning\n * `table-widths.spec.ts` back into a test that passes whether or not the measured arm ran.\n * A caller who needs both runtimes to agree on a column states it with `data-pptx-width`.\n * @param {readonly number[]} measured - per-column `offsetWidth`\n * @param {readonly number[]} cssWidths - per-column CSS width basis (`[]` when unusable)\n * @returns {number[]} the basis vector to run the proportional calc on\n */\nexport function pickColWidthBasis(measured: readonly number[], cssWidths: readonly number[]): number[] {\n\tconst sum = (arr: readonly number[]): number => arr.reduce((acc, n) => acc + (Number.isFinite(n) ? n : 0), 0)\n\tif (sum(measured) > 0) return [...measured]\n\tif (cssWidths.length === measured.length && sum(cssWidths) > 0) return [...cssWidths]\n\treturn measured.map(() => 1)\n}\n\n/** One cell's span attributes, as far as the grid walk cares. */\ntype GridCellSpans = { colspan?: number; rowspan?: number }\n\n/**\n * Read a `colspan`/`rowspan` as the number of grid tracks it covers.\n *\n * Lenient on purpose: `0`, a negative, a fraction, an unparseable attribute and an absent one all\n * mean `1`. A bad span attribute should cost its own cell nothing and the rest of the grid nothing\n * — the alternative, propagating a `NaN` or a negative into the column walk, shifts every\n * subsequent column.\n * @param {unknown} value - the raw attribute value\n * @returns {number} tracks covered, at least 1\n */\nfunction gridSpan(value: unknown, kind: 'colspan' | 'rowspan'): number {\n\tconst num = Math.floor(Number(value))\n\tif (!Number.isFinite(num) || num <= 1) return 1\n\t// Past `MAX_TABLE_SPAN` is not lenient ground: `resolveSpan` reports it and reads 1, the value\n\t// the pager's own span check would set. Without this ceiling the grid was measured and padded\n\t// for `colspan=\"1500\"` while the same cell was paged and written as one column wide.\n\treturn num > MAX_TABLE_SPAN ? resolveSpan(num, kind) : num\n}\n\n/**\n * Measure the column grid a set of table rows actually occupies.\n *\n * An HTML table is not a rectangle of cells — a row states only the cells it *starts*, so its\n * length says nothing about how many grid columns it fills: a `colspan` fills several, and a\n * `rowspan` started higher up fills one without the row mentioning it. The pptx side has no such\n * model: `<a:tblGrid>` declares N columns and every `<a:tr>` must carry N `<a:tc>`. Something has\n * to translate, and that is a walk of the standard HTML table model — cells pack left to right,\n * skipping columns still held by a rowspan above.\n *\n * Returns the grid width and, per row, how many columns that row reaches. The difference between\n * the two is exactly the padding a ragged row needs; the merge cells for `colspan`/`rowspan` are\n * *not* padding — the table emitter synthesizes those itself, so they are counted as filled here.\n *\n * Spans are read through {@link gridSpan}, so a bad attribute cannot shift the whole grid. The\n * occupancy bookkeeping underneath is {@link createRowSpanOccupancy}, shared with\n * `walkTableGrid` -- the same rowspan rule, asked a different question: that one places authored\n * cells into a grid whose width is already declared, this one measures how wide the grid *is*.\n * @param {readonly (readonly GridCellSpans[])[]} rows - per-row cell spans, in emission order\n * @returns {{ columns: number, filled: number[] }} grid width, and columns reached per row\n */\nexport function measureGridColumns(rows: readonly (readonly GridCellSpans[])[]): { columns: number; filled: number[] } {\n\tconst occupancy = createRowSpanOccupancy()\n\tconst filled: number[] = []\n\n\tfor (const row of rows) {\n\t\tlet col = 0\n\t\tfor (const cell of row) {\n\t\t\tcol = occupancy.nextFree(col)\n\t\t\tconst colspan = gridSpan(cell?.colspan, 'colspan')\n\t\t\t// Held now, aged at the end of this row, so it leaves `rowspan - 1` behind.\n\t\t\toccupancy.hold(col, colspan, gridSpan(cell?.rowspan, 'rowspan'))\n\t\t\tcol += colspan\n\t\t}\n\t\t// Trailing columns held from above count too: a row whose last cells are all rowspan\n\t\t// continuations reaches past its own final cell.\n\t\tfilled.push(occupancy.nextFree(col))\n\t\toccupancy.endRow()\n\t}\n\n\treturn { columns: filled.reduce((max, reached) => (reached > max ? reached : max), 0), filled }\n}\n\n/**\n * Widen a column-width basis to cover a grid wider than the row it was derived from.\n *\n * The basis comes from one row — the first with cells — but the grid is as wide as the *widest*\n * row, and those need not agree (a single spanning header over a wider body is the common shape).\n * The columns the source row never described get the average of the ones it did, so they read as\n * ordinary columns rather than as a zero-width sliver; with no usable basis at all they get `1`,\n * which the proportional calc downstream turns into an equal split.\n * @param {readonly number[]} basis - per-column basis derived from the width-source row\n * @param {number} columns - the full grid width\n * @returns {number[]} basis covering every grid column\n */\nexport function extendColBasis(basis: readonly number[], columns: number): number[] {\n\tconst extended = [...basis]\n\tconst total = extended.reduce((acc, width) => acc + (Number.isFinite(width) ? width : 0), 0)\n\tconst share = extended.length > 0 && total > 0 ? total / extended.length : 1\n\twhile (extended.length < columns) extended.push(share)\n\treturn extended\n}\n\n/**\n * The minimum a cell has to look like for {@link readCellText}. Any DOM's element satisfies it;\n * stating it structurally is what lets the fallback walk be unit-tested without a DOM at all.\n */\ntype TextCell = {\n\tinnerText?: string\n\tnodeType?: number\n\tnodeValue?: string | null\n\tnodeName?: string\n\tchildNodes?: ArrayLike<TextCell>\n}\n\n/**\n * Read a cell's text, with `<br>` surviving as a newline.\n *\n * `innerText` is the right answer in a browser — it is the *rendered* text, so it already\n * collapses whitespace, honors `display: none`, and turns `<br>` into `\"\\n\"`. But it is an\n * HTML-spec extra tied to rendering, and outside a browser it is either absent (jsdom does not\n * implement it, so every cell would come out empty) or present but not actually rendered\n * (happy-dom returns `\"ab\"` for `a<br>b`, so every cell would come out on one line).\n *\n * So both are computed and the better one wins: a `childNodes` walk that maps `<br>` to a line\n * break and collapses whitespace per line, and `innerText`. `innerText` is preferred unless it\n * dropped a line break the walk found — the one thing that provably makes it not the rendered\n * text. Neither can know about `text-transform` without a browser.\n * @param {TextCell} cell - the table cell element\n * @returns {string} cell text, `<br>`-separated lines joined by `\"\\n\"`\n */\nexport function readCellText(cell: TextCell): string {\n\t// Accumulate one bucket per line rather than one string with \"\\n\" separators: the source's\n\t// own indentation contains newlines, and only a `<br>` may actually start a new line. A\n\t// separator character could not tell those two apart; separate buckets never have to.\n\tconst lines: string[] = ['']\n\tconst append = (text: string): void => {\n\t\tlines[lines.length - 1] = (lines[lines.length - 1] ?? '') + text\n\t}\n\tconst walk = (node: TextCell): void => {\n\t\tif (node.nodeType === 3) {\n\t\t\tappend(node.nodeValue ?? '')\n\t\t\treturn\n\t\t}\n\t\tif (node.nodeType !== 1) return\n\t\tif ((node.nodeName ?? '').toUpperCase() === 'BR') {\n\t\t\tlines.push('')\n\t\t\treturn\n\t\t}\n\t\tconst children = node.childNodes\n\t\tfor (let idx = 0; idx < (children?.length ?? 0); idx++) {\n\t\t\tconst child = children?.[idx]\n\t\t\tif (child) walk(child)\n\t\t}\n\t}\n\n\t// Walk from the cell's children: the cell itself is an element, and can never be a BR.\n\tconst children = cell.childNodes\n\tfor (let idx = 0; idx < (children?.length ?? 0); idx++) {\n\t\tconst child = children?.[idx]\n\t\tif (child) walk(child)\n\t}\n\tconst walked = lines.map((line) => line.replace(/\\s+/g, ' ').trim()).join('\\n')\n\n\t// Prefer `innerText` — except when the walk found line breaks it dropped. A DOM that does\n\t// not render can still expose an `innerText` property that is really just `textContent`\n\t// (happy-dom returns `\"ab\"` for `a<br>b`), and that one is not the rendered text this\n\t// wants: it has silently lost the cell's line structure. Where it kept the breaks, it is\n\t// the better answer, because it also knows about `display:none` and `text-transform`.\n\tconst rendered = cell.innerText\n\tif (typeof rendered !== 'string') return walked\n\treturn walked.includes('\\n') && !rendered.includes('\\n') ? walked : rendered\n}\n\n// ===== Live-DOM tableToSlides() flow =====\n// Browser-only entry (reads a rendered table via getComputedStyle/offsetWidth);\n// out of active scope — see AGENTS.md. Internally signposted by `// STEP 1..5`.\n\n/**\n * Resolve `options.masterTitle` to the slide layout it names, so the auto-pager can take that\n * master's margins.\n *\n * The layout registry is a presentation *internal* — it is not on {@link TableToSlidesHost},\n * and the public `slideLayouts` getter deliberately hides the `_name` this matches on. Rather\n * than widen either, read it defensively: a host that has no registry simply resolves no\n * master, which is what a caller passing a bare `{ addSlide, presLayout }` object should get.\n * The alternative — dropping the lookup on the free-function path — would make `masterTitle`\n * silently do nothing there, which is a trap.\n * @param {TableToSlidesHost} pptx - the presentation the slides are being added to\n * @param {string} masterTitle - the `title` passed to `defineSlideMaster`\n * @returns {SlideLayoutInternal | undefined} the named layout, if this host has one\n */\nfunction resolveMasterSlide(pptx: TableToSlidesHost, masterTitle?: string): SlideLayoutInternal | undefined {\n\tif (!masterTitle) return undefined\n\tconst layouts = (pptx as { _slideLayouts?: SlideLayoutInternal[] })._slideLayouts\n\tif (!Array.isArray(layouts)) return undefined\n\treturn layouts.find((layout) => layout._name === masterTitle)\n}\n\n/** Which of the three logical sections a row belongs to. A section-less row counts as body. */\ntype TablePart = 'thead' | 'tbody' | 'tfoot'\n\n/**\n * A row's cells, via `HTMLTableRowElement.cells`.\n *\n * Read off the structural shape rather than the `lib.dom` type so a DOM that does not implement\n * the collection degrades to \"this row has no cells\" instead of throwing — the same tolerance\n * every other DOM read in this file has.\n * @param {Element} row - a `<tr>`\n * @returns {HTMLTableCellElement[]} the row's cells, in document order\n */\nfunction rowCells(row: Element): HTMLTableCellElement[] {\n\tconst cells = (row as { cells?: ArrayLike<Element> }).cells\n\treturn cells ? (Array.from(cells) as HTMLTableCellElement[]) : []\n}\n\n/**\n * Collect every row of the table, bucketed head → body → foot.\n *\n * `HTMLTableElement.rows` is the right source and a `thead tr`/`tbody tr`/`tfoot tr` query is not,\n * for two reasons the query cannot fix:\n *\n * - **A row need not be in a section.** `<table><tr>…` is valid authored markup, and a table built\n * with `createElement`/`appendChild` has no `<tbody>` at all — the HTML *parser* inserts one, the\n * DOM API does not. Those rows matched none of the three selectors and were silently dropped,\n * which is how a perfectly good table reached `addTable` with zero rows and threw\n * `addTable: Array expected!` (upstream gitbrent/PptxGenJS#1005).\n * - **A descendant query reaches into nested tables.** `tbody tr` matches the rows of a table\n * inside a cell of this one, folding them into the outer table as extra rows.\n *\n * Each row's own parentage settles both questions: it names the section the row belongs to (the\n * head/body/foot split still matters downstream, for repeating header rows on auto-paged slides),\n * and it says whether the row is this table's at all. The ownership check is not redundant with\n * using `rows` — happy-dom's `rows` is itself a descendant walk, so a nested table's rows arrive\n * there too. Checking is what makes the answer the same on every DOM.\n * @param {Element} table - the `<table>` being converted\n * @returns {Array<{ row: Element, part: TablePart }>} rows in emission order\n */\nfunction collectTableRows(table: Element): Array<{ row: Element; part: TablePart }> {\n\tconst head: Array<{ row: Element; part: TablePart }> = []\n\tconst body: Array<{ row: Element; part: TablePart }> = []\n\tconst foot: Array<{ row: Element; part: TablePart }> = []\n\tconst place = (row: Element): void => {\n\t\tconst parent = row.parentElement\n\t\tconst section = (parent?.nodeName ?? '').toUpperCase()\n\t\tconst sectioned = section === 'THEAD' || section === 'TBODY' || section === 'TFOOT'\n\t\tif ((sectioned ? parent?.parentElement : parent) !== table) return\n\t\tif (section === 'THEAD') head.push({ row, part: 'thead' })\n\t\telse if (section === 'TFOOT') foot.push({ row, part: 'tfoot' })\n\t\telse body.push({ row, part: 'tbody' })\n\t}\n\n\tconst rows = (table as { rows?: ArrayLike<Element> }).rows\n\tif (rows) {\n\t\tfor (let idx = 0; idx < rows.length; idx++) {\n\t\t\tconst row = rows[idx]\n\t\t\tif (row) place(row)\n\t\t}\n\t} else {\n\t\t// A DOM without `rows` is not one this library has ever run on, but the section query is\n\t\t// still a truthful fallback for the sectioned tables it can see.\n\t\tfor (const part of ['thead', 'tbody', 'tfoot']) {\n\t\t\ttable.querySelectorAll(`${part} tr`).forEach(place)\n\t\t}\n\t}\n\n\treturn [...head, ...body, ...foot]\n}\n\n/**\n * Reproduces an HTML table as a PowerPoint table - including column widths, style, etc. - creates 1 or more slides as needed\n * @param {TableToSlidesHost} pptx - pptx-ts instance\n * @param {TableToSlidesElement | string} target - the table element, or the HTMLElementID of the table\n * @param {TableToSlidesProps} options - array of options (e.g.: tabsize)\n */\nexport function genTableToSlides(\n\tpptx: TableToSlidesHost,\n\ttarget: TableToSlidesElement | string,\n\toptions: TableToSlidesProps = {}\n): void {\n\t// Own the options before touching them, the way `addTextDefinition`, `addShapeDefinition`\n\t// and `addTableDefinition` each do. This function resolves the slide margin, the column\n\t// widths, the head rows and the per-page `y` into its working bag; writing those into the\n\t// caller's object made a reused bag change the next call's output — most visibly `y`, left\n\t// holding the continuation start, so the second call's first table began where the first\n\t// call's *second* page did.\n\tconst opts: TableToSlidesPropsInternal = { ...options }\n\tconst masterSlide = resolveMasterSlide(pptx, opts.masterTitle)\n\tconst arrObjTabHeadRows: TableCellInternal[][] = []\n\tconst arrObjTabBodyRows: TableCellInternal[][] = []\n\tconst arrObjTabFootRows: TableCellInternal[][] = []\n\tconst arrColW: number[] = []\n\tconst arrTabColW: number[] = []\n\tconst arrTabColCssW: string[] = []\n\tlet arrInchMargins: [number, number, number, number] = [0.5, 0.5, 0.5, 0.5] // TRBL-style\n\tlet intTabW = 0\n\n\t// REALITY-CHECK: resolve the table (and its style reader) before anything else — this is\n\t// also where a missing/unresolvable table id fails.\n\tconst ctx = resolveDomContext(target, opts)\n\n\t// STEP 1: Set margins. The caller's `slideMargin` is passed as given, absent included:\n\t// `resolveSlideMarginsInches` owns the caller/master/default tiers, and substituting 0.5\n\t// for an unstated one here made every deck look like it had asked for the default margin,\n\t// which outranks and so suppresses the master's own.\n\tarrInchMargins = resolveSlideMarginsInches(masterSlide?._margin, opts.slideMargin)\n\t// A stated `w` is the table's width, as given. Otherwise the table runs from its own left edge to\n\t// the right slide margin: `usableTableWidthEmu`, the reading `addTable` applies. This took the\n\t// slide width (or `w`) less BOTH margins, so it ignored `x` -- `{ x: 3 }` on a 10in slide was\n\t// 9in wide and ran to 12in -- and shrank a stated `w: 8` to 7in.\n\tconst tableXEmu =\n\t\topts.x === undefined || opts.x === null\n\t\t\t? inch2Emu(arrInchMargins[3])\n\t\t\t: getSmartParseNumber(opts.x, 'X', pptx.presLayout)\n\tconst emuSlideTabW =\n\t\topts.w === undefined || opts.w === null\n\t\t\t? usableTableWidthEmu(pptx.presLayout, tableXEmu, arrInchMargins)\n\t\t\t: getSmartParseNumber(opts.w, 'X', pptx.presLayout)\n\n\tif (opts.verbose) {\n\t\tconsole.log('[[VERBOSE MODE]]')\n\t\tconsole.log('|-- `tableToSlides` ----------------------------------------------------|')\n\t\tconsole.log(`| tableProps.h .................................... = ${opts.h}`)\n\t\tconsole.log(`| tableProps.w .................................... = ${opts.w}`)\n\t\tconsole.log(\n\t\t\t`| pptx.presLayout.width ........................... = ${(pptx.presLayout.width / EMU_PER_INCH).toFixed(1)}`\n\t\t)\n\t\tconsole.log(\n\t\t\t`| pptx.presLayout.height .......................... = ${(pptx.presLayout.height / EMU_PER_INCH).toFixed(1)}`\n\t\t)\n\t\tconsole.log(`| emuSlideTabW .................................... = ${(emuSlideTabW / EMU_PER_INCH).toFixed(1)}`)\n\t}\n\n\t// STEP 2: Resolve the rows and the grid they occupy, then take the column widths from the\n\t// first row that has any cells (others may have colspans, who cares, we only need col widths from 1).\n\t// Two bases are collected in the same pass: the rendered `offsetWidth` (what a browser\n\t// reports) and the computed CSS `width` (the only width statement available where nothing\n\t// laid the table out). `pickColWidthBasis` decides which one STEP 3 runs on.\n\tconst domRows = collectTableRows(ctx.table)\n\t// Each cell's spans, read once per conversion. The grid measure, the column widths and the cell\n\t// options all need them, and reading the attributes once is what makes those three agree and\n\t// reports a span past the ceiling once rather than once per reader.\n\tconst spansByCell = new Map<Element, { colspan: number; rowspan: number }>()\n\tconst spansOf = (cell: Element): { colspan: number; rowspan: number } => {\n\t\tlet spans = spansByCell.get(cell)\n\t\tif (!spans) {\n\t\t\tspans = {\n\t\t\t\tcolspan: gridSpan(cell.getAttribute('colspan'), 'colspan'),\n\t\t\t\trowspan: gridSpan(cell.getAttribute('rowspan'), 'rowspan'),\n\t\t\t}\n\t\t\tspansByCell.set(cell, spans)\n\t\t}\n\t\treturn spans\n\t}\n\tconst { columns: intColCnt, filled: arrRowFilled } = measureGridColumns(\n\t\tdomRows.map(({ row }) => rowCells(row).map(spansOf))\n\t)\n\t// A table with no rows — or only empty ones — has nothing to convert. Say so here: the failure\n\t// used to surface far downstream as `Reduce of empty array with no initial value` out of the\n\t// auto-pager, or as `addTable: Array expected!`, neither of which names the table.\n\tconst srcRow = domRows.find(({ row }) => rowCells(row).length > 0)\n\tif (!srcRow) {\n\t\tthrow new InvalidOptionError(\n\t\t\t'html/table-has-no-cells',\n\t\t\t'tableToSlides: the table has no cells to convert - expected at least one <tr> with a <td>/<th>.'\n\t\t)\n\t}\n\n\t// Per grid column, the width-source cell it came from and that cell's colspan. Built here so\n\t// STEP 3 can read a column's overrides off the *right* cell: with a colspan in play, column\n\t// index and cell index part ways, and indexing the row by column silently applied one cell's\n\t// `data-pptx-width` to the next column along (upstream gitbrent/PptxGenJS#1244).\n\tconst arrColSrc: Array<{ cell: HTMLTableCellElement; span: number }> = []\n\tconst arrCellSpans: number[] = []\n\trowCells(srcRow.row).forEach((cell) => {\n\t\tconst offsetW = Number(cell.offsetWidth)\n\t\tconst measured = Number.isFinite(offsetW) ? offsetW : 0\n\t\tarrTabColCssW.push(ctx.getComputedStyle(cell).getPropertyValue('width'))\n\t\t// Guesstimate (divide evenly) col widths across a spanned cell.\n\t\t// NOTE: both j$query and vanilla selectors return {0} when table is not visible)\n\t\tconst span = spansOf(cell).colspan\n\t\tarrCellSpans.push(span)\n\t\tfor (let idxc = 0; idxc < span; idxc++) {\n\t\t\tarrTabColW.push(Math.round(measured / span))\n\t\t\tarrColSrc.push({ cell, span })\n\t\t}\n\t})\n\n\t// The CSS basis is parsed per *cell* (unit uniformity is a property of the row as authored),\n\t// then expanded across each cell's colspan the same way `offsetWidth` is.\n\tconst parsedCellCssW = parseCssWidthBasis(arrTabColCssW)\n\tconst arrCssColW: number[] = []\n\tif (parsedCellCssW.length === arrCellSpans.length) {\n\t\tparsedCellCssW.forEach((cssW, idxC) => {\n\t\t\tconst span = arrCellSpans[idxC] ?? 1\n\t\t\tfor (let idxc = 0; idxc < span; idxc++) arrCssColW.push(cssW / span)\n\t\t})\n\t}\n\n\t// The width-source row can be narrower than the grid (one spanning header over a wider body),\n\t// so widen the basis to the full grid before the proportional calc — that way the calc still\n\t// divides the slide across *every* column instead of overflowing it by the missing ones.\n\tconst arrBasisColW = extendColBasis(pickColWidthBasis(arrTabColW, arrCssColW), intColCnt)\n\tarrBasisColW.forEach((colW) => {\n\t\tintTabW += colW\n\t})\n\n\t// STEP 3: Calc/Set column widths by using same column width percent from HTML table\n\tarrBasisColW.forEach((colW, idxW) => {\n\t\tconst intCalcWidth = Number(((Number(emuSlideTabW) * ((colW / intTabW) * 100)) / 100 / EMU_PER_INCH).toFixed(2))\n\t\t// A `data-pptx-width` on a spanning cell states that *cell's* width, so it divides across\n\t\t// the columns the cell covers — exactly as its `offsetWidth` and its CSS width do above.\n\t\t// A column past the source row's reach has no cell to be overridden by.\n\t\tconst src = arrColSrc[idxW]\n\t\tconst intSetWidth = src ? Number(src.cell.getAttribute('data-pptx-width')) / src.span : 0\n\t\tconst intMinWidth = src ? Number(src.cell.getAttribute('data-pptx-min-width')) / src.span : 0\n\t\tarrColW.push(resolveHtmlColWidth(intCalcWidth, intSetWidth, intMinWidth))\n\t})\n\tif (opts.verbose) {\n\t\tconsole.log(`| arrColW ......................................... = [${arrColW.join(', ')}]`)\n\t}\n\n\t// STEP 4: Iterate over each table element and create data arrays (text and opts)\n\t// NOTE: We create 3 arrays instead of one so we can loop over body then show header/footer rows on first and last page\n\tdomRows.forEach(({ row, part }, idxRow) => {\n\t\tconst arrObjTabCells: TableCellInternal[] = []\n\t\trowCells(row).forEach((cell) => {\n\t\t\t// The computed style is read a dozen times below; resolve it once per cell.\n\t\t\tconst style = ctx.getComputedStyle(cell)\n\n\t\t\t// A: Get text/bkgd colors\n\t\t\t// NOTE: an unparseable or fully transparent background is the default for an\n\t\t\t// unstyled table; pptx has no \"transparent\" solid fill, so use white instead.\n\t\t\tconst textColor = cssColorToHex(style.getPropertyValue('color')) ?? '000000'\n\t\t\tconst fillColor = cssColorToHex(style.getPropertyValue('background-color')) ?? 'FFFFFF'\n\n\t\t\t// B: Create option object\n\t\t\tconst cellOpts: TableCellProps = {\n\t\t\t\tbold: !!(\n\t\t\t\t\tstyle.getPropertyValue('font-weight') === 'bold' || Number(style.getPropertyValue('font-weight')) >= 500\n\t\t\t\t),\n\t\t\t\tcolor: textColor,\n\t\t\t\tfill: { color: fillColor },\n\t\t\t}\n\t\t\t// A relative or keyword font size has no absolute magnitude here, so the key stays off\n\t\t\t// the cell and the size inherits, rather than arriving as `NaN` in `sz`.\n\t\t\tconst fontSizePt = htmlCssPxToPoints(style.getPropertyValue('font-size'))\n\t\t\tif (Number.isFinite(fontSizePt)) cellOpts.fontSize = fontSizePt\n\t\t\tconst fontFace = ((style.getPropertyValue('font-family') || '').split(',')[0] ?? '')\n\t\t\t\t.replace(/\"/g, '')\n\t\t\t\t.replace('inherit', '')\n\t\t\t\t.replace('initial', '')\n\t\t\t// The same spans the grid walk measured, so what is emitted and what was measured cannot\n\t\t\t// disagree: a `colspan=\"-2\"` counted as one column above must not reach the table\n\t\t\t// definition as `-2` and corrupt its own column count.\n\t\t\tconst { colspan, rowspan } = spansOf(cell)\n\t\t\tif (fontFace) cellOpts.fontFace = fontFace\n\t\t\tif (colspan > 1) cellOpts.colspan = colspan\n\t\t\tif (rowspan > 1) cellOpts.rowspan = rowspan\n\n\t\t\t// A CSS value this table has no spelling for leaves the key off rather than writing an\n\t\t\t// `undefined` into it, so the cell keeps whatever alignment it inherits. The guard and\n\t\t\t// the ternary chain they replace could not disagree, but only because every value the\n\t\t\t// guard admitted had an arm — the `: undefined` tail was unreachable, and a sixth CSS\n\t\t\t// value added to one list and not the other would have made it reachable and silent.\n\t\t\tconst align = CSS_TEXT_ALIGN[style.getPropertyValue('text-align')]\n\t\t\tif (align) cellOpts.align = align\n\t\t\tconst valign = CSS_VERTICAL_ALIGN[style.getPropertyValue('vertical-align')]\n\t\t\tif (valign) cellOpts.valign = valign\n\n\t\t\t// C: Add padding [margin] (if any)\n\t\t\t// NOTE: `TableCellProps.margin` is INCHES, so computed px must be converted, not copied.\n\t\t\t// CSS defines the reference pixel as 1/96in, and mirroring what the browser rendered is\n\t\t\t// this conversion's whole job — so resolve at `DEFAULT_PX_PER_INCH`, the same density the\n\t\t\t// `\"<n>px\"` coordinate unit uses. (Until 2026-07-31 the px magnitude was assigned straight\n\t\t\t// through under a stale \"px->pt 1:1\" note left from when cell margin was points; that made\n\t\t\t// a 4px pad a *4 inch* inset and tripped the legacy-points warning on any pad >= 1px.)\n\t\t\t// No rounding to whole px: the browser's computed value can be fractional, and `inch2Emu`\n\t\t\t// already does the one rounding that matters, at EMU precision.\n\t\t\tif (style.getPropertyValue('padding-left')) {\n\t\t\t\tconst cellMargin: MarginTuple = [0, 0, 0, 0]\n\t\t\t\tconst sidesPad = ['padding-top', 'padding-right', 'padding-bottom', 'padding-left']\n\t\t\t\tsidesPad.forEach((val, idxs) => {\n\t\t\t\t\t// Anything that is not an absolute px length (a `%` padding, a keyword) has no\n\t\t\t\t\t// meaning as a fixed inset, so it insets by nothing rather than by its digits.\n\t\t\t\t\tconst pad = parseCssPx(style.getPropertyValue(val))\n\t\t\t\t\tcellMargin[idxs] = Number.isFinite(pad) ? pad / DEFAULT_PX_PER_INCH : 0\n\t\t\t\t})\n\t\t\t\tcellOpts.margin = cellMargin\n\t\t\t}\n\n\t\t\t// D: Add border (if any)\n\t\t\tif (\n\t\t\t\tstyle.getPropertyValue('border-top-width') ||\n\t\t\t\tstyle.getPropertyValue('border-right-width') ||\n\t\t\t\tstyle.getPropertyValue('border-bottom-width') ||\n\t\t\t\tstyle.getPropertyValue('border-left-width')\n\t\t\t) {\n\t\t\t\tconst cellBorder: BorderTuple = [{ type: 'none' }, { type: 'none' }, { type: 'none' }, { type: 'none' }]\n\t\t\t\tconst sidesBor = ['top', 'right', 'bottom', 'left']\n\t\t\t\tsidesBor.forEach((val, idxb) => {\n\t\t\t\t\tcellBorder[idxb] = htmlBorderToProps(\n\t\t\t\t\t\tstyle.getPropertyValue('border-' + val + '-width'),\n\t\t\t\t\t\tstyle.getPropertyValue('border-' + val + '-color')\n\t\t\t\t\t)\n\t\t\t\t})\n\t\t\t\tcellOpts.border = cellBorder\n\t\t\t}\n\n\t\t\t// LAST: Add cell\n\t\t\tarrObjTabCells.push({\n\t\t\t\t_type: SlideObjectType.tablecell,\n\t\t\t\ttext: readCellText(cell), // <br> must survive as \"\\n\", so linebreak etc. work later!\n\t\t\t\toptions: cellOpts,\n\t\t\t})\n\t\t})\n\n\t\t// Normalize a ragged row up to the grid width. HTML tolerates a short row and just leaves\n\t\t// the tail of the grid empty; pptx does not — `<a:tblGrid>` declares the column count and a\n\t\t// row with fewer `<a:tc>` is a malformed table PowerPoint has to repair. The missing cells\n\t\t// are blank rather than a copy of a neighbour: the source table never stated them, so there\n\t\t// is nothing to carry over. Columns held by a `rowspan` from above are already counted as\n\t\t// filled — the table emitter synthesizes those merge cells itself.\n\t\tfor (let idxPad = arrRowFilled[idxRow] ?? 0; idxPad < intColCnt; idxPad++) {\n\t\t\tarrObjTabCells.push({ _type: SlideObjectType.tablecell, text: '', options: {} })\n\t\t}\n\n\t\tif (part === 'thead') arrObjTabHeadRows.push(arrObjTabCells)\n\t\telse if (part === 'tfoot') arrObjTabFootRows.push(arrObjTabCells)\n\t\telse arrObjTabBodyRows.push(arrObjTabCells)\n\t})\n\n\t// STEP 5: Break table into Slides as needed\n\t// Pass head-rows as there is an option to add to each table and the parse func needs this data to fulfill that option\n\topts._arrObjTabHeadRows = arrObjTabHeadRows\n\topts.colW = arrColW\n\tgetSlidesForTableRows(\n\t\t[...arrObjTabHeadRows, ...arrObjTabBodyRows, ...arrObjTabFootRows],\n\t\topts,\n\t\tpptx.presLayout,\n\t\tmasterSlide\n\t).forEach((slide) => {\n\t\t// A: Create new Slide\n\t\tconst newSlide = pptx.addSlide(opts.masterTitle ? { masterTitle: opts.masterTitle } : {})\n\n\t\t// B: DESIGN: Reset `y` to startY or margin after first Slide.\n\t\t// Every page goes where the pager started it when it budgeted the page's height\n\t\t// (`slide.y`). This used to restate that rule, and the copy had drifted three times:\n\t\t// `autoPageSlideStartY: 0` read as unset, a `y` above the top margin was pushed back down,\n\t\t// and a first page stated at `y: 0` was moved down to the margin.\n\t\tif (slide.y !== undefined) opts.y = slide.y\n\t\tif (opts.verbose)\n\t\t\tconsole.log(\n\t\t\t\t`| opts.autoPageSlideStartY: ${opts.autoPageSlideStartY} / arrInchMargins[0]: ${arrInchMargins[0]} => opts.y = ${opts.y}`\n\t\t\t)\n\n\t\t// C: Add table to Slide\n\t\tconst slideTableProps: TableProps = {\n\t\t\t// `??`: a stated `x: 0` is the left edge of the slide, not a missing `x`.\n\t\t\tx: opts.x ?? arrInchMargins[3],\n\t\t\tw: Number(emuSlideTabW) / EMU_PER_INCH,\n\t\t\tcolW: arrColW,\n\t\t\tautoPage: false,\n\t\t}\n\t\t// `y` is set on `opts` a few lines up on every branch, but only where the caller stated one\n\t\t// does it belong on the table's own props — an absent `y` is what lets `addTable` apply its\n\t\t// own default.\n\t\tif (opts.y !== undefined) slideTableProps.y = opts.y\n\t\tnewSlide.addTable(slide.rows, slideTableProps)\n\n\t\t// D: Add any additional objects\n\t\tif (opts.addImage) {\n\t\t\topts.addImage.options = opts.addImage.options || {}\n\t\t\tif (!opts.addImage.image || (!opts.addImage.image.path && !opts.addImage.image.data)) {\n\t\t\t\twarn('html/image-missing-source', 'tableToSlides.addImage requires either `path` or `data`')\n\t\t\t} else {\n\t\t\t\tconst imageProps = opts.addImage.image.path\n\t\t\t\t\t? { path: opts.addImage.image.path }\n\t\t\t\t\t: { data: opts.addImage.image.data as string }\n\t\t\t\t// Geometry is copied only where the caller stated it, so an omitted axis keeps\n\t\t\t\t// `addImage`'s own default rather than arriving as an explicit `undefined`.\n\t\t\t\tconst imageOptions = opts.addImage.options\n\t\t\t\tconst geometry: PositionProps = {}\n\t\t\t\tif (imageOptions.x !== undefined) geometry.x = imageOptions.x\n\t\t\t\tif (imageOptions.y !== undefined) geometry.y = imageOptions.y\n\t\t\t\tif (imageOptions.w !== undefined) geometry.w = imageOptions.w\n\t\t\t\tif (imageOptions.h !== undefined) geometry.h = imageOptions.h\n\t\t\t\tnewSlide.addImage({ ...imageProps, ...geometry })\n\t\t\t}\n\t\t}\n\t\tif (opts.addShape) newSlide.addShape(opts.addShape.shapeName, opts.addShape.options || {})\n\t\tif (opts.addTable) newSlide.addTable(opts.addTable.rows, opts.addTable.options || {})\n\t\tif (opts.addText) newSlide.addText(opts.addText.text, opts.addText.options || {})\n\t})\n}\n"],"mappings":"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"}
|