@pptx-studio/model 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/LICENSE +202 -0
- package/NOTICE +43 -0
- package/README.md +183 -0
- package/dist/index.d.ts +1340 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3042 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1340 @@
|
|
|
1
|
+
import { COLOR_TRANSFORM_OPS, ClrMap, ClrScheme, Color, ColorContext, Effect, Fill, Line, Rgba } from "@pptx-studio/paint";
|
|
2
|
+
import { XElement } from "@pptx-studio/xml";
|
|
3
|
+
import { Geometry, PresetGuide } from "@pptx-studio/geometry";
|
|
4
|
+
import { PartStore } from "@pptx-studio/opc";
|
|
5
|
+
//#region src/errors.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Typed failures, as everywhere else in this repository.
|
|
8
|
+
*
|
|
9
|
+
* Two kinds of thing go wrong here and they want different treatment.
|
|
10
|
+
*
|
|
11
|
+
* A **broken package** - a slide that names no layout, a layout whose master is
|
|
12
|
+
* missing, a master with no theme - is not a programming mistake. PowerPoint
|
|
13
|
+
* repairs all three rather than refusing them (measured in 2.9, and after the
|
|
14
|
+
* repair the binding is simply gone), and a viewer that throws on a file
|
|
15
|
+
* PowerPoint opens is a viewer nobody can use. So those are *not* errors here:
|
|
16
|
+
* the chain records what it found and `parent` is `null`. There is a code for
|
|
17
|
+
* each all the same, because `validate` refuses to *write* one, and because a
|
|
18
|
+
* caller that asks for the theme of a master that has none needs an answer with
|
|
19
|
+
* a name.
|
|
20
|
+
*
|
|
21
|
+
* A **caller mistake** - resolving `phClr` outside a style invocation, asking
|
|
22
|
+
* for a sheet that is not in the document - is an error and throws.
|
|
23
|
+
*/
|
|
24
|
+
type ModelErrorCode =
|
|
25
|
+
/** A part the chain needs is not in the package. */
|
|
26
|
+
'MODEL_PART_MISSING' |
|
|
27
|
+
/** A part is present but its root element is not the one its rel promised. */
|
|
28
|
+
'MODEL_PART_KIND' |
|
|
29
|
+
/** `ppt/presentation.xml` is missing, or the root rels do not name it. */
|
|
30
|
+
'MODEL_NO_PRESENTATION' |
|
|
31
|
+
/** A slide has no `slideLayout` relationship, or a layout no `slideMaster`. */
|
|
32
|
+
'MODEL_NO_PARENT' |
|
|
33
|
+
/** A master has no `theme` relationship. */
|
|
34
|
+
'MODEL_NO_THEME' |
|
|
35
|
+
/** A `p:clrMap` or `a:overrideClrMapping` missing one of its twelve attributes. */
|
|
36
|
+
'MODEL_CLRMAP_INCOMPLETE' |
|
|
37
|
+
/** A `p:clrMap` attribute naming something that is not one of the twelve slots. */
|
|
38
|
+
'MODEL_CLRMAP_SLOT' |
|
|
39
|
+
/** A `p:ph/@idx` that is not a non-negative integer below 2^32. */
|
|
40
|
+
'MODEL_PLACEHOLDER_IDX' |
|
|
41
|
+
/** An `a:off`/`a:ext`/`@rot` attribute that is not an integer. */
|
|
42
|
+
'MODEL_XFRM_NUMBER' |
|
|
43
|
+
/** A style-matrix reference whose `@idx` does not parse. */
|
|
44
|
+
'MODEL_STYLE_IDX' |
|
|
45
|
+
/** An `a:fontRef/@idx` outside `major`, `minor` and `none`. */
|
|
46
|
+
'MODEL_FONT_COLLECTION' |
|
|
47
|
+
/** A theme with no `a:fmtScheme`, asked for a style-matrix entry. */
|
|
48
|
+
'MODEL_NO_STYLE_MATRIX' |
|
|
49
|
+
/** A `a:fillStyleLst`/`a:lnStyleLst`/`a:bgFillStyleLst` with no entries at all. */
|
|
50
|
+
'MODEL_STYLE_LIST_EMPTY' |
|
|
51
|
+
/** A sheet chain that returns to a sheet it has already visited. */
|
|
52
|
+
'MODEL_SHEET_CYCLE' |
|
|
53
|
+
/** A sheet that does not belong to the document it was asked about. */
|
|
54
|
+
'MODEL_FOREIGN_SHEET' |
|
|
55
|
+
/** `a:prstGeom` with no `@prst`, or an `a:custGeom` command missing a point. */
|
|
56
|
+
'MODEL_GEOMETRY' |
|
|
57
|
+
/** A text attribute whose value is not of the type its schema names. */
|
|
58
|
+
'MODEL_TEXT_ATTR' |
|
|
59
|
+
/** An `a:fld` with no `@id`, which is a required `ST_Guid`. */
|
|
60
|
+
'MODEL_TEXT_FIELD' |
|
|
61
|
+
/**
|
|
62
|
+
* A bullet that contradicts itself or omits what the schema requires.
|
|
63
|
+
*
|
|
64
|
+
* The four kinds are an exclusive group, `a:buAutoNum` must carry a @type and
|
|
65
|
+
* `a:buBlip` must resolve to a relationship. A file that breaks one of those is
|
|
66
|
+
* one PowerPoint would repair, and repairing it here quietly would hide which.
|
|
67
|
+
*/
|
|
68
|
+
'MODEL_TEXT_BULLET' |
|
|
69
|
+
/** A paragraph level that is not an integer. */
|
|
70
|
+
'MODEL_TEXT_LEVEL' | 'MODEL_TEXT_TYPEFACE' | 'BLIP_NO_EMBED' | 'BLIP_DUOTONE' | 'BLIP_CLR_CHANGE' | 'BLIP_TILE_ALIGN' | 'BLIP_TILE_FLIP';
|
|
71
|
+
declare class ModelError extends Error {
|
|
72
|
+
readonly name = "ModelError";
|
|
73
|
+
readonly code: ModelErrorCode;
|
|
74
|
+
/** The part the failure is about, when there is one. */
|
|
75
|
+
readonly partName: string | null;
|
|
76
|
+
/** Whatever detail names the failure: an attribute value, a rel id, a slot. */
|
|
77
|
+
readonly detail: string | null;
|
|
78
|
+
constructor(code: ModelErrorCode, message: string, partName?: string | null, detail?: string | null);
|
|
79
|
+
}
|
|
80
|
+
declare function isModelError(value: unknown): value is ModelError;
|
|
81
|
+
declare const MODEL_ERROR_CODES: readonly ModelErrorCode[];
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/parse/geometry.d.ts
|
|
84
|
+
/**
|
|
85
|
+
* What a shape says it is.
|
|
86
|
+
*
|
|
87
|
+
* `preset` keeps the adjust values as guides rather than numbers, because
|
|
88
|
+
* `a:avLst` is a `CT_GeomGuideList` and a guide may in principle carry any
|
|
89
|
+
* formula - `evaluateGuides` takes either form and the file's form is the one
|
|
90
|
+
* that round-trips.
|
|
91
|
+
*/
|
|
92
|
+
type ShapeGeometry = {
|
|
93
|
+
readonly kind: 'preset';
|
|
94
|
+
readonly prst: string;
|
|
95
|
+
readonly adjust: readonly PresetGuide[];
|
|
96
|
+
} | {
|
|
97
|
+
readonly kind: 'custom';
|
|
98
|
+
readonly geometry: Geometry;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The geometry a shape declares, or `undefined` when it declares none.
|
|
102
|
+
*
|
|
103
|
+
* `undefined` is the whole point: a slide placeholder with no `a:prstGeom` has
|
|
104
|
+
* not chosen to be a rectangle, it has said nothing, and `resolve` is what turns
|
|
105
|
+
* that into the layout's answer.
|
|
106
|
+
*/
|
|
107
|
+
declare function parseGeometry(spPr: XElement | undefined, partName: string): ShapeGeometry | undefined;
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/text.d.ts
|
|
110
|
+
/** `ST_TextAlignType`. */
|
|
111
|
+
type TextAlign = 'l' | 'ctr' | 'r' | 'just' | 'justLow' | 'dist' | 'thaiDist';
|
|
112
|
+
/** `ST_TextFontAlignType`. */
|
|
113
|
+
type FontAlign = 'auto' | 't' | 'ctr' | 'base' | 'b';
|
|
114
|
+
/** `ST_TextUnderlineType`, all seventeen, as written. */
|
|
115
|
+
type Underline = 'none' | 'words' | 'sng' | 'dbl' | 'heavy' | 'dotted' | 'dottedHeavy' | 'dash' | 'dashHeavy' | 'dashLong' | 'dashLongHeavy' | 'dotDash' | 'dotDashHeavy' | 'dotDotDash' | 'dotDotDashHeavy' | 'wavy' | 'wavyHeavy' | 'wavyDbl';
|
|
116
|
+
/** `ST_TextStrikeType`. */
|
|
117
|
+
type Strike = 'noStrike' | 'sngStrike' | 'dblStrike';
|
|
118
|
+
/** `ST_TextCapsType`. */
|
|
119
|
+
type Caps = 'none' | 'small' | 'all';
|
|
120
|
+
/**
|
|
121
|
+
* `a:lnSpc`, `a:spcBef` and `a:spcAft`, which are one of two quite different
|
|
122
|
+
* things and say which in their child element's name.
|
|
123
|
+
*
|
|
124
|
+
* `a:spcPct` is hundred-thousandths of the line height - 150000 is 150%.
|
|
125
|
+
* `a:spcPts` is hundredths of a point - 3000 is 30pt. Conflating them collapses
|
|
126
|
+
* every slide that uses the second, and `ST_Percentage` accepts *both* the
|
|
127
|
+
* `150000` and the `150%` spellings, so the parse is not `parseInt` either:
|
|
128
|
+
* `parseInt("150%")` is 150, which is 0.15% line spacing. Measured in 3.1, and
|
|
129
|
+
* in 2.6 for the colour transforms that share the type.
|
|
130
|
+
*/
|
|
131
|
+
type Spacing = {
|
|
132
|
+
readonly kind: 'percent';
|
|
133
|
+
readonly value: number;
|
|
134
|
+
} | {
|
|
135
|
+
readonly kind: 'points';
|
|
136
|
+
readonly value: number;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* One of the four typeface slots on a run.
|
|
140
|
+
*
|
|
141
|
+
* `@typeface` may be a real face name or a theme reference - `+mj-lt`,
|
|
142
|
+
* `+mn-lt`, `+mj-ea`, `+mn-ea`, `+mj-cs`, `+mn-cs` - and the reference is kept
|
|
143
|
+
* as written rather than resolved here, because which theme it resolves against
|
|
144
|
+
* is a property of the sheet and not of the run.
|
|
145
|
+
*/
|
|
146
|
+
interface Typeface {
|
|
147
|
+
readonly typeface: string;
|
|
148
|
+
/** `@panose`, twenty hex characters. */
|
|
149
|
+
readonly panose: string | undefined;
|
|
150
|
+
/** `@pitchFamily`, `(family << 4) | pitch`. */
|
|
151
|
+
readonly pitchFamily: number | undefined;
|
|
152
|
+
/** `@charset`, **signed**: Shift-JIS is -128, not 128. */
|
|
153
|
+
readonly charset: number | undefined;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Which of a theme's two font collections a `+mj-`/`+mn-` reference names.
|
|
157
|
+
*
|
|
158
|
+
* `script` is spelled the way `FontCollection` spells it rather than the way the
|
|
159
|
+
* reference does - `lt` in the markup is the `a:latin` element, and a resolver
|
|
160
|
+
* that carried the reference's spelling would need a second map between two
|
|
161
|
+
* three-member sets to index the thing it just parsed.
|
|
162
|
+
*/
|
|
163
|
+
type ThemeFontRef = {
|
|
164
|
+
readonly collection: 'major' | 'minor';
|
|
165
|
+
readonly script: 'latin' | 'ea' | 'cs';
|
|
166
|
+
};
|
|
167
|
+
/** `+mn-lt` and its five siblings, or `null` for a real typeface name. */
|
|
168
|
+
declare function themeFontRef(typeface: string): ThemeFontRef | null;
|
|
169
|
+
/**
|
|
170
|
+
* `CT_TextCharacterProperties` - `a:rPr`, `a:defRPr` and `a:endParaRPr`.
|
|
171
|
+
*
|
|
172
|
+
* Every field is optional in the file and optional here. The cascade merges
|
|
173
|
+
* these **per property**: measured in 3.1 with five levels declaring one
|
|
174
|
+
* property each, which produced a 24-point bold italic underlined struck run
|
|
175
|
+
* where a nearest-level-takes-all reading gives an 18-point struck one.
|
|
176
|
+
*/
|
|
177
|
+
interface RunProps {
|
|
178
|
+
/** `@sz`, hundredths of a point. 2400 is 24pt. */
|
|
179
|
+
readonly sz: number | undefined;
|
|
180
|
+
readonly b: boolean | undefined;
|
|
181
|
+
readonly i: boolean | undefined;
|
|
182
|
+
readonly u: Underline | undefined;
|
|
183
|
+
readonly strike: Strike | undefined;
|
|
184
|
+
readonly cap: Caps | undefined;
|
|
185
|
+
/** `@spc`, hundredths of a point. May be negative. */
|
|
186
|
+
readonly spc: number | undefined;
|
|
187
|
+
/** `@kern`, hundredths of a point: the size at or above which to kern. */
|
|
188
|
+
readonly kern: number | undefined;
|
|
189
|
+
/** `@baseline`, hundred-thousandths. 30000 is superscript. */
|
|
190
|
+
readonly baseline: number | undefined;
|
|
191
|
+
readonly noProof: boolean | undefined;
|
|
192
|
+
readonly lang: string | undefined;
|
|
193
|
+
readonly altLang: string | undefined;
|
|
194
|
+
readonly latin: Typeface | undefined;
|
|
195
|
+
readonly ea: Typeface | undefined;
|
|
196
|
+
readonly cs: Typeface | undefined;
|
|
197
|
+
readonly sym: Typeface | undefined;
|
|
198
|
+
/** The text's own fill: `a:solidFill` and its siblings inside `a:rPr`. */
|
|
199
|
+
readonly fill: Fill | undefined;
|
|
200
|
+
/** `a:ln` inside `a:rPr`: the outline of the glyphs. */
|
|
201
|
+
readonly line: Line | undefined;
|
|
202
|
+
readonly effects: readonly Effect[] | undefined;
|
|
203
|
+
/** `a:highlight`, which is a colour and not a fill. */
|
|
204
|
+
readonly highlight: Color | undefined;
|
|
205
|
+
/** The element this was read from. Edits go here, never to the fields above. */
|
|
206
|
+
readonly node: XElement;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The exclusive group in `CT_TextParagraphProperties`: one of four, or nothing.
|
|
210
|
+
*
|
|
211
|
+
* `undefined` on `ParaProps` is the fifth case and the one that matters -
|
|
212
|
+
* a level that declares no bullet element at all **inherits** one, where
|
|
213
|
+
* `'none'` suppresses it.
|
|
214
|
+
*/
|
|
215
|
+
type BulletKind = 'none' | 'char' | 'autonum' | 'blip';
|
|
216
|
+
/** `a:buFont` / `a:buFontTx`, which are exclusive of each other. */
|
|
217
|
+
type BulletFont = {
|
|
218
|
+
readonly kind: 'typeface';
|
|
219
|
+
readonly value: Typeface;
|
|
220
|
+
} |
|
|
221
|
+
/** `a:buFontTx`: follow the text, and cancel anything inherited. */
|
|
222
|
+
{
|
|
223
|
+
readonly kind: 'text';
|
|
224
|
+
};
|
|
225
|
+
/** `a:buSzPct` / `a:buSzPts` / `a:buSzTx`. */
|
|
226
|
+
type BulletSize =
|
|
227
|
+
/** `a:buSzPct/@val`, thousandths of a percent of the first run's size. */
|
|
228
|
+
{
|
|
229
|
+
readonly kind: 'percent';
|
|
230
|
+
readonly value: number;
|
|
231
|
+
} |
|
|
232
|
+
/** `a:buSzPts/@val`, hundredths of a point, absolute. */
|
|
233
|
+
{
|
|
234
|
+
readonly kind: 'points';
|
|
235
|
+
readonly value: number;
|
|
236
|
+
} | {
|
|
237
|
+
readonly kind: 'text';
|
|
238
|
+
};
|
|
239
|
+
/** `a:buClr` / `a:buClrTx`. */
|
|
240
|
+
type BulletColor = {
|
|
241
|
+
readonly kind: 'color';
|
|
242
|
+
readonly value: Color;
|
|
243
|
+
} | {
|
|
244
|
+
readonly kind: 'text';
|
|
245
|
+
};
|
|
246
|
+
/** `a:buAutoNum`. */
|
|
247
|
+
interface BulletAutoNum {
|
|
248
|
+
/** `@type`, one of the 41 `ST_TextAutonumberScheme` values. */
|
|
249
|
+
readonly type: string;
|
|
250
|
+
/**
|
|
251
|
+
* `@startAt`. Absent is measured to behave exactly as `1` - but the two are
|
|
252
|
+
* kept apart, because a paragraph whose `startAt` differs from its
|
|
253
|
+
* predecessor's begins a new run, and "absent" has to compare equal to "1"
|
|
254
|
+
* for that rule rather than to nothing.
|
|
255
|
+
*/
|
|
256
|
+
readonly startAt: number | undefined;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* `CT_TextParagraphProperties` - `a:pPr` and every `a:lvlNpPr`.
|
|
260
|
+
*
|
|
261
|
+
* `@lvl` is deliberately absent. It is the level a paragraph *is at*, not a
|
|
262
|
+
* property that inherits: an `a:lvl3pPr` carrying `lvl="7"` would be nonsense,
|
|
263
|
+
* and a cascade that inherited it would change which level the next lookup used
|
|
264
|
+
* halfway through resolving one paragraph.
|
|
265
|
+
*/
|
|
266
|
+
interface ParaProps {
|
|
267
|
+
/** `@marL`, EMU. Measured to default to **0**, not to the schema's 347663. */
|
|
268
|
+
readonly marL: number | undefined;
|
|
269
|
+
readonly marR: number | undefined;
|
|
270
|
+
/** `@indent`, EMU, usually negative. Defaults to 0, not to -342900. */
|
|
271
|
+
readonly indent: number | undefined;
|
|
272
|
+
readonly algn: TextAlign | undefined;
|
|
273
|
+
/** `@defTabSz`, EMU. */
|
|
274
|
+
readonly defTabSz: number | undefined;
|
|
275
|
+
readonly rtl: boolean | undefined;
|
|
276
|
+
readonly eaLnBrk: boolean | undefined;
|
|
277
|
+
readonly fontAlgn: FontAlign | undefined;
|
|
278
|
+
/** `@latinLnBrk`. ECMA says the default is true; PowerPoint behaves as false. */
|
|
279
|
+
readonly latinLnBrk: boolean | undefined;
|
|
280
|
+
readonly hangingPunct: boolean | undefined;
|
|
281
|
+
readonly lnSpc: Spacing | undefined;
|
|
282
|
+
readonly spcBef: Spacing | undefined;
|
|
283
|
+
readonly spcAft: Spacing | undefined;
|
|
284
|
+
/** `a:defRPr`: the run properties every run in this paragraph starts from. */
|
|
285
|
+
readonly defRPr: RunProps | undefined;
|
|
286
|
+
/**
|
|
287
|
+
* Which of `a:buNone`, `a:buChar`, `a:buAutoNum` and `a:buBlip` this level
|
|
288
|
+
* states, or `undefined` where it states none and inherits instead.
|
|
289
|
+
*/
|
|
290
|
+
readonly buKind: BulletKind | undefined;
|
|
291
|
+
/** `a:buChar/@char`, exactly as written. The symbol mapping happens at draw time. */
|
|
292
|
+
readonly buChar: string | undefined;
|
|
293
|
+
readonly buAutoNum: BulletAutoNum | undefined;
|
|
294
|
+
/** `a:buBlip/a:blip/@r:embed`. */
|
|
295
|
+
readonly buBlip: string | undefined;
|
|
296
|
+
/**
|
|
297
|
+
* The three decorations, each its own slot.
|
|
298
|
+
*
|
|
299
|
+
* They merge independently of the kind and of each other, which is measured
|
|
300
|
+
* rather than assumed: a level declaring only `a:buFont` re-faces the
|
|
301
|
+
* character it inherits and keeps its size and colour, and a level declaring
|
|
302
|
+
* only `a:buSzTx` cancels an inherited `a:buSzPct` and keeps the rest.
|
|
303
|
+
* Measured on eleven cases twice - once through a shape's own `a:lstStyle`
|
|
304
|
+
* and once through three hops of the master chain.
|
|
305
|
+
*/
|
|
306
|
+
readonly buFont: BulletFont | undefined;
|
|
307
|
+
readonly buSize: BulletSize | undefined;
|
|
308
|
+
readonly buColor: BulletColor | undefined;
|
|
309
|
+
readonly node: XElement;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* `CT_TextListStyle`: nine levels, and an `a:defPPr` nothing reads.
|
|
313
|
+
*
|
|
314
|
+
* `levels[0]` is `a:lvl1pPr`, which a paragraph at `lvl="0"` uses. Measured in
|
|
315
|
+
* 3.1: the levels are independent all the way up the chain - a layout
|
|
316
|
+
* placeholder declaring only `a:lvl2pPr` changes the second level and leaves the
|
|
317
|
+
* first and third to the master - so this is nine slots and not one object.
|
|
318
|
+
*
|
|
319
|
+
* `a:defPPr` is parsed and kept because it is in the file, and it is **not** a
|
|
320
|
+
* source: measured on a shape's own `a:lstStyle` and on `p:defaultTextStyle`,
|
|
321
|
+
* declaring only an `a:defPPr` changed nothing either time.
|
|
322
|
+
*/
|
|
323
|
+
interface ListStyle {
|
|
324
|
+
/** Nine entries, `a:lvl1pPr` through `a:lvl9pPr`, absent ones `undefined`. */
|
|
325
|
+
readonly levels: readonly (ParaProps | undefined)[];
|
|
326
|
+
/** `a:defPPr`. Preserved, never resolved against. */
|
|
327
|
+
readonly defPPr: ParaProps | undefined;
|
|
328
|
+
readonly node: XElement;
|
|
329
|
+
}
|
|
330
|
+
/** The number of levels a `CT_TextListStyle` holds, and `@lvl`'s range plus one. */
|
|
331
|
+
declare const LEVELS = 9;
|
|
332
|
+
/** `a:r`: a run of text with its own properties. */
|
|
333
|
+
interface TextRun {
|
|
334
|
+
readonly kind: 'run';
|
|
335
|
+
readonly props: RunProps | undefined;
|
|
336
|
+
readonly text: string;
|
|
337
|
+
readonly node: XElement;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* `a:br`: a hard line break.
|
|
341
|
+
*
|
|
342
|
+
* Not a paragraph break. It starts no new bullet, resets no first-line indent
|
|
343
|
+
* and applies neither `spcBef` nor `spcAft` - which is 3.6's problem, and is
|
|
344
|
+
* recorded here so that nothing later mistakes it for an `a:p`.
|
|
345
|
+
*/
|
|
346
|
+
interface TextBreak {
|
|
347
|
+
readonly kind: 'br';
|
|
348
|
+
readonly props: RunProps | undefined;
|
|
349
|
+
readonly node: XElement;
|
|
350
|
+
}
|
|
351
|
+
/** `a:fld`: a field, with the text PowerPoint last cached for it. */
|
|
352
|
+
interface TextField {
|
|
353
|
+
readonly kind: 'field';
|
|
354
|
+
/** `@id`, a required `ST_Guid`. Regenerating it is a repair risk. */
|
|
355
|
+
readonly id: string;
|
|
356
|
+
/** `@type`, one of the fourteen reserved names or a custom one. */
|
|
357
|
+
readonly fieldType: string | undefined;
|
|
358
|
+
readonly props: RunProps | undefined;
|
|
359
|
+
readonly text: string;
|
|
360
|
+
readonly node: XElement;
|
|
361
|
+
}
|
|
362
|
+
type TextContent = TextRun | TextBreak | TextField;
|
|
363
|
+
/** `a:p`. */
|
|
364
|
+
interface Paragraph {
|
|
365
|
+
readonly props: ParaProps | undefined;
|
|
366
|
+
/**
|
|
367
|
+
* `a:pPr/@lvl`, 0 through 8, defaulting to 0.
|
|
368
|
+
*
|
|
369
|
+
* Read off the paragraph rather than inherited, and clamped rather than
|
|
370
|
+
* thrown on: `ST_TextIndentLevelType` bounds it at 8, and a file outside the
|
|
371
|
+
* bound is one PowerPoint still opens.
|
|
372
|
+
*/
|
|
373
|
+
readonly level: number;
|
|
374
|
+
readonly content: readonly TextContent[];
|
|
375
|
+
/** `a:endParaRPr`: the properties of the (empty) run after the last one. */
|
|
376
|
+
readonly endParaRPr: RunProps | undefined;
|
|
377
|
+
readonly node: XElement;
|
|
378
|
+
}
|
|
379
|
+
/** `ST_TextAnchoringType`. PowerPoint lays `just` and `dist` out as `b`. */
|
|
380
|
+
type TextAnchor = 't' | 'ctr' | 'b' | 'just' | 'dist';
|
|
381
|
+
/** `ST_TextVerticalType`. */
|
|
382
|
+
type VerticalText = 'horz' | 'vert' | 'vert270' | 'wordArtVert' | 'eaVert' | 'mongolianVert' | 'wordArtVertRtl';
|
|
383
|
+
/** `ST_TextWrappingType`. */
|
|
384
|
+
type TextWrap = 'none' | 'square';
|
|
385
|
+
/** `ST_TextVertOverflowType`. */
|
|
386
|
+
type VertOverflow = 'overflow' | 'ellipsis' | 'clip';
|
|
387
|
+
/** `ST_TextHorzOverflowType`. */
|
|
388
|
+
type HorzOverflow = 'overflow' | 'clip';
|
|
389
|
+
/** The one autofit child an `a:bodyPr` may carry. */
|
|
390
|
+
type Autofit = {
|
|
391
|
+
readonly kind: 'none';
|
|
392
|
+
} | {
|
|
393
|
+
readonly kind: 'shape';
|
|
394
|
+
} | {
|
|
395
|
+
readonly kind: 'normal';
|
|
396
|
+
/** `@fontScale`, thousandths of a percent. */
|
|
397
|
+
readonly fontScale: number | undefined;
|
|
398
|
+
/** `@lnSpcReduction`, thousandths of a percent. */
|
|
399
|
+
readonly lnSpcReduction: number | undefined;
|
|
400
|
+
};
|
|
401
|
+
/**
|
|
402
|
+
* `a:bodyPr`, as the file states it.
|
|
403
|
+
*
|
|
404
|
+
* Lengths are EMU and `rot` is 60000ths of a degree, both as written. Every
|
|
405
|
+
* attribute inherits through the placeholder chain on its own - measured in 3.6
|
|
406
|
+
* at all three levels - so absence has to survive parsing.
|
|
407
|
+
*/
|
|
408
|
+
interface BodyProps {
|
|
409
|
+
readonly anchor: TextAnchor | undefined;
|
|
410
|
+
readonly anchorCtr: boolean | undefined;
|
|
411
|
+
readonly lIns: number | undefined;
|
|
412
|
+
readonly tIns: number | undefined;
|
|
413
|
+
readonly rIns: number | undefined;
|
|
414
|
+
readonly bIns: number | undefined;
|
|
415
|
+
readonly vert: VerticalText | undefined;
|
|
416
|
+
readonly wrap: TextWrap | undefined;
|
|
417
|
+
readonly vertOverflow: VertOverflow | undefined;
|
|
418
|
+
readonly horzOverflow: HorzOverflow | undefined;
|
|
419
|
+
readonly rot: number | undefined;
|
|
420
|
+
readonly upright: boolean | undefined;
|
|
421
|
+
readonly numCol: number | undefined;
|
|
422
|
+
readonly spcCol: number | undefined;
|
|
423
|
+
readonly rtlCol: boolean | undefined;
|
|
424
|
+
readonly spcFirstLastPara: boolean | undefined;
|
|
425
|
+
readonly compatLnSpc: boolean | undefined;
|
|
426
|
+
readonly fromWordArt: boolean | undefined;
|
|
427
|
+
readonly forceAA: boolean | undefined;
|
|
428
|
+
readonly autofit: Autofit | undefined;
|
|
429
|
+
readonly node: XElement;
|
|
430
|
+
}
|
|
431
|
+
/** `p:txBody` / `a:txBody`. */
|
|
432
|
+
interface TextBody {
|
|
433
|
+
readonly bodyPr: BodyProps | undefined;
|
|
434
|
+
readonly lstStyle: ListStyle | undefined;
|
|
435
|
+
readonly paragraphs: readonly Paragraph[];
|
|
436
|
+
readonly node: XElement;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* The bucket of `p:txStyles` a shape reads, or `null` for one that reads none.
|
|
440
|
+
*
|
|
441
|
+
* `other` is in the union because the element exists, not because anything
|
|
442
|
+
* reaches it - see the module comment.
|
|
443
|
+
*/
|
|
444
|
+
type TextStyleBucket = 'title' | 'body' | 'other';
|
|
445
|
+
/** `p:txStyles` on a master. */
|
|
446
|
+
interface TextStyles {
|
|
447
|
+
readonly title: ListStyle | undefined;
|
|
448
|
+
readonly body: ListStyle | undefined;
|
|
449
|
+
readonly other: ListStyle | undefined;
|
|
450
|
+
readonly node: XElement;
|
|
451
|
+
}
|
|
452
|
+
//#endregion
|
|
453
|
+
//#region src/types.d.ts
|
|
454
|
+
/** `a:off` and `a:ext` together, in EMU, plus the three transform attributes. */
|
|
455
|
+
interface Xfrm {
|
|
456
|
+
readonly x: number;
|
|
457
|
+
readonly y: number;
|
|
458
|
+
readonly cx: number;
|
|
459
|
+
readonly cy: number;
|
|
460
|
+
/** `@rot`, sixtieths of a degree. Zero when the attribute was absent. */
|
|
461
|
+
readonly rot: number;
|
|
462
|
+
readonly flipH: boolean;
|
|
463
|
+
readonly flipV: boolean;
|
|
464
|
+
/** `a:chOff`/`a:chExt`, present only on a group's `a:xfrm`. */
|
|
465
|
+
readonly child: {
|
|
466
|
+
readonly x: number;
|
|
467
|
+
readonly y: number;
|
|
468
|
+
readonly cx: number;
|
|
469
|
+
readonly cy: number;
|
|
470
|
+
} | null;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* `ST_PlaceholderType`. All nineteen, as written.
|
|
474
|
+
*
|
|
475
|
+
* Not all nineteen are legal everywhere. A slide **master** accepts only
|
|
476
|
+
* `title`, `body`, `dt`, `ftr`, `sldNum` and `hdr`: a master carrying
|
|
477
|
+
* `ctrTitle`, `subTitle`, `obj` or `pic` is repaired on open, measured in 2.9.
|
|
478
|
+
* That is not a curiosity - it is the reason the layout-to-master hop has to
|
|
479
|
+
* fold `ctrTitle` into `title` and every content type into `body`, because
|
|
480
|
+
* otherwise the stock "Title and Content" layout could inherit nothing from the
|
|
481
|
+
* stock master.
|
|
482
|
+
*/
|
|
483
|
+
type PlaceholderType = 'title' | 'body' | 'ctrTitle' | 'subTitle' | 'obj' | 'chart' | 'tbl' | 'clipArt' | 'dgm' | 'media' | 'sldImg' | 'pic' | 'sldNum' | 'hdr' | 'ftr' | 'dt';
|
|
484
|
+
declare const PLACEHOLDER_TYPES: readonly PlaceholderType[];
|
|
485
|
+
/** The six a slide master may carry. Measured; see `PlaceholderType`. */
|
|
486
|
+
declare const MASTER_PLACEHOLDER_TYPES: readonly PlaceholderType[];
|
|
487
|
+
/** `@sz`, a sizing hint. Recorded, and not part of matching - measured. */
|
|
488
|
+
type PlaceholderSize = 'full' | 'half' | 'quarter';
|
|
489
|
+
interface Placeholder {
|
|
490
|
+
/**
|
|
491
|
+
* `@type` as written, or `null` when the attribute was absent.
|
|
492
|
+
*
|
|
493
|
+
* `null` is kept rather than defaulted, because "the file said `obj`" and
|
|
494
|
+
* "the file said nothing" are different facts and only the second one is safe
|
|
495
|
+
* to rewrite. `normalizePlaceholder` supplies the default when a comparison
|
|
496
|
+
* needs one.
|
|
497
|
+
*/
|
|
498
|
+
readonly type: PlaceholderType | null;
|
|
499
|
+
/** `@idx` as written, or `null` when absent. Defaults to 0 when compared. */
|
|
500
|
+
readonly idx: number | null;
|
|
501
|
+
readonly size: PlaceholderSize | null;
|
|
502
|
+
/** `@orient`. Recorded, and not part of matching. */
|
|
503
|
+
readonly orient: 'horz' | 'vert' | null;
|
|
504
|
+
readonly hasCustomPrompt: boolean;
|
|
505
|
+
}
|
|
506
|
+
/** A placeholder with its defaults supplied: what the matcher compares. */
|
|
507
|
+
interface NormalPlaceholder {
|
|
508
|
+
readonly type: PlaceholderType;
|
|
509
|
+
readonly idx: number;
|
|
510
|
+
}
|
|
511
|
+
/** One of the six things a `p:spTree` may contain. */
|
|
512
|
+
type ShapeKind = 'sp' | 'pic' | 'grpSp' | 'graphicFrame' | 'cxnSp' | 'contentPart';
|
|
513
|
+
/** `a:lnRef`, `a:fillRef` and `a:effectRef`: an index into the style matrix. */
|
|
514
|
+
interface StyleRef {
|
|
515
|
+
/**
|
|
516
|
+
* `@idx`. Zero means none; 1..999 index the main list; 1001 and up index the
|
|
517
|
+
* background list, offset by 1000. Measured on both `a:fillRef` and
|
|
518
|
+
* `p:bgRef`, which turn out to be the same rule over the same six entries.
|
|
519
|
+
*/
|
|
520
|
+
readonly idx: number;
|
|
521
|
+
/** The colour `phClr` takes inside the entry this reference names. */
|
|
522
|
+
readonly color: Color | null;
|
|
523
|
+
}
|
|
524
|
+
/** `a:fontRef`. `@idx` is a collection name, never a number. */
|
|
525
|
+
interface FontRef {
|
|
526
|
+
readonly idx: 'major' | 'minor' | 'none';
|
|
527
|
+
readonly color: Color | null;
|
|
528
|
+
}
|
|
529
|
+
/** `p:style`: four references into the theme's `a:fmtScheme` and `a:fontScheme`. */
|
|
530
|
+
interface ShapeStyle {
|
|
531
|
+
readonly lnRef: StyleRef;
|
|
532
|
+
readonly fillRef: StyleRef;
|
|
533
|
+
readonly effectRef: StyleRef;
|
|
534
|
+
readonly fontRef: FontRef;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* A shape, exactly as its part wrote it.
|
|
538
|
+
*
|
|
539
|
+
* Everything optional here is optional *in the file*, and the resolver is the
|
|
540
|
+
* only thing entitled to fill any of it in.
|
|
541
|
+
*/
|
|
542
|
+
interface Shape {
|
|
543
|
+
readonly kind: ShapeKind;
|
|
544
|
+
/** `p:cNvPr/@id`. Unique within a part, and may repeat across parts. */
|
|
545
|
+
readonly cNvPrId: number;
|
|
546
|
+
readonly name: string;
|
|
547
|
+
/** `p:cNvPr/@descr`, the alt text. */
|
|
548
|
+
readonly descr: string | null;
|
|
549
|
+
readonly hidden: boolean;
|
|
550
|
+
readonly placeholder: Placeholder | null;
|
|
551
|
+
readonly xfrm: Xfrm | undefined;
|
|
552
|
+
readonly fill: Fill | undefined;
|
|
553
|
+
readonly line: Line | undefined;
|
|
554
|
+
readonly effects: readonly Effect[] | undefined;
|
|
555
|
+
readonly style: ShapeStyle | undefined;
|
|
556
|
+
/** `a:prstGeom/@prst`, or `null` for a `custGeom` or no geometry at all. */
|
|
557
|
+
readonly prstGeom: string | undefined;
|
|
558
|
+
/**
|
|
559
|
+
* `a:prstGeom` or `a:custGeom`, parsed far enough to draw.
|
|
560
|
+
*
|
|
561
|
+
* `undefined` when the shape declares neither, which is the ordinary state of
|
|
562
|
+
* a slide placeholder: it inherits its outline from its layout exactly as it
|
|
563
|
+
* inherits its rectangle, and `resolve` is what asks.
|
|
564
|
+
*/
|
|
565
|
+
readonly geometry: ShapeGeometry | undefined;
|
|
566
|
+
/**
|
|
567
|
+
* `p:txBody`, when the shape has one.
|
|
568
|
+
*
|
|
569
|
+
* Present on every `p:sp` PowerPoint writes, including the ones with no text
|
|
570
|
+
* in them, and absent from a `p:pic` or a `p:graphicFrame`. Its `a:lstStyle`
|
|
571
|
+
* is one level of the text cascade; the paragraphs are the text itself.
|
|
572
|
+
*/
|
|
573
|
+
readonly text: TextBody | undefined;
|
|
574
|
+
/** Children, for a `grpSp`. Empty for everything else. */
|
|
575
|
+
readonly children: readonly Shape[];
|
|
576
|
+
/** The element this was read from. Edits go here, never to the fields above. */
|
|
577
|
+
readonly node: XElement;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* `p:bg`, which is one of two quite different things.
|
|
581
|
+
*
|
|
582
|
+
* `p:bgPr` states a fill. `p:bgRef` names an entry of the theme's style matrix
|
|
583
|
+
* and the colour to invoke it with - the same mechanism as `a:fillRef` on a
|
|
584
|
+
* shape, over the same table, with the same 1000-offset. Both were measured
|
|
585
|
+
* against the same six theme entries in 2.9 and agreed on all six.
|
|
586
|
+
*/
|
|
587
|
+
type Background = {
|
|
588
|
+
readonly kind: 'fill';
|
|
589
|
+
readonly fill: Fill;
|
|
590
|
+
readonly effects: readonly Effect[] | undefined;
|
|
591
|
+
} | {
|
|
592
|
+
readonly kind: 'ref';
|
|
593
|
+
readonly ref: StyleRef;
|
|
594
|
+
};
|
|
595
|
+
/** `a:fmtScheme`: four lists of style entries, held as the elements they were. */
|
|
596
|
+
interface FormatScheme {
|
|
597
|
+
readonly name: string | null;
|
|
598
|
+
/** `a:fillStyleLst`. Each entry is a whole `EG_FillProperties` element. */
|
|
599
|
+
readonly fillStyles: readonly Fill[];
|
|
600
|
+
/** `a:lnStyleLst`. Each entry is a whole `a:ln`. */
|
|
601
|
+
readonly lineStyles: readonly Line[];
|
|
602
|
+
/** `a:effectStyleLst`. Each entry's `a:effectLst`, flattened. */
|
|
603
|
+
readonly effectStyles: readonly (readonly Effect[])[];
|
|
604
|
+
/** `a:bgFillStyleLst`, which `@idx` 1001 and up reach. */
|
|
605
|
+
readonly bgFillStyles: readonly Fill[];
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* `a:fontScheme`: the two collections `+mj-` and `+mn-` name.
|
|
609
|
+
*
|
|
610
|
+
* Three scripts each, because `a:rPr` has four typeface slots and three of them
|
|
611
|
+
* take a theme reference - `+mn-ea` on an `a:ea` is how a CJK run follows the
|
|
612
|
+
* theme. The `a:font` script-tag list under each collection is 3.7's business
|
|
613
|
+
* and is not modelled here.
|
|
614
|
+
*/
|
|
615
|
+
interface FontCollection {
|
|
616
|
+
/** `a:latin/@typeface`. An empty string means the theme states none. */
|
|
617
|
+
readonly latin: string | null;
|
|
618
|
+
readonly ea: string | null;
|
|
619
|
+
readonly cs: string | null;
|
|
620
|
+
}
|
|
621
|
+
interface FontScheme {
|
|
622
|
+
readonly name: string | null;
|
|
623
|
+
readonly major: FontCollection;
|
|
624
|
+
readonly minor: FontCollection;
|
|
625
|
+
}
|
|
626
|
+
interface Theme {
|
|
627
|
+
readonly partName: string;
|
|
628
|
+
readonly name: string | null;
|
|
629
|
+
readonly scheme: ClrScheme;
|
|
630
|
+
readonly fonts: FontScheme;
|
|
631
|
+
readonly format: FormatScheme | null;
|
|
632
|
+
readonly node: XElement;
|
|
633
|
+
}
|
|
634
|
+
type SheetKind = 'slide' | 'layout' | 'master';
|
|
635
|
+
/**
|
|
636
|
+
* `p:clrMapOvr`, which has exactly two forms and one surprise.
|
|
637
|
+
*
|
|
638
|
+
* `a:masterClrMapping` means "use the map already in force". The surprise,
|
|
639
|
+
* measured in 2.9, is what "already in force" means for a slide: it is the
|
|
640
|
+
* **layout's** map, not the master's. A layout carrying an
|
|
641
|
+
* `a:overrideClrMapping` changes the colours of every slide bound to it that
|
|
642
|
+
* says `masterClrMapping`, and a slide's own override beats its layout's. The
|
|
643
|
+
* element's name says master and it means parent.
|
|
644
|
+
*/
|
|
645
|
+
type ColorMapOverride = {
|
|
646
|
+
readonly kind: 'inherit';
|
|
647
|
+
} | {
|
|
648
|
+
readonly kind: 'override';
|
|
649
|
+
readonly map: ClrMap;
|
|
650
|
+
};
|
|
651
|
+
/**
|
|
652
|
+
* A slide, a layout or a master, with its parent already resolved.
|
|
653
|
+
*
|
|
654
|
+
* The parent link comes from **this part's own `.rels`** and from nowhere else.
|
|
655
|
+
* Not from `p:sldLayoutIdLst`, not from `p:sldMasterIdLst`, and not from the
|
|
656
|
+
* part's number in its folder: a two-master deck saved by PowerPoint numbers its
|
|
657
|
+
* layouts `slideLayout1..22` in one flat folder, and which master owns which is
|
|
658
|
+
* recorded only in the masters' relationship parts. The list elements exist to
|
|
659
|
+
* give each sheet an id and an order in the UI, not to bind anything.
|
|
660
|
+
*/
|
|
661
|
+
interface Sheet {
|
|
662
|
+
readonly kind: SheetKind;
|
|
663
|
+
readonly partName: string;
|
|
664
|
+
/** `p:cSld/@name`. */
|
|
665
|
+
readonly name: string | null;
|
|
666
|
+
/** `p:sldLayout/@type`, one of `ST_SlideLayoutType`. Layouts only. */
|
|
667
|
+
readonly layoutType: string | null;
|
|
668
|
+
/** `p:sldLayout/@matchingName`. Layouts only, and only when written. */
|
|
669
|
+
readonly matchingName: string | null;
|
|
670
|
+
readonly shapes: readonly Shape[];
|
|
671
|
+
readonly background: Background | undefined;
|
|
672
|
+
/** `p:clrMap`, on a master. `undefined` everywhere else. */
|
|
673
|
+
readonly clrMap: ClrMap | undefined;
|
|
674
|
+
/**
|
|
675
|
+
* `p:txStyles`, on a master. `undefined` everywhere else, and meaningfully so.
|
|
676
|
+
*
|
|
677
|
+
* A master that declares none does not get a partial one: PowerPoint
|
|
678
|
+
* substitutes its whole built-in set, measured in 3.1. So the difference
|
|
679
|
+
* between `undefined` and a `p:txStyles` whose buckets say nothing is the
|
|
680
|
+
* difference between a 28-point body placeholder and an 18-point one.
|
|
681
|
+
*/
|
|
682
|
+
readonly txStyles: TextStyles | undefined;
|
|
683
|
+
/** `p:clrMapOvr`, on a layout or a slide. */
|
|
684
|
+
readonly clrMapOvr: ColorMapOverride | undefined;
|
|
685
|
+
/** `@showMasterSp`, defaulting to true. Slides and layouts. */
|
|
686
|
+
readonly showMasterShapes: boolean;
|
|
687
|
+
/** The layout of a slide, the master of a layout, `null` for a master and for
|
|
688
|
+
* a sheet whose binding is missing - which PowerPoint repairs rather than
|
|
689
|
+
* refuses, so it has to be representable. */
|
|
690
|
+
readonly parent: Sheet | null;
|
|
691
|
+
/** The theme, on a master. Every other sheet reaches it through `parent`. */
|
|
692
|
+
readonly theme: Theme | null;
|
|
693
|
+
readonly node: XElement;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Where a resolved value came from.
|
|
697
|
+
*
|
|
698
|
+
* 2.9 declared this union in advance, guessing at the members the text cascade
|
|
699
|
+
* would need. 3.1 measured them, and the guess was wrong in one place:
|
|
700
|
+
* `themeObjDefaults` is gone, because `a:objectDefaults/a:spDef/a:lstStyle` is
|
|
701
|
+
* not a source. A package declaring a size there and nowhere else resolves to
|
|
702
|
+
* the built-in default, so the member named a level that never fires - see
|
|
703
|
+
* `corpus/ground-truth/text-cascade.json`.
|
|
704
|
+
*/
|
|
705
|
+
type Origin =
|
|
706
|
+
/** The run's own `a:rPr`. */
|
|
707
|
+
'run' |
|
|
708
|
+
/** The paragraph's `a:pPr`, or its `a:defRPr`. */
|
|
709
|
+
'paragraph' |
|
|
710
|
+
/** The shape itself: its `p:spPr`, or its own `a:lstStyle`. */
|
|
711
|
+
'shape' | 'layoutPh' | 'masterPh' |
|
|
712
|
+
/** The master's `p:txStyles`, in the bucket the chain's last type selects. */
|
|
713
|
+
'txStyles' |
|
|
714
|
+
/** `p:defaultTextStyle`, which only a shape with no bucket reaches. */
|
|
715
|
+
'defaultTextStyle' |
|
|
716
|
+
/** PowerPoint's own text styles, substituted for a master that declares none. */
|
|
717
|
+
'builtin' | 'theme' | 'schemaDefault';
|
|
718
|
+
/**
|
|
719
|
+
* A value, where it came from, and whether the thing that owns it said so.
|
|
720
|
+
*
|
|
721
|
+
* `explicit` is not the same as `origin === 'shape'`: a layout placeholder that
|
|
722
|
+
* declares a fill is explicit *about that fill*, and the slide that inherits it
|
|
723
|
+
* is not. The inspector's hollow-versus-filled dot is exactly this bit.
|
|
724
|
+
*/
|
|
725
|
+
interface Resolved<T> {
|
|
726
|
+
readonly value: T;
|
|
727
|
+
readonly origin: Origin;
|
|
728
|
+
readonly explicit: boolean;
|
|
729
|
+
/** The sheet the value was found on, when one was involved. */
|
|
730
|
+
readonly sheet: Sheet | null;
|
|
731
|
+
/** The shape the value was found on, when one was involved. */
|
|
732
|
+
readonly shape: Shape | null;
|
|
733
|
+
}
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/parse/paint.d.ts
|
|
736
|
+
/** One of the six `EG_ColorChoice` members. */
|
|
737
|
+
declare function parseColorElement(element: XElement): Color;
|
|
738
|
+
/** The first colour child of a wrapper such as `a:solidFill` or `a:fillRef`. */
|
|
739
|
+
declare function parseColorChild(parent: XElement | undefined): Color | null;
|
|
740
|
+
/** One member of `EG_FillProperties`. */
|
|
741
|
+
declare function parseFillElement(element: XElement, partName: string): Fill;
|
|
742
|
+
/** The fill a container declares, or `undefined` when it declares none. */
|
|
743
|
+
declare function parseFill(parent: XElement, partName: string): Fill | undefined;
|
|
744
|
+
/** `a:ln`, lazily: every field is `null` when the attribute was absent. */
|
|
745
|
+
declare function parseLineElement(element: XElement, partName: string): Line;
|
|
746
|
+
declare function parseLine(parent: XElement, partName: string): Line | undefined;
|
|
747
|
+
/**
|
|
748
|
+
* `a:effectLst`, in the order the file wrote it.
|
|
749
|
+
*
|
|
750
|
+
* Which is not the order it is painted in: 2.8 measured a glow painting *over*
|
|
751
|
+
* an outer shadow, the reverse of the schema's sequence. `effectFilter` in
|
|
752
|
+
* `paint` owns that, and this owns only the reading.
|
|
753
|
+
*
|
|
754
|
+
* `a:effectDag` is not modelled, so the shape is re-emitted byte for byte
|
|
755
|
+
* rather than approximated. PowerPoint writes none but does render one:
|
|
756
|
+
* measured on `a04-effects-03`, where it composites a glow over the fill.
|
|
757
|
+
*/
|
|
758
|
+
declare function parseEffects(parent: XElement): readonly Effect[] | undefined;
|
|
759
|
+
//#endregion
|
|
760
|
+
//#region src/parse/sheet.d.ts
|
|
761
|
+
/**
|
|
762
|
+
* `p:clrMap` or `a:overrideClrMapping`: all twelve attributes, every time.
|
|
763
|
+
*
|
|
764
|
+
* Eleven is a repair prompt, so a map that is missing one is a broken file
|
|
765
|
+
* rather than a partial opinion, and there is nothing sensible to default the
|
|
766
|
+
* missing one to.
|
|
767
|
+
*/
|
|
768
|
+
declare function parseClrMap(element: XElement, partName: string): ClrMap;
|
|
769
|
+
declare function parseTheme(root: XElement, partName: string): Theme;
|
|
770
|
+
/**
|
|
771
|
+
* One part into one sheet. The parent and the theme are filled in by
|
|
772
|
+
* `document.ts`, which is the only thing that can follow a relationship.
|
|
773
|
+
*/
|
|
774
|
+
declare function parseSheet(root: XElement, partName: string): Omit<Sheet, 'parent' | 'theme'>;
|
|
775
|
+
//#endregion
|
|
776
|
+
//#region src/resolve/placeholder.d.ts
|
|
777
|
+
/**
|
|
778
|
+
* The type of a `p:ph` that has none.
|
|
779
|
+
*
|
|
780
|
+
* `obj`, measured: a bare `<p:ph/>` on a slide reads back through PowerPoint's
|
|
781
|
+
* object model as `ppPlaceholderObject`. ECMA's own default for the attribute
|
|
782
|
+
* is `body`, and the two behave identically at the first hop because that hop
|
|
783
|
+
* ignores the type - but they differ at the second, where `obj` folds to `body`
|
|
784
|
+
* and `body` is already there. They agree, and it is worth knowing why rather
|
|
785
|
+
* than by luck.
|
|
786
|
+
*/
|
|
787
|
+
declare const DEFAULT_PLACEHOLDER_TYPE: PlaceholderType;
|
|
788
|
+
/** The `@idx` of a `p:ph` that has none. */
|
|
789
|
+
declare const DEFAULT_PLACEHOLDER_IDX = 0;
|
|
790
|
+
/** Supply the two defaults, so a comparison has something to compare. */
|
|
791
|
+
declare function normalizePlaceholder(ph: Placeholder): NormalPlaceholder;
|
|
792
|
+
/**
|
|
793
|
+
* The type a placeholder presents when it asks a master for its parent.
|
|
794
|
+
*
|
|
795
|
+
* `ctrTitle` becomes `title`; everything a master may not carry - `subTitle`,
|
|
796
|
+
* `obj`, `pic`, `chart`, `tbl`, `clipArt`, `dgm`, `media`, `sldImg` - becomes
|
|
797
|
+
* `body`. Measured on `pic`, `obj`, `subTitle` and `ctrTitle`; the rest follow
|
|
798
|
+
* because a master cannot hold them either and `body` is the only remaining
|
|
799
|
+
* content type.
|
|
800
|
+
*/
|
|
801
|
+
declare function masterPlaceholderType(type: PlaceholderType): PlaceholderType;
|
|
802
|
+
/** Every placeholder in a sheet's top-level shape tree, in document order. */
|
|
803
|
+
declare function placeholders(sheet: Sheet): readonly Shape[];
|
|
804
|
+
/**
|
|
805
|
+
* Slide to layout: the first placeholder whose `@idx` agrees.
|
|
806
|
+
*
|
|
807
|
+
* "First" matters only for a layout that has two placeholders at one index,
|
|
808
|
+
* which PowerPoint accepts without repairing; the first in the shape tree is
|
|
809
|
+
* the one that wins.
|
|
810
|
+
*/
|
|
811
|
+
declare function matchInLayout(ph: Placeholder, layout: Sheet): Shape | null;
|
|
812
|
+
/** Layout to master: the first placeholder of the folded type. */
|
|
813
|
+
declare function matchInMaster(ph: Placeholder, master: Sheet): Shape | null;
|
|
814
|
+
/** One link of the chain: a shape, the sheet it is on, and how it was reached. */
|
|
815
|
+
interface ChainLink {
|
|
816
|
+
readonly shape: Shape;
|
|
817
|
+
readonly sheet: Sheet;
|
|
818
|
+
/** `shape` for the first link, then `layoutPh`, then `masterPh`. */
|
|
819
|
+
readonly origin: 'shape' | 'layoutPh' | 'masterPh';
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* The chain a shape inherits along, nearest first.
|
|
823
|
+
*
|
|
824
|
+
* One entry for a non-placeholder, and for a placeholder that matched nothing.
|
|
825
|
+
* Up to three for a slide placeholder that reached the master. Each hop asks
|
|
826
|
+
* with the placeholder of the sheet it is leaving, which is why the layout's
|
|
827
|
+
* `@type` and not the slide's decides the second hop.
|
|
828
|
+
*/
|
|
829
|
+
declare function inheritanceChain(shape: Shape, sheet: Sheet): readonly ChainLink[];
|
|
830
|
+
/**
|
|
831
|
+
* A placeholder that reached no parent and states no geometry of its own.
|
|
832
|
+
*
|
|
833
|
+
* PowerPoint renders one at the origin with zero width and height - it does not
|
|
834
|
+
* refuse the file, does not drop the shape, and does not invent a rectangle.
|
|
835
|
+
* Measured on four probes: a title where the layout has none, a body at an index
|
|
836
|
+
* nobody has, and both against a layout with no placeholders at all.
|
|
837
|
+
*/
|
|
838
|
+
declare const ORPHAN_RECT: {
|
|
839
|
+
readonly x: 0;
|
|
840
|
+
readonly y: 0;
|
|
841
|
+
readonly cx: 0;
|
|
842
|
+
readonly cy: 0;
|
|
843
|
+
};
|
|
844
|
+
//#endregion
|
|
845
|
+
//#region src/resolve/resolve.d.ts
|
|
846
|
+
/**
|
|
847
|
+
* The first level of the chain that declared something.
|
|
848
|
+
*
|
|
849
|
+
* `pick` must return `undefined` for "this level did not say" and anything else
|
|
850
|
+
* for a value, including `null` - a shape may legitimately declare a `null`, and
|
|
851
|
+
* conflating that with silence is how an explicit `a:noFill` gets overwritten by
|
|
852
|
+
* an inherited colour.
|
|
853
|
+
*/
|
|
854
|
+
declare function resolve<T>(shape: Shape, sheet: Sheet, pick: (shape: Shape) => T | undefined): Resolved<T> | undefined;
|
|
855
|
+
/**
|
|
856
|
+
* The rectangle a shape occupies, and which sheet stated it.
|
|
857
|
+
*
|
|
858
|
+
* The single most consequential call in the package. A slide placeholder that
|
|
859
|
+
* PowerPoint wrote has **no** `a:xfrm` - not when it was created, not when text
|
|
860
|
+
* was typed into it, only when the user moved or resized it, at which point the
|
|
861
|
+
* whole resolved rectangle is baked in at once. So an absent `xfrm` is the
|
|
862
|
+
* statement "still bound to my layout", and it is what Change Layout reads.
|
|
863
|
+
*/
|
|
864
|
+
declare function resolveXfrm(shape: Shape, sheet: Sheet): Resolved<Xfrm> | undefined;
|
|
865
|
+
/** Every sheet from this one up to its master, nearest first. */
|
|
866
|
+
declare function sheetChain(sheet: Sheet): readonly Sheet[];
|
|
867
|
+
/** The master at the top of a sheet's chain, or `null` if the chain is broken. */
|
|
868
|
+
declare function masterOf(sheet: Sheet): Sheet | null;
|
|
869
|
+
/**
|
|
870
|
+
* The theme a sheet resolves against.
|
|
871
|
+
*
|
|
872
|
+
* The master's, reached through this sheet's own chain. **Not** the one
|
|
873
|
+
* `ppt/presentation.xml.rels` names: PowerPoint writes a `theme` relationship
|
|
874
|
+
* there too, it always points at `theme1.xml`, and on a two-master deck every
|
|
875
|
+
* slide on the second master would take the first master's palette. Measured -
|
|
876
|
+
* the two masters resolved `accent1` to two different colours, and each
|
|
877
|
+
* master's background used its own theme's `bgFillStyleLst`.
|
|
878
|
+
*
|
|
879
|
+
* A master must own its theme part outright: two masters pointing at the same
|
|
880
|
+
* one is repaired on open, so a shared theme is a broken file rather than an
|
|
881
|
+
* economy.
|
|
882
|
+
*/
|
|
883
|
+
declare function themeOf(sheet: Sheet): Theme | null;
|
|
884
|
+
declare function schemeOf(sheet: Sheet): ClrScheme | undefined;
|
|
885
|
+
/**
|
|
886
|
+
* The colour map in force on a sheet.
|
|
887
|
+
*
|
|
888
|
+
* `a:masterClrMapping` says "the map already in force", and the surprise is what
|
|
889
|
+
* that means: for a slide it is the **layout's** map, not the master's. Measured
|
|
890
|
+
* - a layout carrying an `a:overrideClrMapping` changed `accent1` on a slide
|
|
891
|
+
* that declared `masterClrMapping`, and a slide with an override of its own beat
|
|
892
|
+
* its layout's. The element is named for the sheet it usually ends at rather
|
|
893
|
+
* than for the one it asks.
|
|
894
|
+
*/
|
|
895
|
+
declare function colorMapOf(sheet: Sheet): ClrMap | undefined;
|
|
896
|
+
/**
|
|
897
|
+
* Everything `resolveColor` needs, for a colour written on this sheet.
|
|
898
|
+
*
|
|
899
|
+
* `phClr` is supplied by whatever style invocation the colour sits inside, and
|
|
900
|
+
* there is nothing sensible to default it to: `style.ts` passes it in, and a
|
|
901
|
+
* `schemeClr val="phClr"` reached any other way throws rather than painting
|
|
902
|
+
* black.
|
|
903
|
+
*/
|
|
904
|
+
declare function colorContextOf(sheet: Sheet, phClr?: Rgba): ColorContext;
|
|
905
|
+
//#endregion
|
|
906
|
+
//#region src/style.d.ts
|
|
907
|
+
/**
|
|
908
|
+
* The offset that separates the two style lists.
|
|
909
|
+
*
|
|
910
|
+
* `0` and `1000` mean *nothing at all*; `1..999` index the main list; `1001` and
|
|
911
|
+
* up index the background list. Measured on both `a:fillRef` and `p:bgRef`
|
|
912
|
+
* against a theme whose six entries paint six distinguishable colours - all six
|
|
913
|
+
* agreed between the two elements, and `idx="0"` and `idx="1000"` both painted
|
|
914
|
+
* nothing.
|
|
915
|
+
*/
|
|
916
|
+
declare const STYLE_MATRIX_OFFSET = 1000;
|
|
917
|
+
/** Which of the two lists an index reaches, and where in it. */
|
|
918
|
+
type StyleMatrixTarget = {
|
|
919
|
+
readonly list: 'none';
|
|
920
|
+
} | {
|
|
921
|
+
readonly list: 'main';
|
|
922
|
+
readonly at: number;
|
|
923
|
+
} | {
|
|
924
|
+
readonly list: 'background';
|
|
925
|
+
readonly at: number;
|
|
926
|
+
};
|
|
927
|
+
/**
|
|
928
|
+
* Where an index points, before anything is fetched.
|
|
929
|
+
*
|
|
930
|
+
* Out of range is not an error. A `fillRef idx="4"` against a three-entry list
|
|
931
|
+
* paints the third entry, and a `bgRef idx="9999"` paints the last background
|
|
932
|
+
* entry: PowerPoint clamps, opens the file without repairing it, and a renderer
|
|
933
|
+
* that throws here refuses a deck PowerPoint shows.
|
|
934
|
+
*/
|
|
935
|
+
declare function styleMatrixTarget(idx: number): StyleMatrixTarget;
|
|
936
|
+
/** The fill a `fillRef`/`bgRef` index names, or `null` for none. */
|
|
937
|
+
declare function styleMatrixFill(ref: StyleRef, theme: Theme): Fill | null;
|
|
938
|
+
/**
|
|
939
|
+
* The line an `lnRef` index names, or `null` for none.
|
|
940
|
+
*
|
|
941
|
+
* `a:lnStyleLst` has no background counterpart, so an index above 1000 clamps
|
|
942
|
+
* into the same list rather than reaching a second one.
|
|
943
|
+
*/
|
|
944
|
+
declare function styleMatrixLine(ref: StyleRef, theme: Theme): Line | null;
|
|
945
|
+
/** The effects an `effectRef` index names. Empty for none. */
|
|
946
|
+
declare function styleMatrixEffects(ref: StyleRef, theme: Theme): readonly Effect[];
|
|
947
|
+
/**
|
|
948
|
+
* The colour a style reference invokes its entry with.
|
|
949
|
+
*
|
|
950
|
+
* The reference's own colour child, resolved against the sheet - and it may
|
|
951
|
+
* carry transforms of its own. PowerPoint's shape-style gallery writes
|
|
952
|
+
* `<a:schemeClr val="accent1"><a:shade val="15000"/></a:schemeClr>` on seven of
|
|
953
|
+
* its forty-two entries, so `phClr` is a fully transformed colour and not a
|
|
954
|
+
* theme slot name.
|
|
955
|
+
*/
|
|
956
|
+
declare function phClrOf(ref: StyleRef, sheet: Sheet): Rgba | null;
|
|
957
|
+
/** What a shape paints, and where each half of the answer came from. */
|
|
958
|
+
interface ResolvedAppearance {
|
|
959
|
+
/** `null` means nothing is painted: no fill was declared and no style names one. */
|
|
960
|
+
readonly fill: Fill | null;
|
|
961
|
+
readonly fillOrigin: Origin | null;
|
|
962
|
+
/** The colour `phClr` resolves to inside `fill`, when it came from the theme. */
|
|
963
|
+
readonly fillPhClr: Rgba | null;
|
|
964
|
+
readonly line: Line | null;
|
|
965
|
+
readonly lineOrigin: Origin | null;
|
|
966
|
+
readonly linePhClr: Rgba | null;
|
|
967
|
+
readonly effects: readonly Effect[] | null;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* What a shape paints, following both routes and in the right order.
|
|
971
|
+
*
|
|
972
|
+
* An explicit `spPr` fill beats the `fillRef`, and an explicit `a:noFill` beats
|
|
973
|
+
* it too - both measured. A shape with neither paints nothing rather than black.
|
|
974
|
+
*
|
|
975
|
+
* The two routes are searched independently: the `spPr` fill is looked for down
|
|
976
|
+
* the whole inheritance chain first, and only if no level declared one does the
|
|
977
|
+
* `p:style` - itself inherited down the same chain - get consulted.
|
|
978
|
+
*/
|
|
979
|
+
declare function resolveAppearance(shape: Shape, sheet: Sheet): ResolvedAppearance;
|
|
980
|
+
/**
|
|
981
|
+
* A shape's fill as a single colour, when it is one.
|
|
982
|
+
*
|
|
983
|
+
* A convenience over `resolveAppearance` for the common case, and the shape the
|
|
984
|
+
* ground-truth fixture is in: PowerPoint's object model reports one RGB per
|
|
985
|
+
* shape, so this is what a measurement can be compared against.
|
|
986
|
+
*/
|
|
987
|
+
declare function resolveSolidFill(shape: Shape, sheet: Sheet): Rgba | null;
|
|
988
|
+
/** Resolve any colour written on a sheet, with an optional `phClr` in scope. */
|
|
989
|
+
declare function resolveOnSheet(color: Color, sheet: Sheet, phClr?: Rgba): Rgba;
|
|
990
|
+
//#endregion
|
|
991
|
+
//#region src/resolve/background.d.ts
|
|
992
|
+
/** A background, with the sheet that declared it and how it was expressed. */
|
|
993
|
+
interface ResolvedBackground {
|
|
994
|
+
readonly fill: Fill;
|
|
995
|
+
/** The sheet whose `p:bg` this is. */
|
|
996
|
+
readonly sheet: Sheet;
|
|
997
|
+
/** True when the sheet asked for it is the one that declared it. */
|
|
998
|
+
readonly explicit: boolean;
|
|
999
|
+
/** `bgPr` or `bgRef`, because they round-trip differently. */
|
|
1000
|
+
readonly form: 'bgPr' | 'bgRef';
|
|
1001
|
+
/** The colour `phClr` takes inside `fill`, for a `bgRef`. */
|
|
1002
|
+
readonly phClr: Rgba | null;
|
|
1003
|
+
}
|
|
1004
|
+
/** Which sheet's `p:bg` applies, without unpacking it. */
|
|
1005
|
+
declare function backgroundSheet(sheet: Sheet): {
|
|
1006
|
+
sheet: Sheet;
|
|
1007
|
+
background: Background;
|
|
1008
|
+
} | null;
|
|
1009
|
+
/**
|
|
1010
|
+
* The background of a slide, layout or master.
|
|
1011
|
+
*
|
|
1012
|
+
* `null` when no sheet in the chain declares one, which is a legal file: a deck
|
|
1013
|
+
* whose master has no `p:bg` paints nothing behind its slides.
|
|
1014
|
+
*/
|
|
1015
|
+
declare function resolveBackground(sheet: Sheet): ResolvedBackground | null;
|
|
1016
|
+
/** The background as one colour, when it is a solid. `null` otherwise. */
|
|
1017
|
+
declare function resolveBackgroundColor(sheet: Sheet): Rgba | null;
|
|
1018
|
+
//#endregion
|
|
1019
|
+
//#region src/document.d.ts
|
|
1020
|
+
/** One thing wrong with the package that did not stop the load. */
|
|
1021
|
+
interface DocumentProblem {
|
|
1022
|
+
readonly code: 'MODEL_NO_PARENT' | 'MODEL_NO_THEME' | 'MODEL_PART_MISSING' | 'MODEL_PART_KIND';
|
|
1023
|
+
readonly partName: string;
|
|
1024
|
+
readonly message: string;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* A loaded presentation: its slides, in `p:sldIdLst` order, each with its chain.
|
|
1028
|
+
*
|
|
1029
|
+
* Nothing here is a class with behaviour. It is the result of a load, and every
|
|
1030
|
+
* question about it is a free function in `resolve.ts`, `style.ts` or
|
|
1031
|
+
* `background.ts` - so a caller can hold a `Sheet` from anywhere and still ask
|
|
1032
|
+
* everything, and so the whole surface stays tree-shakable.
|
|
1033
|
+
*/
|
|
1034
|
+
interface Document {
|
|
1035
|
+
/** The presentation part, for the parts of it 2.9 does not model. */
|
|
1036
|
+
readonly presentation: XElement;
|
|
1037
|
+
readonly presentationPartName: string;
|
|
1038
|
+
/** In `p:sldIdLst` order, which *is* the deck's order. */
|
|
1039
|
+
readonly slides: readonly Sheet[];
|
|
1040
|
+
/** In `p:sldMasterIdLst` order. */
|
|
1041
|
+
readonly masters: readonly Sheet[];
|
|
1042
|
+
/** Every layout reachable from a master, in the order its master lists it. */
|
|
1043
|
+
readonly layouts: readonly Sheet[];
|
|
1044
|
+
readonly themes: readonly Theme[];
|
|
1045
|
+
readonly problems: readonly DocumentProblem[];
|
|
1046
|
+
/**
|
|
1047
|
+
* `p:defaultTextStyle`, the terminus of the text cascade for every shape that
|
|
1048
|
+
* reaches no `p:txStyles` bucket - which is every shape that is not a
|
|
1049
|
+
* placeholder, and the `dt`, `ftr`, `sldNum` and `hdr` placeholders besides.
|
|
1050
|
+
*
|
|
1051
|
+
* It lives on the presentation part, so it belongs to the package rather than
|
|
1052
|
+
* to any sheet, and `undefined` means the package declared none.
|
|
1053
|
+
*/
|
|
1054
|
+
readonly defaultTextStyle: ListStyle | undefined;
|
|
1055
|
+
/** Slide size in EMU, from `p:sldSz`. */
|
|
1056
|
+
readonly slideSize: {
|
|
1057
|
+
readonly cx: number;
|
|
1058
|
+
readonly cy: number;
|
|
1059
|
+
};
|
|
1060
|
+
sheet(partName: string): Sheet | undefined;
|
|
1061
|
+
}
|
|
1062
|
+
declare function loadDocument(store: PartStore): Document;
|
|
1063
|
+
//#endregion
|
|
1064
|
+
//#region src/parse/text.d.ts
|
|
1065
|
+
/** `a:rPr`, `a:defRPr` or `a:endParaRPr` - one type under three names. */
|
|
1066
|
+
declare function parseRunProps(element: XElement, partName: string): RunProps;
|
|
1067
|
+
/** `a:pPr`, `a:defPPr` or any `a:lvlNpPr` - one type under eleven names. */
|
|
1068
|
+
declare function parseParaProps(element: XElement, partName: string): ParaProps;
|
|
1069
|
+
/**
|
|
1070
|
+
* `a:lstStyle`, or a `p:txStyles` bucket, which is the same type unwrapped.
|
|
1071
|
+
*
|
|
1072
|
+
* The nine levels are independent: measured in 3.1, a layout placeholder
|
|
1073
|
+
* declaring only `a:lvl2pPr` changes the second level and leaves the first and
|
|
1074
|
+
* third to the master. So a level nobody declared stays `undefined` rather than
|
|
1075
|
+
* falling back to level one, and the resolver asks per level.
|
|
1076
|
+
*/
|
|
1077
|
+
declare function parseListStyle(element: XElement, partName: string): ListStyle;
|
|
1078
|
+
/** `p:txStyles` on a master. */
|
|
1079
|
+
declare function parseTextStyles(element: XElement, partName: string): TextStyles;
|
|
1080
|
+
/** `p:defaultTextStyle` on `ppt/presentation.xml`, which is a `CT_TextListStyle`. */
|
|
1081
|
+
declare function parseDefaultTextStyle(presentation: XElement, partName: string): ListStyle | undefined;
|
|
1082
|
+
/** A `p:txBody` or an `a:txBody`. */
|
|
1083
|
+
declare function parseTextBody(element: XElement, partName: string): TextBody;
|
|
1084
|
+
/** The `p:txBody` of a shape, when it has one. */
|
|
1085
|
+
declare function parseTextBodyChild(parent: XElement, partName: string): TextBody | undefined;
|
|
1086
|
+
//#endregion
|
|
1087
|
+
//#region src/builtin-text-styles.d.ts
|
|
1088
|
+
/**
|
|
1089
|
+
* PowerPoint's own `p:txStyles`, substituted when a master declares none.
|
|
1090
|
+
*
|
|
1091
|
+
* GENERATED by tools/ground-truth/text/cascade/write-tables.ts from
|
|
1092
|
+
* corpus/ground-truth/text-cascade.json. Do not edit by hand.
|
|
1093
|
+
*
|
|
1094
|
+
* Measured, not transcribed. Nine paragraphs at `lvl="0"` through `lvl="8"` in a
|
|
1095
|
+
* title placeholder, a body placeholder and a shape that is not a placeholder,
|
|
1096
|
+
* in a package whose master carries no `p:txStyles` at all, read back through
|
|
1097
|
+
* PowerPoint's own object model. The body ladder - 28, 24, 20 and then 18 for
|
|
1098
|
+
* the rest - is not a number anything in the file declares, which is how the
|
|
1099
|
+
* ladder experiment discovered there was a source below every source the plan
|
|
1100
|
+
* names.
|
|
1101
|
+
*
|
|
1102
|
+
* A PowerPoint-authored master always writes `p:txStyles`, so this table only
|
|
1103
|
+
* ever applies to a hand-written or damaged one. It exists because the
|
|
1104
|
+
* alternative is a placeholder resolving to no size at all, and because a
|
|
1105
|
+
* measured answer costs one deck.
|
|
1106
|
+
*
|
|
1107
|
+
* `bullet` says whether PowerPoint drew one, which is what 3.5 reproduces; the
|
|
1108
|
+
* glyph and its font belong to that sub-phase and are in the fixture, not here.
|
|
1109
|
+
*/
|
|
1110
|
+
/** One level of a built-in list style. */
|
|
1111
|
+
interface BuiltinLevel {
|
|
1112
|
+
/** Hundredths of a point, as `a:defRPr/@sz` holds it. */
|
|
1113
|
+
readonly sz: number;
|
|
1114
|
+
/** EMU, as `a:lvlNpPr/@marL` holds it. */
|
|
1115
|
+
readonly marL: number;
|
|
1116
|
+
/** EMU, as `a:lvlNpPr/@indent` holds it. Negative is a hanging indent. */
|
|
1117
|
+
readonly indent: number;
|
|
1118
|
+
readonly bullet: boolean;
|
|
1119
|
+
/**
|
|
1120
|
+
* The theme reference this level names, or `null` where it names none.
|
|
1121
|
+
*
|
|
1122
|
+
* A reference and not a face, because the built-in styles are the same
|
|
1123
|
+
* whatever theme a package carries: `+mj-lt` measured as the theme's major
|
|
1124
|
+
* face and `+mn-lt` as its minor.
|
|
1125
|
+
*/
|
|
1126
|
+
readonly typeface: string | null;
|
|
1127
|
+
}
|
|
1128
|
+
/** The three buckets, nine levels each, level 1 first. */
|
|
1129
|
+
declare const BUILTIN_TEXT_STYLES: {
|
|
1130
|
+
readonly title: readonly BuiltinLevel[];
|
|
1131
|
+
readonly body: readonly BuiltinLevel[];
|
|
1132
|
+
readonly other: readonly BuiltinLevel[];
|
|
1133
|
+
};
|
|
1134
|
+
/**
|
|
1135
|
+
* What is left when every source is silent and the master *does* declare
|
|
1136
|
+
* `p:txStyles`.
|
|
1137
|
+
*
|
|
1138
|
+
* Distinct from the table above, and measured separately: a body placeholder
|
|
1139
|
+
* whose `p:bodyStyle/a:lvl1pPr` declares only a `marL` came back at
|
|
1140
|
+
* 18 points rather than the built-in body style's
|
|
1141
|
+
* 28, and with no indent rather than the built-in's
|
|
1142
|
+
* hanging one. So the built-in styles are substituted wholesale for an absent
|
|
1143
|
+
* `p:txStyles` and are not a per-property backstop underneath a present one.
|
|
1144
|
+
*
|
|
1145
|
+
* `marL` and `indent` are **0**, not the ECMA-376 schema defaults of 347663 and
|
|
1146
|
+
* -342900. Materialising those at parse time gives every paragraph a
|
|
1147
|
+
* 27-point hanging indent nothing asked for, and blocks the inherited value on
|
|
1148
|
+
* top of it, because a default that has been written down cannot be told from a
|
|
1149
|
+
* declaration.
|
|
1150
|
+
*
|
|
1151
|
+
* The typeface is the minor face on all 6 probes that reach a silent cascade.
|
|
1152
|
+
*/
|
|
1153
|
+
declare const TEXT_FLOOR: BuiltinLevel;
|
|
1154
|
+
//#endregion
|
|
1155
|
+
//#region src/resolve/text.d.ts
|
|
1156
|
+
/** Which `p:txStyles` bucket a placeholder type reads, or `null` for none. */
|
|
1157
|
+
declare function bucketOf(type: string): 'title' | 'body' | null;
|
|
1158
|
+
/**
|
|
1159
|
+
* Everything the cascade needs that is not on the shape.
|
|
1160
|
+
*
|
|
1161
|
+
* `defaultTextStyle` comes from `ppt/presentation.xml` and is therefore a
|
|
1162
|
+
* property of the package rather than of any sheet, which is why it is passed
|
|
1163
|
+
* in rather than walked to. A caller that has a `Document` has it already;
|
|
1164
|
+
* `undefined` means the package declared none, which is a state PowerPoint
|
|
1165
|
+
* distinguishes and this must too.
|
|
1166
|
+
*/
|
|
1167
|
+
interface TextContext {
|
|
1168
|
+
readonly sheet: Sheet;
|
|
1169
|
+
readonly shape: Shape;
|
|
1170
|
+
readonly defaultTextStyle: ListStyle | undefined;
|
|
1171
|
+
}
|
|
1172
|
+
/** One level of the walk: a list style, and what to call it if it answers. */
|
|
1173
|
+
interface Level {
|
|
1174
|
+
readonly style: ListStyle | undefined;
|
|
1175
|
+
readonly origin: Origin;
|
|
1176
|
+
readonly sheet: Sheet | null;
|
|
1177
|
+
readonly shape: Shape | null;
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* The list styles a shape reads, nearest first, ending at whichever terminus it
|
|
1181
|
+
* reaches.
|
|
1182
|
+
*
|
|
1183
|
+
* Exported because it *is* the finding: a caller that wants to show the user
|
|
1184
|
+
* where a value could have come from - the inspector's Overrides panel, layout
|
|
1185
|
+
* compatibility scoring - needs the same list the resolver walks, not a second
|
|
1186
|
+
* opinion about it.
|
|
1187
|
+
*/
|
|
1188
|
+
declare function textLevels(context: TextContext): readonly Level[];
|
|
1189
|
+
/**
|
|
1190
|
+
* The values left when every level has been asked and none of them said.
|
|
1191
|
+
*
|
|
1192
|
+
* Two quite different things, and which applies turns on one question: does the
|
|
1193
|
+
* master declare `p:txStyles` at all? If it does not, PowerPoint substitutes its
|
|
1194
|
+
* whole built-in set, and a body placeholder is 28 points with a hanging bullet
|
|
1195
|
+
* indent. If it does, there is no per-property backstop underneath it and what
|
|
1196
|
+
* remains is the floor - 18 points, no margin, no indent. Measured as two
|
|
1197
|
+
* separate probes precisely because the two are easy to conflate and differ on
|
|
1198
|
+
* every partially-specified master.
|
|
1199
|
+
*/
|
|
1200
|
+
declare function floorOf(context: TextContext, level: number): BuiltinLevel;
|
|
1201
|
+
/**
|
|
1202
|
+
* A paragraph property, from the paragraph's own `a:pPr` or up the walk.
|
|
1203
|
+
*
|
|
1204
|
+
* `pick` returns `undefined` for "this level did not say" and anything else for
|
|
1205
|
+
* a value, including `null` - the same contract `resolve` uses, and for the same
|
|
1206
|
+
* reason: a level may legitimately declare a `null`, and conflating that with
|
|
1207
|
+
* silence is how an explicit value gets overwritten by an inherited one.
|
|
1208
|
+
*/
|
|
1209
|
+
declare function resolveParagraph<T>(context: TextContext, paragraph: Paragraph, pick: (props: ParaProps) => T | undefined): Resolved<T> | undefined;
|
|
1210
|
+
/**
|
|
1211
|
+
* A run property, from the run's own `a:rPr` and then every `a:defRPr` above it.
|
|
1212
|
+
*
|
|
1213
|
+
* The paragraph's `a:pPr/a:defRPr` is one level, not a special case: it sits
|
|
1214
|
+
* between the run and the shape's `a:lstStyle`, which the ladder pinned by
|
|
1215
|
+
* declaring a different size at each and reading back which one won.
|
|
1216
|
+
*/
|
|
1217
|
+
declare function resolveRun<T>(context: TextContext, paragraph: Paragraph, run: TextContent | undefined, pick: (props: RunProps) => T | undefined): Resolved<T> | undefined;
|
|
1218
|
+
/**
|
|
1219
|
+
* The font size of a run, in hundredths of a point, always.
|
|
1220
|
+
*
|
|
1221
|
+
* The only resolver here that cannot return `undefined`: text has to be drawn at
|
|
1222
|
+
* some size, and the size when nothing declared one is measured rather than
|
|
1223
|
+
* chosen. `origin` is `builtin` when the master declares no `p:txStyles` and
|
|
1224
|
+
* `schemaDefault` when it does and the bucket said nothing - two different
|
|
1225
|
+
* numbers on the same slide, and the field says which was used.
|
|
1226
|
+
*/
|
|
1227
|
+
declare function resolveSize(context: TextContext, paragraph: Paragraph, run: TextContent | undefined): Resolved<number>;
|
|
1228
|
+
/**
|
|
1229
|
+
* The Latin typeface of a run, with any theme reference followed.
|
|
1230
|
+
*
|
|
1231
|
+
* The second resolver that cannot return `undefined`: a run has to be drawn in
|
|
1232
|
+
* some face, and the face when nothing named one is measured rather than
|
|
1233
|
+
* chosen - the theme's minor, on all six probes reaching a silent cascade.
|
|
1234
|
+
*/
|
|
1235
|
+
declare function resolveLatinTypeface(context: TextContext, paragraph: Paragraph, run: TextContent | undefined): Resolved<string>;
|
|
1236
|
+
/** `@marL` in EMU. Measured to be 0 when nothing declares it, not 347663. */
|
|
1237
|
+
declare function resolveMarginLeft(context: TextContext, paragraph: Paragraph): Resolved<number>;
|
|
1238
|
+
/** `@indent` in EMU. Measured to be 0 when nothing declares it, not -342900. */
|
|
1239
|
+
declare function resolveIndent(context: TextContext, paragraph: Paragraph): Resolved<number>;
|
|
1240
|
+
/**
|
|
1241
|
+
* The bullet, merged the way T5 measured it: five slots, each on its own.
|
|
1242
|
+
*
|
|
1243
|
+
* The kind is one slot because the schema makes the four elements exclusive, and
|
|
1244
|
+
* the three decorations are three more because PowerPoint merges them
|
|
1245
|
+
* separately - a level declaring only `a:buFont` re-faces the character it
|
|
1246
|
+
* inherits and keeps its size and colour. Measured on eleven cases twice over,
|
|
1247
|
+
* once through a shape's own `a:lstStyle` and once through three hops of the
|
|
1248
|
+
* master chain, and the two agree.
|
|
1249
|
+
*
|
|
1250
|
+
* Every one of these returns `undefined` when nothing in the chain declares the
|
|
1251
|
+
* slot, which for the kind is the difference between "no bullet" and "nobody
|
|
1252
|
+
* said" - `a:buNone` resolves to `'none'` and an empty chain to `undefined`.
|
|
1253
|
+
* Nothing here supplies a default, because a paragraph with no bullet anywhere
|
|
1254
|
+
* in its chain genuinely has none.
|
|
1255
|
+
*/
|
|
1256
|
+
declare function resolveBulletKind(context: TextContext, paragraph: Paragraph): Resolved<BulletKind> | undefined;
|
|
1257
|
+
/** `a:buChar/@char`, as written. The symbol mapping belongs to the renderer. */
|
|
1258
|
+
declare function resolveBulletChar(context: TextContext, paragraph: Paragraph): Resolved<string> | undefined;
|
|
1259
|
+
/** `a:buAutoNum`, type and start value together, since one is meaningless alone. */
|
|
1260
|
+
declare function resolveBulletAutoNum(context: TextContext, paragraph: Paragraph): Resolved<BulletAutoNum> | undefined;
|
|
1261
|
+
/** `a:buBlip/a:blip/@r:embed`, which the caller resolves against the part's rels. */
|
|
1262
|
+
declare function resolveBulletBlip(context: TextContext, paragraph: Paragraph): Resolved<string> | undefined;
|
|
1263
|
+
/**
|
|
1264
|
+
* `a:buFont` or `a:buFontTx`.
|
|
1265
|
+
*
|
|
1266
|
+
* Worth knowing before using it: this is **inert for an autonumber**. PowerPoint
|
|
1267
|
+
* draws a number in the first run's face whatever `a:buFont` says - measured on
|
|
1268
|
+
* twenty probes, including one where `buFont` named Wingdings and the run named
|
|
1269
|
+
* Courier New - and its own UI writes `buFont="+mj-lt"` on every list it
|
|
1270
|
+
* numbers. The resolver still reports it, because the file says it and 1.3 has
|
|
1271
|
+
* to write it back; the renderer is where it is ignored.
|
|
1272
|
+
*/
|
|
1273
|
+
declare function resolveBulletFont(context: TextContext, paragraph: Paragraph): Resolved<BulletFont> | undefined;
|
|
1274
|
+
/** `a:buSzPct`, `a:buSzPts` or `a:buSzTx`; a percentage is of the first run's size. */
|
|
1275
|
+
declare function resolveBulletSize(context: TextContext, paragraph: Paragraph): Resolved<BulletSize> | undefined;
|
|
1276
|
+
/** `a:buClr` or `a:buClrTx`. Unlike the font, this one *does* reach an autonumber. */
|
|
1277
|
+
declare function resolveBulletColor(context: TextContext, paragraph: Paragraph): Resolved<BulletColor> | undefined;
|
|
1278
|
+
//#endregion
|
|
1279
|
+
//#region src/resolve/body.d.ts
|
|
1280
|
+
/**
|
|
1281
|
+
* The four insets in points, per attribute.
|
|
1282
|
+
*
|
|
1283
|
+
* Restated here rather than imported from `@pptx-studio/text`, which is a layer
|
|
1284
|
+
* below and which this package does not depend on - the same posture
|
|
1285
|
+
* `line-model.ts` takes towards `Spacing`.
|
|
1286
|
+
*/
|
|
1287
|
+
interface ResolvedInsets {
|
|
1288
|
+
readonly left: number;
|
|
1289
|
+
readonly top: number;
|
|
1290
|
+
readonly right: number;
|
|
1291
|
+
readonly bottom: number;
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* One property of the text frame, from the shape's own `a:bodyPr` or above it.
|
|
1295
|
+
*
|
|
1296
|
+
* `pick` returns `undefined` for "this level did not say", the same contract the
|
|
1297
|
+
* text cascade uses.
|
|
1298
|
+
*/
|
|
1299
|
+
declare function resolveBody<T>(shape: Shape, sheet: Sheet, pick: (props: BodyProps) => T | undefined): Resolved<T> | undefined;
|
|
1300
|
+
declare function resolveAnchor(shape: Shape, sheet: Sheet): Resolved<TextAnchor> | undefined;
|
|
1301
|
+
declare function resolveAnchorCtr(shape: Shape, sheet: Sheet): Resolved<boolean> | undefined;
|
|
1302
|
+
declare function resolveVertical(shape: Shape, sheet: Sheet): Resolved<VerticalText> | undefined;
|
|
1303
|
+
declare function resolveWrap(shape: Shape, sheet: Sheet): Resolved<TextWrap> | undefined;
|
|
1304
|
+
declare function resolveColumns(shape: Shape, sheet: Sheet): Resolved<number> | undefined;
|
|
1305
|
+
/**
|
|
1306
|
+
* The four insets, in points, each falling back on its own.
|
|
1307
|
+
*
|
|
1308
|
+
* A frame stating only `lIns` still gets 3.6 above and below, so this resolves
|
|
1309
|
+
* four times rather than once.
|
|
1310
|
+
*/
|
|
1311
|
+
declare function resolveInsets(shape: Shape, sheet: Sheet): ResolvedInsets;
|
|
1312
|
+
//#endregion
|
|
1313
|
+
//#region src/parse/body.d.ts
|
|
1314
|
+
/** Parse an `a:bodyPr`. Lengths stay in EMU and angles in 60000ths of a degree. */
|
|
1315
|
+
declare function parseBodyProps(element: XElement, partName: string): BodyProps;
|
|
1316
|
+
/** The `a:bodyPr` of a `p:txBody`, when it has one. */
|
|
1317
|
+
declare function parseBodyPropsChild(parent: XElement, partName: string): BodyProps | undefined;
|
|
1318
|
+
//#endregion
|
|
1319
|
+
//#region src/resolve/typeface.d.ts
|
|
1320
|
+
/** The four slots a `CT_TextCharacterProperties` can name. */
|
|
1321
|
+
type ScriptSlot = 'latin' | 'ea' | 'cs' | 'sym';
|
|
1322
|
+
/**
|
|
1323
|
+
* The typeface a slot asks for, with any theme reference followed.
|
|
1324
|
+
*
|
|
1325
|
+
* `undefined` means the reference resolved to a collection entry the theme
|
|
1326
|
+
* leaves empty, which is not the same as the theme naming nothing.
|
|
1327
|
+
*/
|
|
1328
|
+
declare function resolveTypeface(typeface: string, scheme: FontScheme): string | undefined;
|
|
1329
|
+
/** The same, for a whole `CT_TextFont`. */
|
|
1330
|
+
declare function resolveTypefaceOf(font: Typeface, scheme: FontScheme): string | undefined;
|
|
1331
|
+
/**
|
|
1332
|
+
* Every distinct typeface a set of runs asks for, theme references followed.
|
|
1333
|
+
*
|
|
1334
|
+
* This is what `fontReport` is given: a report keyed on `+mn-lt` would name a
|
|
1335
|
+
* token no user recognises and would collapse two themes into one row.
|
|
1336
|
+
*/
|
|
1337
|
+
declare function requestedTypefaces(fonts: Iterable<Typeface | undefined>, scheme: FontScheme): readonly string[];
|
|
1338
|
+
//#endregion
|
|
1339
|
+
export { BUILTIN_TEXT_STYLES, type Background, type BuiltinLevel, type BulletAutoNum, type BulletColor, type BulletFont, type BulletKind, type BulletSize, COLOR_TRANSFORM_OPS, type Caps, type ChainLink, type ColorMapOverride, DEFAULT_PLACEHOLDER_IDX, DEFAULT_PLACEHOLDER_TYPE, type Document, type DocumentProblem, type FontAlign, type FontCollection, type FontRef, type FontScheme, type FormatScheme, LEVELS, type ListStyle, MASTER_PLACEHOLDER_TYPES, MODEL_ERROR_CODES, ModelError, type ModelErrorCode, type NormalPlaceholder, ORPHAN_RECT, type Origin, PLACEHOLDER_TYPES, type ParaProps, type Paragraph, type Placeholder, type PlaceholderSize, type PlaceholderType, type Resolved, type ResolvedAppearance, type ResolvedBackground, type ResolvedInsets, type RunProps, STYLE_MATRIX_OFFSET, type ScriptSlot, type Shape, type ShapeGeometry, type ShapeKind, type ShapeStyle, type Sheet, type SheetKind, type Spacing, type Strike, type StyleMatrixTarget, type StyleRef, TEXT_FLOOR, type TextAlign, type TextAnchor, type TextBody, type TextBreak, type TextContent, type TextContext, type TextField, type TextRun, type TextStyleBucket, type TextStyles, type Theme, type ThemeFontRef, type Typeface, type Underline, type VerticalText, type Xfrm, backgroundSheet, bucketOf, colorContextOf, colorMapOf, floorOf, inheritanceChain, isModelError, loadDocument, masterOf, masterPlaceholderType, matchInLayout, matchInMaster, normalizePlaceholder, parseBodyProps, parseBodyPropsChild, parseClrMap, parseColorChild, parseColorElement, parseDefaultTextStyle, parseEffects, parseFill, parseFillElement, parseGeometry, parseLine, parseLineElement, parseListStyle, parseParaProps, parseRunProps, parseSheet, parseTextBody, parseTextBodyChild, parseTextStyles, parseTheme, phClrOf, placeholders, requestedTypefaces, resolve, resolveAnchor, resolveAnchorCtr, resolveAppearance, resolveBackground, resolveBackgroundColor, resolveBody, resolveBulletAutoNum, resolveBulletBlip, resolveBulletChar, resolveBulletColor, resolveBulletFont, resolveBulletKind, resolveBulletSize, resolveColumns, resolveIndent, resolveInsets, resolveLatinTypeface, resolveMarginLeft, resolveOnSheet, resolveParagraph, resolveRun, resolveSize, resolveSolidFill, resolveTypeface, resolveTypefaceOf, resolveVertical, resolveWrap, resolveXfrm, schemeOf, sheetChain, styleMatrixEffects, styleMatrixFill, styleMatrixLine, styleMatrixTarget, textLevels, themeFontRef, themeOf };
|
|
1340
|
+
//# sourceMappingURL=index.d.ts.map
|