reamkit 1.22.0 → 1.23.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.
Files changed (72) hide show
  1. package/dist/esm/core/converter/ream.d.ts +16 -0
  2. package/dist/esm/core/converter/ream.js +59 -9
  3. package/dist/esm/core/document-model/types.d.ts +18 -0
  4. package/dist/esm/core/drawingml/chart-geometry.js +11 -5
  5. package/dist/esm/core/drawingml/colors.d.ts +4 -2
  6. package/dist/esm/core/drawingml/colors.js +15 -0
  7. package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
  8. package/dist/esm/core/drawingml/theme-parser.js +64 -1
  9. package/dist/esm/core/fonts/families.d.ts +10 -0
  10. package/dist/esm/core/fonts/families.js +44 -0
  11. package/dist/esm/core/fonts/index.d.ts +3 -2
  12. package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
  13. package/dist/esm/core/fonts/remote-fonts.js +114 -8
  14. package/dist/esm/core/fonts/scripts.d.ts +26 -0
  15. package/dist/esm/core/fonts/scripts.js +177 -0
  16. package/dist/esm/core/metafile/blit.d.ts +33 -0
  17. package/dist/esm/core/metafile/blit.js +67 -0
  18. package/dist/esm/core/metafile/dib.d.ts +61 -0
  19. package/dist/esm/core/metafile/dib.js +205 -0
  20. package/dist/esm/core/metafile/emf.js +137 -23
  21. package/dist/esm/core/metafile/picture.d.ts +12 -1
  22. package/dist/esm/core/metafile/wmf.js +149 -9
  23. package/dist/esm/core/ole/escher-blip.d.ts +12 -0
  24. package/dist/esm/core/ole/escher-blip.js +88 -0
  25. package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
  26. package/dist/esm/excel/print-model.js +3 -1
  27. package/dist/esm/excel/styles-parser.js +1 -1
  28. package/dist/esm/excel/xls/biff-reader.js +53 -18
  29. package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
  30. package/dist/esm/excel/xls/biff-styles.js +9 -7
  31. package/dist/esm/excel/xls/escher.js +90 -24
  32. package/dist/esm/layout/page-doc.d.ts +39 -0
  33. package/dist/esm/layout/styled-layout.d.ts +2 -2
  34. package/dist/esm/layout/styled-layout.js +301 -35
  35. package/dist/esm/pdf/styled-page-emitter.js +35 -2
  36. package/dist/esm/pdf-reader/image-decode.js +1 -1
  37. package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
  38. package/dist/esm/pptx/embedded-fonts.js +104 -0
  39. package/dist/esm/pptx/placeholder-cascade.d.ts +73 -6
  40. package/dist/esm/pptx/placeholder-cascade.js +114 -18
  41. package/dist/esm/pptx/ppt/ppt-reader.js +120 -10
  42. package/dist/esm/pptx/ppt/ppt-text.d.ts +66 -1
  43. package/dist/esm/pptx/ppt/ppt-text.js +576 -137
  44. package/dist/esm/pptx/pptx-reader.d.ts +8 -0
  45. package/dist/esm/pptx/pptx-reader.js +27 -5
  46. package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
  47. package/dist/esm/pptx/preset-table-styles.js +27 -0
  48. package/dist/esm/pptx/slide-parser.d.ts +7 -1
  49. package/dist/esm/pptx/slide-parser.js +106 -33
  50. package/dist/esm/pptx/sp-helpers.d.ts +2 -1
  51. package/dist/esm/pptx/sp-helpers.js +3 -2
  52. package/dist/esm/pptx/table-style.d.ts +9 -1
  53. package/dist/esm/pptx/table-style.js +49 -7
  54. package/dist/esm/word/document-parser.d.ts +7 -1
  55. package/dist/esm/word/document-parser.js +6 -6
  56. package/dist/esm/word/docx-reader.js +6 -3
  57. package/dist/esm/word/docx-to-pdf.d.ts +8 -7
  58. package/dist/esm/word/docx-to-pdf.js +25 -7
  59. package/dist/esm/word/drawing-parser.js +31 -19
  60. package/dist/esm/word/numbering-parser.d.ts +2 -1
  61. package/dist/esm/word/numbering-parser.js +6 -6
  62. package/dist/esm/word/paragraph-properties.d.ts +2 -1
  63. package/dist/esm/word/paragraph-properties.js +2 -2
  64. package/dist/esm/word/run-properties.d.ts +5 -2
  65. package/dist/esm/word/run-properties.js +13 -8
  66. package/dist/esm/word/styles-parser.d.ts +2 -1
  67. package/dist/esm/word/styles-parser.js +12 -12
  68. package/dist/esm/word/table-parser.js +3 -3
  69. package/dist/esm/word/theme-fonts.d.ts +10 -0
  70. package/dist/esm/word/theme-fonts.js +28 -0
  71. package/package.json +1 -1
  72. /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
@@ -17,6 +17,14 @@ export declare function readPptx(bytes: Uint8Array): ReadResult<FlowDoc>;
17
17
  * Parse an OOXML part's bytes into preserve-order {@link PoNode} roots with the
18
18
  * module's shared, presentation-tuned {@link XMLParser} (attributes kept, values
19
19
  * not coerced, whitespace preserved). Shared with the slide-style resolvers.
20
+ *
21
+ * ISO/IEC 29500-3 §10.2 — `mc:AlternateContent` is resolved first, to the
22
+ * `mc:Fallback` a reader takes when it implements none of the namespaces the
23
+ * choices require. A deck writes the same shape twice this way, and reading the
24
+ * CHOICE means reading markup written for someone else: tdf143222's whole slide
25
+ * is an embedded worksheet whose preview picture lives in the fallback alone,
26
+ * and the choice — written for VML — carries no picture at all, so the slide
27
+ * came out blank. 82 of the corpus's decks carry such a block.
20
28
  */
21
29
  export declare function parseXml(data: Uint8Array): Array<PoNode>;
22
30
  /**
@@ -7,9 +7,12 @@ import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs } from "../core/p
7
7
  import { packageHasPart } from "../core/bytes.js";
8
8
  import { DEFAULT_SCHEME_ALIAS, DEFAULT_THEME_PALETTE, defaultColorResolver, makeColorResolver } from "../core/drawingml/colors.js";
9
9
  import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
10
- import { parseTheme, parseThemeBgFillStyles, parseThemeFillStyles, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
10
+ import { parseTheme, parseThemeBgFillStyles, parseThemeFillStyles, parseThemeFonts, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
11
11
  import { OpcPackage } from "../core/opc/package.js";
12
12
  import "../core/opc/index.js";
13
+ import { loadPptxEmbeddedFonts } from "./embedded-fonts.js";
14
+ import { presetTableStyle } from "./preset-table-styles.js";
15
+ import { resolveAlternateContent } from "../core/opc/alternate-content.js";
13
16
  import { buildPlaceholderCascade, parseLevelStyles } from "./placeholder-cascade.js";
14
17
  import { normalizeSpid, parseVmlImageRels } from "./ole-preview.js";
15
18
  import { asBackdrop, backdropElement, parseBackgroundFill, parseSlideShapes } from "./slide-parser.js";
@@ -19,6 +22,7 @@ var EMU_PER_PT = 12700;
19
22
  var DEFAULT_CX = 9144e3;
20
23
  var DEFAULT_CY = 6858e3;
21
24
  var decoder = new TextDecoder();
25
+ var encoder = new TextEncoder();
22
26
  var parser = new XMLParser({
23
27
  htmlEntities: true,
24
28
  ignoreAttributes: false,
@@ -55,9 +59,11 @@ function readPptx(bytes) {
55
59
  let cx = DEFAULT_CX;
56
60
  let cy = DEFAULT_CY;
57
61
  let defaultTextStyle;
62
+ let embeddedFonts = /* @__PURE__ */ new Map();
58
63
  const slideParts = [];
59
64
  if (presData) {
60
65
  const pres = parser.parse(decoder.decode(presData)).find((n) => poIs(n, "p:presentation"));
66
+ embeddedFonts = loadPptxEmbeddedFonts(pkg, presPath, pres, (loss) => losses.push(loss));
61
67
  const kids = pres ? poChildren(pres) : [];
62
68
  defaultTextStyle = kids.find((c) => poIs(c, "p:defaultTextStyle"));
63
69
  const sldSz = kids.find((c) => poIs(c, "p:sldSz"));
@@ -123,6 +129,7 @@ function readPptx(bytes) {
123
129
  widthPt: pageW,
124
130
  heightPt: pageH
125
131
  },
132
+ ...styles.themeFonts ? { themeFonts: styles.themeFonts } : {},
126
133
  ...styles.themeFills ? { themeFills: styles.themeFills } : {},
127
134
  ...styles.themeLineWidths ? { themeLineWidths: styles.themeLineWidths } : {},
128
135
  resolveImage: makeSlideImageResolver(pkg, part.path, resources),
@@ -162,7 +169,8 @@ function readPptx(bytes) {
162
169
  section,
163
170
  styles: EMPTY_STYLE_SHEET,
164
171
  resources,
165
- ...charts.size > 0 ? { charts } : {}
172
+ ...charts.size > 0 ? { charts } : {},
173
+ ...embeddedFonts.size > 0 ? { embeddedFonts } : {}
166
174
  },
167
175
  losses
168
176
  };
@@ -171,9 +179,17 @@ function readPptx(bytes) {
171
179
  * Parse an OOXML part's bytes into preserve-order {@link PoNode} roots with the
172
180
  * module's shared, presentation-tuned {@link XMLParser} (attributes kept, values
173
181
  * not coerced, whitespace preserved). Shared with the slide-style resolvers.
182
+ *
183
+ * ISO/IEC 29500-3 §10.2 — `mc:AlternateContent` is resolved first, to the
184
+ * `mc:Fallback` a reader takes when it implements none of the namespaces the
185
+ * choices require. A deck writes the same shape twice this way, and reading the
186
+ * CHOICE means reading markup written for someone else: tdf143222's whole slide
187
+ * is an embedded worksheet whose preview picture lives in the fallback alone,
188
+ * and the choice — written for VML — carries no picture at all, so the slide
189
+ * came out blank. 82 of the corpus's decks carry such a block.
174
190
  */
175
191
  function parseXml(data) {
176
- return parser.parse(decoder.decode(data));
192
+ return parser.parse(resolveAlternateContent(decoder.decode(data)));
177
193
  }
178
194
  function parseSlide(tree, ctx, inheritedBg, pageW, pageH, inheritedShapes = []) {
179
195
  const sld = tree.find((n) => poIs(n, "p:sld"));
@@ -247,6 +263,9 @@ function makeOlePreviewResolver(pkg, slidePath, resources) {
247
263
  * table that names none wears none — table-with-no-theme's two rows are bare
248
264
  * text in a plain frame, not the blue banding `@def` points at.
249
265
  *
266
+ * A GUID the part does not hold may still be one of the GALLERY's own, which
267
+ * every deck names and none ships (see `preset-table-styles`).
268
+ *
250
269
  * The part is read once, on the first table in the deck.
251
270
  */
252
271
  function makeTableStyleResolver(pkg, presPath) {
@@ -265,7 +284,8 @@ function makeTableStyleResolver(pkg, presPath) {
265
284
  }
266
285
  }
267
286
  }
268
- return styleId === void 0 ? void 0 : byId.get(styleId);
287
+ if (styleId === void 0) return void 0;
288
+ return byId.get(styleId) ?? presetTableStyle(styleId, (xml) => parseXml(encoder.encode(xml)));
269
289
  };
270
290
  }
271
291
  function makeHyperlinkResolver(pkg, slidePath) {
@@ -358,7 +378,8 @@ function slideStylesFor(pkg, slidePath, cache, resources, charts, onLoss, deckDe
358
378
  resolveImage: makeSlideImageResolver(pkg, theme.path, resources)
359
379
  } : void 0;
360
380
  const themeLineWidths = theme ? parseThemeLineWidths(theme.data) : void 0;
361
- const cascade = buildPlaceholderCascade(layoutTree, masterTree, colors, parseLevelStyles(deckDefaultTextStyle, colors));
381
+ const themeFonts = theme ? parseThemeFonts(theme.data) : void 0;
382
+ const cascade = buildPlaceholderCascade(layoutTree, masterTree, colors, parseLevelStyles(deckDefaultTextStyle, colors, themeFonts), themeFonts);
362
383
  const background = partBackground(layoutTree, "p:sldLayout", inheritedColors, makeSlideImageResolver(pkg, layout.path, resources), themeFills) ?? (masterTree && master ? partBackground(masterTree, "p:sldMaster", inheritedColors, makeSlideImageResolver(pkg, master.path, resources), themeFills) : void 0);
363
384
  const deps = {
364
385
  colors: inheritedColors,
@@ -376,6 +397,7 @@ function slideStylesFor(pkg, slidePath, cache, resources, charts, onLoss, deckDe
376
397
  const styles = {
377
398
  cascade,
378
399
  colors,
400
+ ...themeFonts ? { themeFonts } : {},
379
401
  ...themeFills ? { themeFills } : {},
380
402
  ...themeLineWidths && themeLineWidths.length > 0 ? { themeLineWidths } : {},
381
403
  ...background ? { background } : {},
@@ -0,0 +1,9 @@
1
+ import { PoNode } from '../core/po-helpers.js';
2
+ /**
3
+ * The built-in table style a GUID names, or `undefined` when it is not one this
4
+ * reader holds.
5
+ *
6
+ * @param styleId The `a:tableStyleId` a table states.
7
+ * @param parse The module's XML reader, injected so this file needs none.
8
+ */
9
+ export declare function presetTableStyle(styleId: string, parse: (xml: string) => ReadonlyArray<PoNode>): PoNode | undefined;
@@ -0,0 +1,27 @@
1
+ import { poAttr, poIs } from "../core/po-helpers.js";
2
+ //#region src/pptx/preset-table-styles.ts
3
+ /** The gallery styles this reader knows, by the GUID a table names. */
4
+ var PRESETS = new Map([
5
+ ["{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}", "<a:tblStyle styleId=\"{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}\" styleName=\"Medium Style 2 - Accent 1\"><a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"accent1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"accent1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band2H><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"accent1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:band2V><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2V><a:lastCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"accent1\"/></a:solidFill></a:fill></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"accent1\"/></a:solidFill></a:fill></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:top><a:ln w=\"38100\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"accent1\"/></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"38100\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"accent1\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow></a:tblStyle>"],
6
+ ["{073A0DAA-6AF3-43AB-8588-CEC1D06C72B9}", "<a:tblStyle styleId=\"{073A0DAA-6AF3-43AB-8588-CEC1D06C72B9}\" styleName=\"Medium Style 2\"><a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"dk1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:insideV></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"20000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:wholeTbl><a:band1H><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1H><a:band2H><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2H><a:band1V><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"><a:tint val=\"40000\"/></a:schemeClr></a:solidFill></a:fill></a:tcStyle></a:band1V><a:band2V><a:tcStyle><a:tcBdr/></a:tcStyle></a:band2V><a:lastCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:lastCol><a:firstCol><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr/><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:firstCol><a:lastRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:top><a:ln w=\"38100\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:top></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:lastRow><a:firstRow><a:tcTxStyle b=\"on\"><a:fontRef idx=\"minor\"><a:prstClr val=\"black\"/></a:fontRef><a:schemeClr val=\"lt1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:bottom><a:ln w=\"38100\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"lt1\"/></a:solidFill></a:ln></a:bottom></a:tcBdr><a:fill><a:solidFill><a:schemeClr val=\"dk1\"/></a:solidFill></a:fill></a:tcStyle></a:firstRow></a:tblStyle>"],
7
+ ["{5940675A-B579-460E-94D1-54222C63F5DA}", "<a:tblStyle styleId=\"{5940675A-B579-460E-94D1-54222C63F5DA}\" styleName=\"No Style, Table Grid\"><a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"tx1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:left><a:right><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:right><a:top><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:top><a:bottom><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:bottom><a:insideH><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:insideH><a:insideV><a:ln w=\"12700\" cmpd=\"sng\"><a:solidFill><a:schemeClr val=\"tx1\"/></a:solidFill></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl></a:tblStyle>"],
8
+ ["{2D5ABB26-0587-4C30-8999-92F81FD0307C}", "<a:tblStyle styleId=\"{2D5ABB26-0587-4C30-8999-92F81FD0307C}\" styleName=\"No Style, No Grid\"><a:wholeTbl><a:tcTxStyle><a:fontRef idx=\"minor\"><a:scrgbClr r=\"0\" g=\"0\" b=\"0\"/></a:fontRef><a:schemeClr val=\"tx1\"/></a:tcTxStyle><a:tcStyle><a:tcBdr><a:left><a:ln><a:noFill/></a:ln></a:left><a:right><a:ln><a:noFill/></a:ln></a:right><a:top><a:ln><a:noFill/></a:ln></a:top><a:bottom><a:ln><a:noFill/></a:ln></a:bottom><a:insideH><a:ln><a:noFill/></a:ln></a:insideH><a:insideV><a:ln><a:noFill/></a:ln></a:insideV></a:tcBdr><a:fill><a:noFill/></a:fill></a:tcStyle></a:wholeTbl></a:tblStyle>"]
9
+ ]);
10
+ var parsed = /* @__PURE__ */ new Map();
11
+ /**
12
+ * The built-in table style a GUID names, or `undefined` when it is not one this
13
+ * reader holds.
14
+ *
15
+ * @param styleId The `a:tableStyleId` a table states.
16
+ * @param parse The module's XML reader, injected so this file needs none.
17
+ */
18
+ function presetTableStyle(styleId, parse) {
19
+ const seen = parsed.get(styleId);
20
+ if (seen !== void 0 || parsed.has(styleId)) return seen;
21
+ const xml = PRESETS.get(styleId);
22
+ const style = xml ? parse(xml).find((n) => poIs(n, "a:tblStyle") && poAttr(n, "styleId") === styleId) : void 0;
23
+ parsed.set(styleId, style);
24
+ return style;
25
+ }
26
+ //#endregion
27
+ export { presetTableStyle };
@@ -1,5 +1,6 @@
1
1
  import { BodyElement, FloatAnchor, ShapeBlock, ShapeFill, ShapeGeometry, ShapeTextBody } from '../core/document-model/index.js';
2
2
  import { ColorResolver } from '../core/drawingml/colors.js';
3
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
3
4
  import { Loss, Pt, ResourceId } from '../core/ir/index.js';
4
5
  import { PoNode } from '../core/po-helpers.js';
5
6
  import { PlaceholderCascade } from './placeholder-cascade.js';
@@ -17,6 +18,11 @@ export interface SlideContext {
17
18
  readonly resolveImage?: (relId: string) => ResourceId | undefined;
18
19
  /** The deck theme's fill style lists, for a `p:bgRef` on this slide. */
19
20
  readonly themeFills?: ThemeFillStyles;
21
+ /**
22
+ * §20.1.4.1.16 — the two typefaces the deck's theme names. A run states its
23
+ * own by TOKEN (`+mn-lt`) more often than by name.
24
+ */
25
+ readonly themeFonts?: ThemeFonts;
20
26
  /** §20.1.4.1.21 `a:lnStyleLst` — the widths an `a:lnRef` indexes, in points. */
21
27
  readonly themeLineWidths?: ReadonlyArray<number>;
22
28
  /**
@@ -203,5 +209,5 @@ export declare function parseGeometry(spPr: PoNode | undefined): ShapeGeometry;
203
209
  * @param resolveLink A run hyperlink resolver, or `undefined`.
204
210
  * @returns The text body, or `undefined` when it holds no paragraphs.
205
211
  */
206
- export declare function parseTxBody(txBody: PoNode, ph: PlaceholderRef | undefined, cascade: PlaceholderCascade | undefined, colors: ColorResolver, resolveLink: LinkResolver, styleColor?: string): ShapeTextBody | undefined;
212
+ export declare function parseTxBody(txBody: PoNode, ph: PlaceholderRef | undefined, cascade: PlaceholderCascade | undefined, colors: ColorResolver, resolveLink: LinkResolver, styleColor?: string, themeFonts?: ThemeFonts): ShapeTextBody | undefined;
207
213
  export {};
@@ -3,7 +3,7 @@ import { FEATURES } from "../core/ir/features.js";
3
3
  import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
4
4
  import { defaultColorResolver, placeholderColors, resolveColorNode } from "../core/drawingml/colors.js";
5
5
  import { boxFromXfrm, parsePh, parseXfrmBox, rPrToRunProps } from "./sp-helpers.js";
6
- import { parseBullet } from "./placeholder-cascade.js";
6
+ import { lineSpacing, parseBullet, spacingFractions, spacingFromLineFraction } from "./placeholder-cascade.js";
7
7
  import { colorChangeOf, parseCustGeom, parseFill, parseLine, parsePrstGeom, parseShadow, parseXfrm, statesFill, styleRefFill, styleRefFontColor, styleRefLine } from "../word/drawing-parser.js";
8
8
  import { cellStyle, lineBorder, tableStyleFlags, tableStyleId, withCellStyle, withoutFill } from "./table-style.js";
9
9
  //#region src/pptx/slide-parser.ts
@@ -116,19 +116,25 @@ function parseSp(sp, ctx, transform) {
116
116
  const style = poChildren(sp).find((c) => poIs(c, "p:style"));
117
117
  const txBody = poChildren(sp).find((c) => poIs(c, "p:txBody"));
118
118
  const styleColor = style ? styleRefFontColor(style, colors) : void 0;
119
- const text = txBody ? parseTxBody(txBody, ph, ctx.cascade, colors, ctx.resolveHyperlink, styleColor) : void 0;
120
- const proto = ph && ctx.cascade ? ctx.cascade.shapePropsFor(ph) : void 0;
121
- const geometry = parseGeometry(spPr && statesGeometry(spPr) ? spPr : proto ?? spPr);
119
+ const text = txBody ? parseTxBody(txBody, ph, ctx.cascade, colors, ctx.resolveHyperlink, styleColor, ctx.themeFonts) : void 0;
120
+ const protos = ph && ctx.cascade ? ctx.cascade.shapePropsFor(ph) : [];
121
+ const from = (states) => spPr && states(spPr) ? spPr : protos.find(states) ?? spPr;
122
+ /** What the shape states ITSELF, before anything is inherited. */
123
+ const stated = (states) => spPr && states(spPr) ? spPr : void 0;
124
+ /** …and what a prototype lends it, nearest first. */
125
+ const lent = (states) => protos.find(states);
126
+ const geometry = parseGeometry(from(statesGeometry));
122
127
  const useBgFill = poAttr(sp, "useBgFill") === "1";
123
- const fillFrom = statesFill(spPr) ? spPr : proto ?? spPr;
124
- const fill = useBgFill ? backgroundThrough(ctx.backgroundFill, box, ctx.slideSize) : fillFrom ? parseFill(fillFrom, colors, ctx.resolveImage) : { kind: "none" };
125
- const lineFrom = spPr && poChildren(spPr).some((c) => poIs(c, "a:ln")) ? spPr : proto ?? spPr;
126
- let line = lineFrom ? parseLine(lineFrom, colors) : void 0;
127
128
  const themeStyles = ctx.themeFills ? {
128
129
  fills: ctx.themeFills.fills,
129
130
  bgFills: ctx.themeFills.backgrounds
130
131
  } : void 0;
131
- const styled = style && fill.kind === "none" && !statesFill(fillFrom) ? styleRefFill(style, colors, themeStyles) : fill;
132
+ const ownFill = stated(statesFill);
133
+ const styleFill = style ? styleRefFill(style, colors, themeStyles) : void 0;
134
+ const lentFill = lent(statesFill);
135
+ const styled = useBgFill ? backgroundThrough(ctx.backgroundFill, box, ctx.slideSize) : ownFill ? parseFill(ownFill, colors, ctx.resolveImage) : styleFill && styleFill.kind !== "none" ? styleFill : lentFill ? parseFill(lentFill, colors, ctx.resolveImage) : spPr ? parseFill(spPr, colors, ctx.resolveImage) : { kind: "none" };
136
+ const lineFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:ln")));
137
+ let line = lineFrom ? parseLine(lineFrom, colors) : void 0;
132
138
  if (style) {
133
139
  const fromStyle = styleRefLine(style, colors, ctx.themeLineWidths);
134
140
  if (fromStyle) line = line ? {
@@ -136,6 +142,8 @@ function parseSp(sp, ctx, transform) {
136
142
  ...Object.fromEntries(Object.entries(line).filter(([, v]) => v !== void 0))
137
143
  } : fromStyle;
138
144
  }
145
+ const shadowFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:effectLst")));
146
+ const shadow = shadowFrom ? parseShadow(shadowFrom, colors) : void 0;
139
147
  const visibleLine = line !== void 0 && line.fill !== "none";
140
148
  if (!text && styled.kind === "none" && !visibleLine) return void 0;
141
149
  const xfrm = spPr ? poChildren(spPr).find((c) => poIs(c, "a:xfrm")) : void 0;
@@ -147,6 +155,7 @@ function parseSp(sp, ctx, transform) {
147
155
  geometry,
148
156
  fill: styled,
149
157
  ...line ? { line } : {},
158
+ ...shadow ? { shadow } : {},
150
159
  ...spin && Object.keys(spin).length > 0 ? { transform: spin } : {},
151
160
  ...text ? { text } : {},
152
161
  paragraphProperties: {}
@@ -177,7 +186,10 @@ function parseGraphicFrame(gf, ctx, transform) {
177
186
  if (uri === TABLE_URI) {
178
187
  const tbl = poFindDescendant(gf, "a:tbl");
179
188
  if (!tbl) return [];
180
- const table = parseTable(tbl, ctx.colors ?? defaultColorResolver, ctx.resolveTableStyle);
189
+ const table = parseTable(tbl, ctx.colors ?? defaultColorResolver, ctx.resolveTableStyle, {
190
+ ...ctx.themeFills ? { fills: ctx.themeFills.fills } : {},
191
+ ...ctx.themeLineWidths ? { lineWidths: ctx.themeLineWidths } : {}
192
+ });
181
193
  return [{
182
194
  kind: "table",
183
195
  table: {
@@ -569,14 +581,14 @@ function picAltText(pic) {
569
581
  const title = cNvPr ? poAttr(cNvPr, "title") : void 0;
570
582
  return (descr ?? title)?.trim() || void 0;
571
583
  }
572
- function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor) {
584
+ function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts) {
573
585
  const content = [];
574
586
  const counters = [];
575
587
  for (const child of poChildren(txBody)) {
576
588
  if (!poIs(child, "a:p")) continue;
577
589
  content.push({
578
590
  kind: "paragraph",
579
- paragraph: parseSlideParagraph(child, ph, cascade, colors, resolveLink, counters, styleColor)
591
+ paragraph: parseSlideParagraph(child, ph, cascade, colors, resolveLink, counters, styleColor, themeFonts)
580
592
  });
581
593
  }
582
594
  return content;
@@ -594,10 +606,11 @@ function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor)
594
606
  * @param resolveLink A run hyperlink resolver, or `undefined`.
595
607
  * @returns The text body, or `undefined` when it holds no paragraphs.
596
608
  */
597
- function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor) {
598
- const content = txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor);
609
+ function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts) {
610
+ const content = txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts);
599
611
  if (content.length === 0) return void 0;
600
612
  const bodyPr = poChildren(txBody).find((c) => poIs(c, "a:bodyPr"));
613
+ const fitted = fitToBody(content, bodyPr);
601
614
  const lIns = bodyPr ? poIntAttr(bodyPr, "lIns") : void 0;
602
615
  const tIns = bodyPr ? poIntAttr(bodyPr, "tIns") : void 0;
603
616
  const rIns = bodyPr ? poIntAttr(bodyPr, "rIns") : void 0;
@@ -605,7 +618,7 @@ function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor) {
605
618
  const a = bodyPr ? poAttr(bodyPr, "anchor") : void 0;
606
619
  const anchor = a === "ctr" || a === "b" || a === "t" ? a : ph && cascade ? cascade.anchorFor(ph) : void 0;
607
620
  return {
608
- content,
621
+ content: fitted,
609
622
  ...lIns !== void 0 ? { insetLeft: emuToPt(lIns) } : {},
610
623
  ...tIns !== void 0 ? { insetTop: emuToPt(tIns) } : {},
611
624
  ...rIns !== void 0 ? { insetRight: emuToPt(rIns) } : {},
@@ -613,7 +626,53 @@ function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor) {
613
626
  ...anchor ? { anchor } : {}
614
627
  };
615
628
  }
616
- function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, styleColor) {
629
+ /**
630
+ * §21.1.2.1.2 — the body's text at the size the autofit settled on.
631
+ *
632
+ * The scale is a property of the BODY that reaches every run in it, so it is
633
+ * applied here rather than carried down: a run in the model already holds the
634
+ * size it inherited, and the shrink multiplies exactly that. Unread, the text
635
+ * PowerPoint squeezed to 62% of its style overflowed the placeholder it was
636
+ * squeezed to fit.
637
+ *
638
+ * @param content The body's paragraphs.
639
+ * @param bodyPr The body's `a:bodyPr`, which carries the autofit.
640
+ * @returns The paragraphs, scaled; the same array when nothing is stated.
641
+ */
642
+ function fitToBody(content, bodyPr) {
643
+ const fit = bodyPr ? poChildren(bodyPr).find((c) => poIs(c, "a:normAutofit")) : void 0;
644
+ const scale = fit ? poIntAttr(fit, "fontScale") : void 0;
645
+ const reduction = fit ? poIntAttr(fit, "lnSpcReduction") : void 0;
646
+ const fontScale = scale !== void 0 && scale > 0 ? scale / 1e5 : void 0;
647
+ const lineScale = reduction !== void 0 && reduction > 0 ? 1 - Math.min(reduction, 1e5) / 1e5 : void 0;
648
+ if (fontScale === void 0 && lineScale === void 0) return content;
649
+ return content.map((el) => {
650
+ if (el.kind !== "paragraph") return el;
651
+ const p = el.paragraph;
652
+ const line = lineScale === void 0 ? void 0 : pt((p.properties.spacingLine ?? 12) * lineScale);
653
+ return {
654
+ ...el,
655
+ paragraph: {
656
+ ...p,
657
+ properties: {
658
+ ...p.properties,
659
+ ...line !== void 0 ? {
660
+ spacingLine: line,
661
+ spacingLineRule: "auto"
662
+ } : {}
663
+ },
664
+ runs: fontScale === void 0 ? p.runs : p.runs.map((run) => run.properties.fontSizePt === void 0 ? run : {
665
+ ...run,
666
+ properties: {
667
+ ...run.properties,
668
+ fontSizePt: pt(run.properties.fontSizePt * fontScale)
669
+ }
670
+ })
671
+ }
672
+ };
673
+ });
674
+ }
675
+ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, styleColor, themeFonts) {
617
676
  const pPr = poChildren(aP).find((c) => poIs(c, "a:pPr"));
618
677
  const level = (pPr ? poIntAttr(pPr, "lvl") : void 0) ?? 0;
619
678
  const defaults = {
@@ -625,7 +684,7 @@ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, sty
625
684
  const alignment = algn !== void 0 ? ALGN_TO_ALIGNMENT[algn] : void 0;
626
685
  const runs = [];
627
686
  for (const child of poChildren(aP)) if (poIs(child, "a:r") || poIs(child, "a:fld")) {
628
- const run = parseSlideRun(child, defaults, colors, resolveLink);
687
+ const run = parseSlideRun(child, defaults, colors, resolveLink, themeFonts);
629
688
  if (run) runs.push(run);
630
689
  }
631
690
  const marL = pPr ? poIntAttr(pPr, "marL") : void 0;
@@ -645,27 +704,41 @@ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, sty
645
704
  listMarker: true
646
705
  });
647
706
  }
648
- if (runs.length === 0) {
649
- const endRPr = poChildren(aP).find((c) => poIs(c, "a:endParaRPr"));
650
- const sz = endRPr ? poIntAttr(endRPr, "sz") : void 0;
651
- if (sz !== void 0 && sz > 0) runs.push({
652
- text: "",
653
- properties: {
654
- ...defaults,
655
- fontSizePt: pt(sz / 100)
656
- }
657
- });
658
- }
707
+ const endRPr = poChildren(aP).find((c) => poIs(c, "a:endParaRPr"));
708
+ const endSz = endRPr ? poIntAttr(endRPr, "sz") : void 0;
709
+ const markProps = runs.length > 0 ? void 0 : {
710
+ ...defaults,
711
+ ...endSz !== void 0 && endSz > 0 ? { fontSizePt: pt(endSz / 100) } : {}
712
+ };
659
713
  return {
660
714
  properties: {
661
715
  ...inherited,
662
716
  ...alignment ? { alignment } : {},
663
717
  ...indentLeft !== void 0 ? { indentLeft } : {},
664
- ...indent !== void 0 ? { indentFirstLine: emuToPt(indent) } : {}
718
+ ...indent !== void 0 ? { indentFirstLine: emuToPt(indent) } : {},
719
+ ...lineSpacing(pPr),
720
+ ...ownSpacing(pPr, runs[0]?.properties.fontSizePt ?? defaults.fontSizePt),
721
+ ...markProps && markProps.fontSizePt !== void 0 ? { runProperties: markProps } : {}
665
722
  },
666
723
  runs
667
724
  };
668
725
  }
726
+ function ownSpacing(pPr, sizePt) {
727
+ const fractions = spacingFractions(pPr);
728
+ const before = spacingFromLineFraction(fractions?.before, sizePt);
729
+ const after = spacingFromLineFraction(fractions?.after, sizePt);
730
+ const points = (tag) => {
731
+ const holder = pPr ? poChildren(pPr).find((c) => poIs(c, tag)) : void 0;
732
+ const node = holder ? poChildren(holder).find((c) => poIs(c, "a:spcPts")) : void 0;
733
+ const val = node ? poIntAttr(node, "val") : void 0;
734
+ return val === void 0 ? void 0 : pt(val / 100);
735
+ };
736
+ const [beforePt, afterPt] = [points("a:spcBef") ?? before, points("a:spcAft") ?? after];
737
+ return {
738
+ ...beforePt !== void 0 ? { spacingBefore: beforePt } : {},
739
+ ...afterPt !== void 0 ? { spacingAfter: afterPt } : {}
740
+ };
741
+ }
669
742
  function bulletProps(base, bullet) {
670
743
  const sizePt = bullet.sizePts ?? (bullet.sizePct !== void 0 && base.fontSizePt !== void 0 ? base.fontSizePt * bullet.sizePct : void 0);
671
744
  return {
@@ -688,7 +761,7 @@ function autoNumSuffix(type) {
688
761
  if (type.endsWith("Period")) return ".";
689
762
  return "";
690
763
  }
691
- function parseSlideRun(node, defaults, colors, resolveLink) {
764
+ function parseSlideRun(node, defaults, colors, resolveLink, themeFonts) {
692
765
  const t = poChildren(node).find((c) => poIs(c, "a:t"));
693
766
  const text = t ? poText(t) : "";
694
767
  if (text.length === 0) return void 0;
@@ -700,12 +773,12 @@ function parseSlideRun(node, defaults, colors, resolveLink) {
700
773
  text,
701
774
  properties: {
702
775
  ...defaults,
703
- ...rPrToRunProps(rPr, colors)
776
+ ...rPrToRunProps(rPr, colors, themeFonts)
704
777
  },
705
778
  ...href ? { href } : {}
706
779
  };
707
780
  }
708
- function parseTable(tbl, colors, resolveTableStyle) {
781
+ function parseTable(tbl, colors, resolveTableStyle, theme) {
709
782
  const grid = [];
710
783
  const tblGrid = poChildren(tbl).find((c) => poIs(c, "a:tblGrid"));
711
784
  if (tblGrid) {
@@ -738,7 +811,7 @@ function parseTable(tbl, colors, resolveTableStyle) {
738
811
  rowCount: rows.length,
739
812
  col: c,
740
813
  colCount: grid.length
741
- }, colors);
814
+ }, colors, theme);
742
815
  const tc = sources[r]?.[c];
743
816
  return withCellStyle(cell, tc && cellSaysNoFill(tc) ? withoutFill(part) : part);
744
817
  })
@@ -1,5 +1,6 @@
1
1
  import { RunProperties } from '../core/document-model/index.js';
2
2
  import { ColorResolver } from '../core/drawingml/colors.js';
3
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
3
4
  import { PoNode } from '../core/po-helpers.js';
4
5
  /**
5
6
  * §19.3.1.36 `p:ph` — a shape's placeholder reference. `type`/`idx` tie a slide
@@ -42,4 +43,4 @@ export declare function parseXfrmBox(spPr: PoNode | undefined): ShapeBoxEmu | un
42
43
  * (`sz`, hundredths of a point), bold/italic/underline, solid colour and the
43
44
  * latin typeface. Scheme colours and the theme font cascade come in PX5.
44
45
  */
45
- export declare function rPrToRunProps(rPr: PoNode | undefined, colors: ColorResolver): RunProperties;
46
+ export declare function rPrToRunProps(rPr: PoNode | undefined, colors: ColorResolver, themeFonts?: ThemeFonts): RunProperties;
@@ -1,6 +1,7 @@
1
1
  import { pt } from "../core/ir/units.js";
2
2
  import { poAttr, poChildren, poIntAttr, poIs } from "../core/po-helpers.js";
3
3
  import { resolveColorNode } from "../core/drawingml/colors.js";
4
+ import { resolveThemeFont } from "../core/drawingml/theme-parser.js";
4
5
  //#region src/pptx/sp-helpers.ts
5
6
  var isTrue = (v) => v === "1" || v === "true" || v === "on";
6
7
  /**
@@ -54,13 +55,13 @@ function parseXfrmBox(spPr) {
54
55
  * (`sz`, hundredths of a point), bold/italic/underline, solid colour and the
55
56
  * latin typeface. Scheme colours and the theme font cascade come in PX5.
56
57
  */
57
- function rPrToRunProps(rPr, colors) {
58
+ function rPrToRunProps(rPr, colors, themeFonts) {
58
59
  if (!rPr) return {};
59
60
  const sz = poIntAttr(rPr, "sz");
60
61
  const u = poAttr(rPr, "u");
61
62
  const colorHex = solidFillColor(rPr, colors);
62
63
  const latin = poChildren(rPr).find((c) => poIs(c, "a:latin"));
63
- const typeface = latin ? poAttr(latin, "typeface")?.trim() : void 0;
64
+ const typeface = resolveThemeFont(latin ? poAttr(latin, "typeface")?.trim() : void 0, themeFonts);
64
65
  const flag = (name) => {
65
66
  const v = poAttr(rPr, name);
66
67
  return v === void 0 ? void 0 : isTrue(v);
@@ -29,6 +29,13 @@ export interface CellPosition {
29
29
  export declare function tableStyleFlags(tblPr: PoNode | undefined): TableStyleFlags;
30
30
  /** The GUID a table names, if it names one (`a:tblPr/a:tableStyleId`). */
31
31
  export declare function tableStyleId(tblPr: PoNode | undefined): string | undefined;
32
+ /** What the deck's theme lends a style that points at it instead of spelling it out. */
33
+ export interface TableStyleTheme {
34
+ /** §20.1.4.1.14 `a:fillStyleLst` — the fills an `a:fillRef` indexes. */
35
+ readonly fills?: ReadonlyArray<PoNode>;
36
+ /** §20.1.4.2.19 `a:lnStyleLst` — the widths an `a:lnRef` indexes, in points. */
37
+ readonly lineWidths?: ReadonlyArray<number>;
38
+ }
32
39
  /**
33
40
  * The style a cell wears, composed from every part that reaches it.
34
41
  *
@@ -36,9 +43,10 @@ export declare function tableStyleId(tblPr: PoNode | undefined): string | undefi
36
43
  * @param flags Which conditional parts the table asks for.
37
44
  * @param at Where the cell sits.
38
45
  * @param colors The deck's colour resolver.
46
+ * @param theme The theme's style lists, for the parts that point at them.
39
47
  * @returns The composed part, empty when the style says nothing.
40
48
  */
41
- export declare function cellStyle(style: PoNode, flags: TableStyleFlags, at: CellPosition, colors: ColorResolver): TableStylePart;
49
+ export declare function cellStyle(style: PoNode, flags: TableStyleFlags, at: CellPosition, colors: ColorResolver, theme?: TableStyleTheme): TableStylePart;
42
50
  /**
43
51
  * §20.1.2.1 `a:ln` → the rule it draws on one side of a cell.
44
52
  *
@@ -26,9 +26,10 @@ function tableStyleId(tblPr) {
26
26
  * @param flags Which conditional parts the table asks for.
27
27
  * @param at Where the cell sits.
28
28
  * @param colors The deck's colour resolver.
29
+ * @param theme The theme's style lists, for the parts that point at them.
29
30
  * @returns The composed part, empty when the style says nothing.
30
31
  */
31
- function cellStyle(style, flags, at, colors) {
32
+ function cellStyle(style, flags, at, colors, theme) {
32
33
  const names = ["a:wholeTbl"];
33
34
  if (flags.bandCol) names.push(bandName(at.col, flags.firstCol, "V"));
34
35
  if (flags.bandRow) names.push(bandName(at.row, flags.firstRow, "H"));
@@ -36,27 +37,52 @@ function cellStyle(style, flags, at, colors) {
36
37
  if (flags.lastCol && at.col === at.colCount - 1) names.push("a:lastCol");
37
38
  if (flags.firstRow && at.row === 0) names.push("a:firstRow");
38
39
  if (flags.lastRow && at.row === at.rowCount - 1) names.push("a:lastRow");
39
- let out = {};
40
+ let out = tableBackground(style, colors, theme);
40
41
  for (const name of names) {
41
42
  const part = poChildren(style).find((c) => poIs(c, name));
42
43
  if (part) out = {
43
44
  ...out,
44
- ...partStyle(part, colors)
45
+ ...partStyle(part, colors, theme)
45
46
  };
46
47
  }
47
48
  return out;
48
49
  }
50
+ function tableBackground(style, colors, theme) {
51
+ const bg = poChildren(style).find((c) => poIs(c, "a:tblBg"));
52
+ if (!bg) return {};
53
+ const solid = poChildren(bg).find((c) => poIs(c, "a:solidFill"));
54
+ const hex = (solid ? colorOf(solid, colors) : void 0) ?? refFillColor(poChildren(bg).find((c) => poIs(c, "a:fillRef")), colors, theme);
55
+ return hex ? { shadingHex: hex } : {};
56
+ }
57
+ /**
58
+ * §20.1.4.1.16 `a:fillRef` — a fill named by its place in the theme's list,
59
+ * with the colour to put wherever that fill says `phClr`.
60
+ *
61
+ * Only its COLOUR is taken: a slot may be a gradient or a picture, and a cell's
62
+ * shading is one colour. The first solid colour the slot names, or the
63
+ * reference's own, is the nearest true answer.
64
+ */
65
+ function refFillColor(ref, colors, theme) {
66
+ if (!ref) return void 0;
67
+ const own = colorOf(ref, colors);
68
+ const idx = poIntAttr(ref, "idx");
69
+ const slot = idx !== void 0 && idx > 0 ? theme?.fills?.[idx - 1] : void 0;
70
+ if (!slot) return own;
71
+ const solid = poChildren(slot).find((c) => poIs(c, "a:solidFill"));
72
+ const slotHex = solid ? colorOf(solid, colors) : void 0;
73
+ return slotHex && slotHex !== "PHCLR" ? own ?? slotHex : own;
74
+ }
49
75
  function bandName(index, edge, axis) {
50
76
  return (edge ? index - 1 : index) % 2 === 0 ? `a:band1${axis}` : `a:band2${axis}`;
51
77
  }
52
- function partStyle(part, colors) {
78
+ function partStyle(part, colors, theme) {
53
79
  const tcStyle = poChildren(part).find((c) => poIs(c, "a:tcStyle"));
54
80
  const txStyle = poChildren(part).find((c) => poIs(c, "a:tcTxStyle"));
55
81
  const fill = tcStyle ? poChildren(tcStyle).find((c) => poIs(c, "a:fill")) : void 0;
56
82
  const solid = fill ? poChildren(fill).find((c) => poIs(c, "a:solidFill")) : void 0;
57
83
  const shadingHex = solid ? colorOf(solid, colors) : void 0;
58
84
  const bdr = tcStyle ? poChildren(tcStyle).find((c) => poIs(c, "a:tcBdr")) : void 0;
59
- const borders = bdr ? partBorders(bdr, colors) : void 0;
85
+ const borders = bdr ? partBorders(bdr, colors, theme) : void 0;
60
86
  const on = (name) => poAttr(txStyle, name) === "on";
61
87
  const colorHex = txStyle ? colorOf(txStyle, colors) : void 0;
62
88
  return {
@@ -75,15 +101,31 @@ var SIDES = [
75
101
  ["a:insideH", "insideH"],
76
102
  ["a:insideV", "insideV"]
77
103
  ];
78
- function partBorders(bdr, colors) {
104
+ function partBorders(bdr, colors, theme) {
79
105
  const out = {};
80
106
  for (const [tag, side] of SIDES) {
81
107
  const holder = poChildren(bdr).find((c) => poIs(c, tag));
82
108
  const ln = holder ? poChildren(holder).find((c) => poIs(c, "a:ln")) : void 0;
83
- if (ln) out[side] = lineBorder(ln, colors);
109
+ if (ln) {
110
+ out[side] = lineBorder(ln, colors);
111
+ continue;
112
+ }
113
+ const border = refBorder(holder ? poChildren(holder).find((c) => poIs(c, "a:lnRef")) : void 0, colors, theme);
114
+ if (border) out[side] = border;
84
115
  }
85
116
  return Object.keys(out).length > 0 ? out : void 0;
86
117
  }
118
+ function refBorder(ref, colors, theme) {
119
+ if (!ref || poAttr(ref, "idx") === "0") return void 0;
120
+ const colorHex = colorOf(ref, colors);
121
+ if (colorHex === void 0) return void 0;
122
+ const idx = poIntAttr(ref, "idx");
123
+ return {
124
+ style: "single",
125
+ colorHex,
126
+ width: pt((idx !== void 0 && idx > 0 ? theme?.lineWidths?.[idx - 1] : void 0) ?? .75)
127
+ };
128
+ }
87
129
  /**
88
130
  * §20.1.2.1 `a:ln` → the rule it draws on one side of a cell.
89
131
  *