@shbernal/ts-pptx 3.4.0 → 3.6.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/dist/{autopage-BYlTzX-l.js → autopage-DkjYZUFD.js} +3 -3
- package/dist/{autopage-BYlTzX-l.js.map → autopage-DkjYZUFD.js.map} +1 -1
- package/dist/browser.d.ts +5 -5
- package/dist/browser.js +4 -4
- package/dist/browser.js.map +1 -1
- package/dist/{diagnostics-B0OmTOoz.d.ts → diagnostics-Du_s75MT.d.ts} +20 -5
- package/dist/diagnostics-Du_s75MT.d.ts.map +1 -0
- package/dist/{errors-fB1KDJKQ.d.ts → errors-PflMPWBn.d.ts} +3 -3
- package/dist/{errors-fB1KDJKQ.d.ts.map → errors-PflMPWBn.d.ts.map} +1 -1
- package/dist/{fit-TjpNbMru.js → fit-BKs0zxMI.js} +3 -3
- package/dist/{fit-TjpNbMru.js.map → fit-BKs0zxMI.js.map} +1 -1
- package/dist/{html-dom-yUSdCExA.js → html-dom-B0I0QSbU.js} +4 -4
- package/dist/{html-dom-yUSdCExA.js.map → html-dom-B0I0QSbU.js.map} +1 -1
- package/dist/html.d.ts +3 -3
- package/dist/html.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -3
- package/dist/inspect.d.ts +28 -4
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +42 -11
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/measure.d.ts +2 -2
- package/dist/measure.js +1 -1
- package/dist/{namespaces-Sy_m7Nhd.js → namespaces-BVnNu7sg.js} +77 -3
- package/dist/namespaces-BVnNu7sg.js.map +1 -0
- package/dist/node.d.ts +5 -5
- package/dist/node.js +3 -3
- package/dist/{notes-bWApshah.js → notes-RLCwdlTE.js} +289 -313
- package/dist/{notes-bWApshah.js.map → notes-RLCwdlTE.js.map} +1 -1
- package/dist/{pres-Dybf7ZUl.d.ts → pres-C5__xkDh.d.ts} +2 -2
- package/dist/{pres-Dybf7ZUl.d.ts.map → pres-C5__xkDh.d.ts.map} +1 -1
- package/dist/{presentation-3rAKKRfm.js → presentation-Cp7vzlAw.js} +566 -519
- package/dist/presentation-Cp7vzlAw.js.map +1 -0
- package/dist/{presentation-types-D7cgT-eG.d.ts → presentation-types-DP_8jog7.d.ts} +514 -276
- package/dist/presentation-types-DP_8jog7.d.ts.map +1 -0
- package/dist/read.d.ts +31 -48
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +3 -3
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +84 -75
- package/dist/script.js.map +1 -1
- package/dist/{shapes-Dyw5bxwO.js → shapes-BemroU-z.js} +1010 -306
- package/dist/shapes-BemroU-z.js.map +1 -0
- package/dist/{slide-B_aInw3N.d.ts → slide-js0QpRV-.d.ts} +1278 -1254
- package/dist/slide-js0QpRV-.d.ts.map +1 -0
- package/dist/{text-DSN3anEh.js → text-CyetbF6p.js} +2039 -1417
- package/dist/text-CyetbF6p.js.map +1 -0
- package/dist/units-1kRzYShk.js +231 -0
- package/dist/units-1kRzYShk.js.map +1 -0
- package/dist/units-internal-Dg95w_YD.js +753 -0
- package/dist/units-internal-Dg95w_YD.js.map +1 -0
- package/dist/zip.d.ts +1 -1
- package/package.json +2 -1
- package/dist/diagnostics-B0OmTOoz.d.ts.map +0 -1
- package/dist/diagnostics-CPVADSL1.js +0 -90
- package/dist/diagnostics-CPVADSL1.js.map +0 -1
- package/dist/namespaces-Sy_m7Nhd.js.map +0 -1
- package/dist/presentation-3rAKKRfm.js.map +0 -1
- package/dist/presentation-types-D7cgT-eG.d.ts.map +0 -1
- package/dist/shapes-Dyw5bxwO.js.map +0 -1
- package/dist/slide-B_aInw3N.d.ts.map +0 -1
- package/dist/text-DSN3anEh.js.map +0 -1
- package/dist/units-internal-DNvK2I6o.js +0 -896
- package/dist/units-internal-DNvK2I6o.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as EMU_PER_POINT, s as PERCENT_SCALE, t as ANGLE_UNITS_PER_DEGREE, x as warn } from "./units-1kRzYShk.js";
|
|
2
2
|
import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-Bvln0H-7.js";
|
|
3
|
-
import {
|
|
3
|
+
import { F as TEXT_VERTICAL, L as checkEnumOrThrow, N as TEXT_ANCHORS, P as TEXT_HORZ_OVERFLOW, a as NOTES_MASTER_REL, c as OFFICE_DOCUMENT_REL, h as SLIDE_MASTER_REL, p as SLIDE_LAYOUT_REL, r as IMAGE_REL, t as OOXML_NS, v as THEME_REL, x as getImageSizeFromBytes, y as fitSrcRectPercents } from "./namespaces-BVnNu7sg.js";
|
|
4
4
|
import { DOMParser, MIME_TYPE, XMLSerializer, onErrorStopParsing } from "@xmldom/xmldom";
|
|
5
5
|
/** Parse an XML string strictly: any well-formedness error throws. */
|
|
6
6
|
function parseXml(xml) {
|
|
@@ -458,6 +458,439 @@ function setSolidFill(parent, afterOrder, color) {
|
|
|
458
458
|
fill.appendChild(clr);
|
|
459
459
|
}
|
|
460
460
|
//#endregion
|
|
461
|
+
//#region src/read/oxml/color-transform.ts
|
|
462
|
+
/**
|
|
463
|
+
* Apply DrawingML colour-transform modifiers (`lumMod`/`lumOff`/`shade`/`tint`/
|
|
464
|
+
* `satMod`/`alpha`/…) to a base sRGB colour, returning the *effective* colour a
|
|
465
|
+
* renderer would paint.
|
|
466
|
+
*
|
|
467
|
+
* The read model resolves a `schemeClr`/`srgbClr` reference to its **base** hex
|
|
468
|
+
* and carries the transform children verbatim (so the `theme: 'preserve'` flatten
|
|
469
|
+
* path can re-emit them byte-for-byte). This module is the missing step that
|
|
470
|
+
* turns that base hex + transform list into the final rendered hex, so a consumer
|
|
471
|
+
* never hand-computes a tint/shade again.
|
|
472
|
+
*
|
|
473
|
+
* Colour-space model (verified against PowerPoint output — see
|
|
474
|
+
* `test/read/color-transform.test.js`): the working colour is kept canonical as
|
|
475
|
+
* sRGB between transforms; each transform converts into the space its family
|
|
476
|
+
* operates in, applies, and converts back to sRGB. Transforms apply in **document
|
|
477
|
+
* order** (ECMA-376 §20.1.2.3).
|
|
478
|
+
*
|
|
479
|
+
* - `lumMod` / `lumOff` — luminance (L) in HSL: `L' = L·mod + off`. PowerPoint's
|
|
480
|
+
* "Lighter/Darker N%" family.
|
|
481
|
+
* - `satMod` / `satOff` — saturation (S) in HSL.
|
|
482
|
+
* - `hueMod` / `hueOff` — hue (H) in HSL (`hueMod` scales, `hueOff` offsets by
|
|
483
|
+
* degrees). Not exercised by any current source; implemented for completeness.
|
|
484
|
+
* - `shade` — toward black in **linear** RGB: `c' = c·k`.
|
|
485
|
+
* - `tint` — toward white in **linear** RGB: `c' = c·k + (1−k)`.
|
|
486
|
+
* - `alpha` / `alphaMod` / `alphaOff` — opacity, returned alongside the hex
|
|
487
|
+
* (never folded into RGB).
|
|
488
|
+
* - `comp` / `inv` / `gray` / `gamma` / `invGamma` — pass-through for now (no
|
|
489
|
+
* current source needs them; add when one does).
|
|
490
|
+
*
|
|
491
|
+
* All DrawingML percentage values are stored in thousandths of a percent
|
|
492
|
+
* (`100%` → `100000`), so a modifier's fraction is `val / PERCENT_SCALE`.
|
|
493
|
+
*/
|
|
494
|
+
/**
|
|
495
|
+
* DrawingML percentage → fraction, or `null` when unparseable.
|
|
496
|
+
*
|
|
497
|
+
* `a:ST_Percentage` is a *union* in the Transitional profile: the fixed-point integer form
|
|
498
|
+
* Office writes (`100%` → `100000`) and a decimal string with a literal `%` (`-?[0-9]+(\.[0-9]+)?%`),
|
|
499
|
+
* which is the only form the Strict profile has. Both are read here — a reader that took only the
|
|
500
|
+
* first dropped a schema-legal value silently, and the two are one `endsWith` apart.
|
|
501
|
+
* @param value - the raw attribute value, or `null` when the attribute is absent
|
|
502
|
+
*/
|
|
503
|
+
function parsePercent(value) {
|
|
504
|
+
if (value === null || value === "") return null;
|
|
505
|
+
if (value.endsWith("%")) {
|
|
506
|
+
const n = Number(value.slice(0, -1));
|
|
507
|
+
return Number.isFinite(n) ? n / 100 : null;
|
|
508
|
+
}
|
|
509
|
+
const n = Number(value);
|
|
510
|
+
return Number.isFinite(n) ? n / PERCENT_SCALE : null;
|
|
511
|
+
}
|
|
512
|
+
const clamp01 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
|
|
513
|
+
/** Parse a 6-hex string (`RRGGBB`, optional `#`) into 0–1 sRGB channels, or `null`. */
|
|
514
|
+
function parseHex(hex) {
|
|
515
|
+
const h = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
516
|
+
if (!/^[0-9a-fA-F]{6}$/.test(h)) return null;
|
|
517
|
+
return {
|
|
518
|
+
r: parseInt(h.slice(0, 2), 16) / 255,
|
|
519
|
+
g: parseInt(h.slice(2, 4), 16) / 255,
|
|
520
|
+
b: parseInt(h.slice(4, 6), 16) / 255
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
/** 0–1 sRGB channels → uppercase `RRGGBB`, rounding and clamping each channel. */
|
|
524
|
+
function toHex(c) {
|
|
525
|
+
const ch = (v) => Math.round(clamp01(v) * 255).toString(16).toUpperCase().padStart(2, "0");
|
|
526
|
+
return `${ch(c.r)}${ch(c.g)}${ch(c.b)}`;
|
|
527
|
+
}
|
|
528
|
+
/** sRGB channel (0–1) → linear-light (gamma decode). */
|
|
529
|
+
function srgbToLinear(c) {
|
|
530
|
+
return c <= .04045 ? c / 12.92 : Math.pow((c + .055) / 1.055, 2.4);
|
|
531
|
+
}
|
|
532
|
+
/** Linear-light channel (0–1) → sRGB (gamma encode). */
|
|
533
|
+
function linearToSrgb(c) {
|
|
534
|
+
return c <= .0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - .055;
|
|
535
|
+
}
|
|
536
|
+
/** sRGB (0–1) → HSL with H in degrees [0,360), S/L in [0,1]. */
|
|
537
|
+
function rgbToHsl(c) {
|
|
538
|
+
const { r, g, b } = c;
|
|
539
|
+
const max = Math.max(r, g, b);
|
|
540
|
+
const min = Math.min(r, g, b);
|
|
541
|
+
const l = (max + min) / 2;
|
|
542
|
+
const d = max - min;
|
|
543
|
+
if (d === 0) return {
|
|
544
|
+
h: 0,
|
|
545
|
+
s: 0,
|
|
546
|
+
l
|
|
547
|
+
};
|
|
548
|
+
const s = d / (1 - Math.abs(2 * l - 1));
|
|
549
|
+
let h;
|
|
550
|
+
if (max === r) h = (g - b) / d % 6;
|
|
551
|
+
else if (max === g) h = (b - r) / d + 2;
|
|
552
|
+
else h = (r - g) / d + 4;
|
|
553
|
+
h *= 60;
|
|
554
|
+
if (h < 0) h += 360;
|
|
555
|
+
return {
|
|
556
|
+
h,
|
|
557
|
+
s,
|
|
558
|
+
l
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
/** HSL (H degrees, S/L 0–1) → sRGB (0–1). */
|
|
562
|
+
function hslToRgb({ h, s, l }) {
|
|
563
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
564
|
+
const hp = (h % 360 + 360) % 360 / 60;
|
|
565
|
+
const x = c * (1 - Math.abs(hp % 2 - 1));
|
|
566
|
+
const [r, g, b] = hp < 1 ? [
|
|
567
|
+
c,
|
|
568
|
+
x,
|
|
569
|
+
0
|
|
570
|
+
] : hp < 2 ? [
|
|
571
|
+
x,
|
|
572
|
+
c,
|
|
573
|
+
0
|
|
574
|
+
] : hp < 3 ? [
|
|
575
|
+
0,
|
|
576
|
+
c,
|
|
577
|
+
x
|
|
578
|
+
] : hp < 4 ? [
|
|
579
|
+
0,
|
|
580
|
+
x,
|
|
581
|
+
c
|
|
582
|
+
] : hp < 5 ? [
|
|
583
|
+
x,
|
|
584
|
+
0,
|
|
585
|
+
c
|
|
586
|
+
] : [
|
|
587
|
+
c,
|
|
588
|
+
0,
|
|
589
|
+
x
|
|
590
|
+
];
|
|
591
|
+
const m = l - c / 2;
|
|
592
|
+
return {
|
|
593
|
+
r: r + m,
|
|
594
|
+
g: g + m,
|
|
595
|
+
b: b + m
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* An `a:hslClr` triple → 6-hex sRGB, or `null` when any of the three is unparseable.
|
|
600
|
+
*
|
|
601
|
+
* The colour space is the one `lumMod`/`satMod` already work in — DrawingML's HSL is sRGB-HSL,
|
|
602
|
+
* which is what the transform family below is verified against — so this shares that conversion
|
|
603
|
+
* rather than introducing a second one. Units are the schema's: `@hue` is
|
|
604
|
+
* `a:ST_PositiveFixedAngle`, i.e. 60,000ths of a degree, and `@sat`/`@lum` are `a:ST_Percentage`
|
|
605
|
+
* (see {@link parsePercent}). Saturation and luminance are clamped to 0–1; hue wraps.
|
|
606
|
+
* @param hue - raw `@hue`
|
|
607
|
+
* @param sat - raw `@sat`
|
|
608
|
+
* @param lum - raw `@lum`
|
|
609
|
+
*/
|
|
610
|
+
function hslClrToHex(hue, sat, lum) {
|
|
611
|
+
const h = hue === null || hue === "" ? null : Number(hue);
|
|
612
|
+
const s = parsePercent(sat);
|
|
613
|
+
const l = parsePercent(lum);
|
|
614
|
+
if (h === null || !Number.isFinite(h) || s === null || l === null) return null;
|
|
615
|
+
return toHex(hslToRgb({
|
|
616
|
+
h: h / ANGLE_UNITS_PER_DEGREE,
|
|
617
|
+
s: clamp01(s),
|
|
618
|
+
l: clamp01(l)
|
|
619
|
+
}));
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Apply an ordered list of DrawingML colour transforms to a base sRGB hex,
|
|
623
|
+
* returning the effective sRGB hex (and opacity, when an `alpha*` modifier set
|
|
624
|
+
* it). Pure: no DOM, no theme lookup — the caller has already resolved the base
|
|
625
|
+
* colour and extracted each modifier's `{ name, value }`.
|
|
626
|
+
*
|
|
627
|
+
* An unparseable base hex is returned unchanged (with no transforms applied); an
|
|
628
|
+
* unparseable/`null` modifier value is skipped.
|
|
629
|
+
*/
|
|
630
|
+
function applyColorTransforms(baseHex, transforms) {
|
|
631
|
+
const parsed = parseHex(baseHex);
|
|
632
|
+
if (!parsed) return { hex: baseHex };
|
|
633
|
+
let rgb = parsed;
|
|
634
|
+
let alpha;
|
|
635
|
+
for (const { name, value } of transforms) switch (name) {
|
|
636
|
+
case "lumMod":
|
|
637
|
+
case "lumOff": {
|
|
638
|
+
const f = parsePercent(value);
|
|
639
|
+
if (f === null) break;
|
|
640
|
+
const hsl = rgbToHsl(rgb);
|
|
641
|
+
hsl.l = clamp01(name === "lumMod" ? hsl.l * f : hsl.l + f);
|
|
642
|
+
rgb = hslToRgb(hsl);
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
case "satMod":
|
|
646
|
+
case "satOff": {
|
|
647
|
+
const f = parsePercent(value);
|
|
648
|
+
if (f === null) break;
|
|
649
|
+
const hsl = rgbToHsl(rgb);
|
|
650
|
+
hsl.s = clamp01(name === "satMod" ? hsl.s * f : hsl.s + f);
|
|
651
|
+
rgb = hslToRgb(hsl);
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
case "hueMod":
|
|
655
|
+
case "hueOff": {
|
|
656
|
+
const hsl = rgbToHsl(rgb);
|
|
657
|
+
if (name === "hueMod") {
|
|
658
|
+
const f = parsePercent(value);
|
|
659
|
+
if (f === null) break;
|
|
660
|
+
hsl.h = (hsl.h * f % 360 + 360) % 360;
|
|
661
|
+
} else {
|
|
662
|
+
const n = value === null ? NaN : Number(value);
|
|
663
|
+
if (!Number.isFinite(n)) break;
|
|
664
|
+
hsl.h = ((hsl.h + n / ANGLE_UNITS_PER_DEGREE) % 360 + 360) % 360;
|
|
665
|
+
}
|
|
666
|
+
rgb = hslToRgb(hsl);
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
case "shade":
|
|
670
|
+
case "tint": {
|
|
671
|
+
const k = parsePercent(value);
|
|
672
|
+
if (k === null) break;
|
|
673
|
+
const lin = {
|
|
674
|
+
r: srgbToLinear(rgb.r),
|
|
675
|
+
g: srgbToLinear(rgb.g),
|
|
676
|
+
b: srgbToLinear(rgb.b)
|
|
677
|
+
};
|
|
678
|
+
const apply = (c) => clamp01(name === "shade" ? c * k : c * k + (1 - k));
|
|
679
|
+
rgb = {
|
|
680
|
+
r: linearToSrgb(apply(lin.r)),
|
|
681
|
+
g: linearToSrgb(apply(lin.g)),
|
|
682
|
+
b: linearToSrgb(apply(lin.b))
|
|
683
|
+
};
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
case "alpha": {
|
|
687
|
+
const f = parsePercent(value);
|
|
688
|
+
if (f !== null) alpha = clamp01(f);
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
case "alphaMod": {
|
|
692
|
+
const f = parsePercent(value);
|
|
693
|
+
if (f !== null) alpha = clamp01((alpha ?? 1) * f);
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
case "alphaOff": {
|
|
697
|
+
const f = parsePercent(value);
|
|
698
|
+
if (f !== null) alpha = clamp01((alpha ?? 1) + f);
|
|
699
|
+
break;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return alpha === void 0 ? { hex: toHex(rgb) } : {
|
|
703
|
+
hex: toHex(rgb),
|
|
704
|
+
alpha
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
//#endregion
|
|
708
|
+
//#region src/read/oxml/preset-color.ts
|
|
709
|
+
/**
|
|
710
|
+
* The ECMA-376 preset colour table (`a:prstClr/@val` → literal RGB).
|
|
711
|
+
*
|
|
712
|
+
* `ST_PresetColorVal` (§20.1.10.47) enumerates 190 names, and the standard gives each one an
|
|
713
|
+
* RGB triple. They are the HTML/CSS named colours: every value in the enumeration has the same
|
|
714
|
+
* RGB here as the CSS colour of the same name, and the 190 names collapse to the 140 distinct
|
|
715
|
+
* CSS names below through three mechanical spelling rules the enumeration adds on top —
|
|
716
|
+
*
|
|
717
|
+
* - abbreviated prefixes: `dk*`/`lt*`/`med*` alongside `dark*`/`light*`/`medium*`
|
|
718
|
+
* (`dkSlateBlue` is `darkSlateBlue`), and only as a *prefix* — `medium…` is not `mediumium…`;
|
|
719
|
+
* - both spellings of grey: `dimGrey` is `dimGray`;
|
|
720
|
+
* - case: the enumeration is camelCase, the table below is folded to lower case.
|
|
721
|
+
*
|
|
722
|
+
* So the table holds one row per colour rather than one per spelling, and {@link presetColorHex}
|
|
723
|
+
* normalizes a name into it. That is the difference between 140 hand-checked constants and 190,
|
|
724
|
+
* and it makes the abbreviation rule something a reader can see rather than something spread
|
|
725
|
+
* across fifty near-duplicate rows.
|
|
726
|
+
*
|
|
727
|
+
* This is spec data, not observed behaviour: the values come from the enumeration's own
|
|
728
|
+
* documentation, and the table is asserted complete against the schema's 190-value list in
|
|
729
|
+
* `test/read/preset-color.test.js` — a name the reader cannot resolve is a hole in the table,
|
|
730
|
+
* and that test is what finds it.
|
|
731
|
+
*/
|
|
732
|
+
/**
|
|
733
|
+
* Canonical (lower-case, unabbreviated, `gray`-spelled) preset colour name → 6-hex RGB.
|
|
734
|
+
* Reach it through {@link presetColorHex}, which does the normalizing.
|
|
735
|
+
*/
|
|
736
|
+
const PRESET_COLOR_HEX = {
|
|
737
|
+
aliceblue: "F0F8FF",
|
|
738
|
+
antiquewhite: "FAEBD7",
|
|
739
|
+
aqua: "00FFFF",
|
|
740
|
+
aquamarine: "7FFFD4",
|
|
741
|
+
azure: "F0FFFF",
|
|
742
|
+
beige: "F5F5DC",
|
|
743
|
+
bisque: "FFE4C4",
|
|
744
|
+
black: "000000",
|
|
745
|
+
blanchedalmond: "FFEBCD",
|
|
746
|
+
blue: "0000FF",
|
|
747
|
+
blueviolet: "8A2BE2",
|
|
748
|
+
brown: "A52A2A",
|
|
749
|
+
burlywood: "DEB887",
|
|
750
|
+
cadetblue: "5F9EA0",
|
|
751
|
+
chartreuse: "7FFF00",
|
|
752
|
+
chocolate: "D2691E",
|
|
753
|
+
coral: "FF7F50",
|
|
754
|
+
cornflowerblue: "6495ED",
|
|
755
|
+
cornsilk: "FFF8DC",
|
|
756
|
+
crimson: "DC143C",
|
|
757
|
+
cyan: "00FFFF",
|
|
758
|
+
darkblue: "00008B",
|
|
759
|
+
darkcyan: "008B8B",
|
|
760
|
+
darkgoldenrod: "B8860B",
|
|
761
|
+
darkgray: "A9A9A9",
|
|
762
|
+
darkgreen: "006400",
|
|
763
|
+
darkkhaki: "BDB76B",
|
|
764
|
+
darkmagenta: "8B008B",
|
|
765
|
+
darkolivegreen: "556B2F",
|
|
766
|
+
darkorange: "FF8C00",
|
|
767
|
+
darkorchid: "9932CC",
|
|
768
|
+
darkred: "8B0000",
|
|
769
|
+
darksalmon: "E9967A",
|
|
770
|
+
darkseagreen: "8FBC8F",
|
|
771
|
+
darkslateblue: "483D8B",
|
|
772
|
+
darkslategray: "2F4F4F",
|
|
773
|
+
darkturquoise: "00CED1",
|
|
774
|
+
darkviolet: "9400D3",
|
|
775
|
+
deeppink: "FF1493",
|
|
776
|
+
deepskyblue: "00BFFF",
|
|
777
|
+
dimgray: "696969",
|
|
778
|
+
dodgerblue: "1E90FF",
|
|
779
|
+
firebrick: "B22222",
|
|
780
|
+
floralwhite: "FFFAF0",
|
|
781
|
+
forestgreen: "228B22",
|
|
782
|
+
fuchsia: "FF00FF",
|
|
783
|
+
gainsboro: "DCDCDC",
|
|
784
|
+
ghostwhite: "F8F8FF",
|
|
785
|
+
gold: "FFD700",
|
|
786
|
+
goldenrod: "DAA520",
|
|
787
|
+
gray: "808080",
|
|
788
|
+
green: "008000",
|
|
789
|
+
greenyellow: "ADFF2F",
|
|
790
|
+
honeydew: "F0FFF0",
|
|
791
|
+
hotpink: "FF69B4",
|
|
792
|
+
indianred: "CD5C5C",
|
|
793
|
+
indigo: "4B0082",
|
|
794
|
+
ivory: "FFFFF0",
|
|
795
|
+
khaki: "F0E68C",
|
|
796
|
+
lavender: "E6E6FA",
|
|
797
|
+
lavenderblush: "FFF0F5",
|
|
798
|
+
lawngreen: "7CFC00",
|
|
799
|
+
lemonchiffon: "FFFACD",
|
|
800
|
+
lightblue: "ADD8E6",
|
|
801
|
+
lightcoral: "F08080",
|
|
802
|
+
lightcyan: "E0FFFF",
|
|
803
|
+
lightgoldenrodyellow: "FAFAD2",
|
|
804
|
+
lightgray: "D3D3D3",
|
|
805
|
+
lightgreen: "90EE90",
|
|
806
|
+
lightpink: "FFB6C1",
|
|
807
|
+
lightsalmon: "FFA07A",
|
|
808
|
+
lightseagreen: "20B2AA",
|
|
809
|
+
lightskyblue: "87CEFA",
|
|
810
|
+
lightslategray: "778899",
|
|
811
|
+
lightsteelblue: "B0C4DE",
|
|
812
|
+
lightyellow: "FFFFE0",
|
|
813
|
+
lime: "00FF00",
|
|
814
|
+
limegreen: "32CD32",
|
|
815
|
+
linen: "FAF0E6",
|
|
816
|
+
magenta: "FF00FF",
|
|
817
|
+
maroon: "800000",
|
|
818
|
+
mediumaquamarine: "66CDAA",
|
|
819
|
+
mediumblue: "0000CD",
|
|
820
|
+
mediumorchid: "BA55D3",
|
|
821
|
+
mediumpurple: "9370DB",
|
|
822
|
+
mediumseagreen: "3CB371",
|
|
823
|
+
mediumslateblue: "7B68EE",
|
|
824
|
+
mediumspringgreen: "00FA9A",
|
|
825
|
+
mediumturquoise: "48D1CC",
|
|
826
|
+
mediumvioletred: "C71585",
|
|
827
|
+
midnightblue: "191970",
|
|
828
|
+
mintcream: "F5FFFA",
|
|
829
|
+
mistyrose: "FFE4E1",
|
|
830
|
+
moccasin: "FFE4B5",
|
|
831
|
+
navajowhite: "FFDEAD",
|
|
832
|
+
navy: "000080",
|
|
833
|
+
oldlace: "FDF5E6",
|
|
834
|
+
olive: "808000",
|
|
835
|
+
olivedrab: "6B8E23",
|
|
836
|
+
orange: "FFA500",
|
|
837
|
+
orangered: "FF4500",
|
|
838
|
+
orchid: "DA70D6",
|
|
839
|
+
palegoldenrod: "EEE8AA",
|
|
840
|
+
palegreen: "98FB98",
|
|
841
|
+
paleturquoise: "AFEEEE",
|
|
842
|
+
palevioletred: "DB7093",
|
|
843
|
+
papayawhip: "FFEFD5",
|
|
844
|
+
peachpuff: "FFDAB9",
|
|
845
|
+
peru: "CD853F",
|
|
846
|
+
pink: "FFC0CB",
|
|
847
|
+
plum: "DDA0DD",
|
|
848
|
+
powderblue: "B0E0E6",
|
|
849
|
+
purple: "800080",
|
|
850
|
+
red: "FF0000",
|
|
851
|
+
rosybrown: "BC8F8F",
|
|
852
|
+
royalblue: "4169E1",
|
|
853
|
+
saddlebrown: "8B4513",
|
|
854
|
+
salmon: "FA8072",
|
|
855
|
+
sandybrown: "F4A460",
|
|
856
|
+
seagreen: "2E8B57",
|
|
857
|
+
seashell: "FFF5EE",
|
|
858
|
+
sienna: "A0522D",
|
|
859
|
+
silver: "C0C0C0",
|
|
860
|
+
skyblue: "87CEEB",
|
|
861
|
+
slateblue: "6A5ACD",
|
|
862
|
+
slategray: "708090",
|
|
863
|
+
snow: "FFFAFA",
|
|
864
|
+
springgreen: "00FF7F",
|
|
865
|
+
steelblue: "4682B4",
|
|
866
|
+
tan: "D2B48C",
|
|
867
|
+
teal: "008080",
|
|
868
|
+
thistle: "D8BFD8",
|
|
869
|
+
tomato: "FF6347",
|
|
870
|
+
turquoise: "40E0D0",
|
|
871
|
+
violet: "EE82EE",
|
|
872
|
+
wheat: "F5DEB3",
|
|
873
|
+
white: "FFFFFF",
|
|
874
|
+
whitesmoke: "F5F5F5",
|
|
875
|
+
yellow: "FFFF00",
|
|
876
|
+
yellowgreen: "9ACD32"
|
|
877
|
+
};
|
|
878
|
+
/**
|
|
879
|
+
* Resolve an `a:prstClr/@val` preset colour name to its 6-hex RGB, or `null` when the name is
|
|
880
|
+
* not one of the 190 `ST_PresetColorVal` values.
|
|
881
|
+
*
|
|
882
|
+
* Lenient about case for the same reason the rest of the read path is: the input is a file
|
|
883
|
+
* someone else wrote, and a producer that spelled `Black` has still said which colour it meant.
|
|
884
|
+
* A name that is not in the enumeration at all resolves to `null` rather than to a guess, so the
|
|
885
|
+
* caller reports "no colour" instead of painting an invented one.
|
|
886
|
+
* @param name - the raw attribute value, or `null` when the attribute is absent
|
|
887
|
+
*/
|
|
888
|
+
function presetColorHex(name) {
|
|
889
|
+
if (!name) return null;
|
|
890
|
+
const canonical = name.toLowerCase().replace(/grey/g, "gray").replace(/^dk/, "dark").replace(/^lt/, "light").replace(/^med(?!ium)/, "medium");
|
|
891
|
+
return PRESET_COLOR_HEX[canonical] ?? null;
|
|
892
|
+
}
|
|
893
|
+
//#endregion
|
|
461
894
|
//#region src/read/oxml/theme.ts
|
|
462
895
|
/**
|
|
463
896
|
* Theme colour resolution: turning a DrawingML colour reference or a style-matrix reference into
|
|
@@ -551,17 +984,34 @@ function resolveSchemeToken(token, ctx) {
|
|
|
551
984
|
function isA(el, local) {
|
|
552
985
|
return !!el && el.namespaceURI === OOXML_NS.a && el.localName === local;
|
|
553
986
|
}
|
|
554
|
-
/**
|
|
987
|
+
/**
|
|
988
|
+
* The literal RGB of a *non-scheme* colour element, or `null` for one that needs the theme
|
|
989
|
+
* (`a:schemeClr`) or that this reader does not resolve.
|
|
990
|
+
*
|
|
991
|
+
* Four of `a:EG_ColorChoice`'s six members land here. `a:scrgbClr` is the one deliberately left
|
|
992
|
+
* out: its channels are percentages of a colour space the schema does not pin down, so whether
|
|
993
|
+
* `50%` is linear-light or sRGB-encoded decides the answer and neither the schema nor the
|
|
994
|
+
* transform work in `color-transform.ts` settles it. Guessing would produce a colour that is
|
|
995
|
+
* wrong by a gamma curve and says nothing about it, which is worse than reporting no colour.
|
|
996
|
+
* Closing it needs a render oracle — a deck with an `a:scrgbClr` fill authored in PowerPoint
|
|
997
|
+
* and the painted pixel read back — not a reading of the schema.
|
|
998
|
+
*/
|
|
555
999
|
function colorElementHex(color) {
|
|
556
1000
|
if (!color) return null;
|
|
557
1001
|
if (isA(color, "srgbClr")) return attr(color, "val");
|
|
558
1002
|
if (isA(color, "sysClr")) return attr(color, "lastClr") ?? attr(color, "val");
|
|
1003
|
+
if (isA(color, "prstClr")) return presetColorHex(attr(color, "val"));
|
|
1004
|
+
if (isA(color, "hslClr")) return hslClrToHex(attr(color, "hue"), attr(color, "sat"), attr(color, "lum"));
|
|
559
1005
|
return null;
|
|
560
1006
|
}
|
|
561
1007
|
/**
|
|
562
1008
|
* Resolve a DrawingML colour element to a literal `{ hex, transforms }`, routing
|
|
563
1009
|
* `a:schemeClr` through the context. Returns `null` when the base cannot be made
|
|
564
1010
|
* literal (unmapped token, or a colour model we do not flatten).
|
|
1011
|
+
*
|
|
1012
|
+
* Five of `a:EG_ColorChoice`'s six members resolve: `a:srgbClr`, `a:sysClr`, `a:schemeClr`,
|
|
1013
|
+
* `a:prstClr` (through the {@link presetColorHex} table) and `a:hslClr`. `a:scrgbClr` does not —
|
|
1014
|
+
* see {@link colorElementHex} for why that one is a `null` rather than a guess.
|
|
565
1015
|
*/
|
|
566
1016
|
function resolveColor(color, ctx) {
|
|
567
1017
|
if (!color) return null;
|
|
@@ -573,7 +1023,7 @@ function resolveColor(color, ctx) {
|
|
|
573
1023
|
transforms
|
|
574
1024
|
} : null;
|
|
575
1025
|
}
|
|
576
|
-
if (isA(color, "sysClr")) {
|
|
1026
|
+
if (isA(color, "sysClr") || isA(color, "prstClr") || isA(color, "hslClr")) {
|
|
577
1027
|
const hex = colorElementHex(color);
|
|
578
1028
|
return hex ? {
|
|
579
1029
|
hex,
|
|
@@ -1003,219 +1453,39 @@ function placeholderInheritedXfrm(type, idx, ctx) {
|
|
|
1003
1453
|
return null;
|
|
1004
1454
|
}
|
|
1005
1455
|
/**
|
|
1006
|
-
* The vertical anchor (`a:bodyPr/@anchor`) a placeholder inherits from the source
|
|
1007
|
-
* layout, then master, or `null`. Resolves per-attribute: the first tier whose
|
|
1008
|
-
* placeholder `a:bodyPr` actually sets `@anchor` wins, so a layout `a:bodyPr`
|
|
1009
|
-
* present but without `@anchor` does not mask the master's. The read-model
|
|
1010
|
-
* `TextFrame.resolvedAnchor` sibling of {@link placeholderInheritedXfrm}.
|
|
1011
|
-
*/
|
|
1012
|
-
function placeholderInheritedAnchor(type, idx, ctx) {
|
|
1013
|
-
for (const root of [ctx.layoutRoot, ctx.masterRoot]) {
|
|
1014
|
-
if (!root) continue;
|
|
1015
|
-
const ph = findPlaceholder(root, type, idx);
|
|
1016
|
-
const txBody = ph && firstChild(ph, "p:txBody");
|
|
1017
|
-
const bodyPr = txBody && firstChild(txBody, "a:bodyPr");
|
|
1018
|
-
const anchor = bodyPr && attr(bodyPr, "anchor");
|
|
1019
|
-
if (anchor) return anchor;
|
|
1020
|
-
}
|
|
1021
|
-
return null;
|
|
1022
|
-
}
|
|
1023
|
-
/** Whether the *slide itself* already fixes this run's colour (so a rebind cannot change it). */
|
|
1024
|
-
function slideDefinesColor(run, pPr, slideLst, level) {
|
|
1025
|
-
const rPr = firstChild(run, "a:rPr");
|
|
1026
|
-
if (rPr && FILL_CHOICES.some((q) => firstChild(rPr, q))) return true;
|
|
1027
|
-
const defRPr = pPr && firstChild(pPr, "a:defRPr");
|
|
1028
|
-
if (defRPr && firstChild(defRPr, "a:solidFill")) return true;
|
|
1029
|
-
return !!lstStyleLevelFill(slideLst, level);
|
|
1030
|
-
}
|
|
1031
|
-
/** Whether the *slide itself* already fixes a run property (so a rebind cannot change it). */
|
|
1032
|
-
function slideDefinesProp(name, run, pPr, slideLst, level) {
|
|
1033
|
-
const rPr = firstChild(run, "a:rPr");
|
|
1034
|
-
if (rPr && attr(rPr, name) != null) return true;
|
|
1035
|
-
const defRPr = pPr && firstChild(pPr, "a:defRPr");
|
|
1036
|
-
if (defRPr && attr(defRPr, name) != null) return true;
|
|
1037
|
-
const slideDefRPr = lstStyleLevelDefRPr(slideLst, level);
|
|
1038
|
-
return !!(slideDefRPr && attr(slideDefRPr, name) != null);
|
|
1039
|
-
}
|
|
1040
|
-
//#endregion
|
|
1041
|
-
//#region src/read/oxml/color-transform.ts
|
|
1042
|
-
/** DrawingML percentage (`100%` = `100000`) → fraction, or `null` when unparseable. */
|
|
1043
|
-
function pct(value) {
|
|
1044
|
-
if (value === null || value === "") return null;
|
|
1045
|
-
const n = Number(value);
|
|
1046
|
-
return Number.isFinite(n) ? n / 1e5 : null;
|
|
1047
|
-
}
|
|
1048
|
-
const clamp01 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
|
|
1049
|
-
/** Parse a 6-hex string (`RRGGBB`, optional `#`) into 0–1 sRGB channels, or `null`. */
|
|
1050
|
-
function parseHex(hex) {
|
|
1051
|
-
const h = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
1052
|
-
if (!/^[0-9a-fA-F]{6}$/.test(h)) return null;
|
|
1053
|
-
return {
|
|
1054
|
-
r: parseInt(h.slice(0, 2), 16) / 255,
|
|
1055
|
-
g: parseInt(h.slice(2, 4), 16) / 255,
|
|
1056
|
-
b: parseInt(h.slice(4, 6), 16) / 255
|
|
1057
|
-
};
|
|
1058
|
-
}
|
|
1059
|
-
/** 0–1 sRGB channels → uppercase `RRGGBB`, rounding and clamping each channel. */
|
|
1060
|
-
function toHex(c) {
|
|
1061
|
-
const ch = (v) => Math.round(clamp01(v) * 255).toString(16).toUpperCase().padStart(2, "0");
|
|
1062
|
-
return `${ch(c.r)}${ch(c.g)}${ch(c.b)}`;
|
|
1063
|
-
}
|
|
1064
|
-
/** sRGB channel (0–1) → linear-light (gamma decode). */
|
|
1065
|
-
function srgbToLinear(c) {
|
|
1066
|
-
return c <= .04045 ? c / 12.92 : Math.pow((c + .055) / 1.055, 2.4);
|
|
1067
|
-
}
|
|
1068
|
-
/** Linear-light channel (0–1) → sRGB (gamma encode). */
|
|
1069
|
-
function linearToSrgb(c) {
|
|
1070
|
-
return c <= .0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - .055;
|
|
1071
|
-
}
|
|
1072
|
-
/** sRGB (0–1) → HSL with H in degrees [0,360), S/L in [0,1]. */
|
|
1073
|
-
function rgbToHsl(c) {
|
|
1074
|
-
const { r, g, b } = c;
|
|
1075
|
-
const max = Math.max(r, g, b);
|
|
1076
|
-
const min = Math.min(r, g, b);
|
|
1077
|
-
const l = (max + min) / 2;
|
|
1078
|
-
const d = max - min;
|
|
1079
|
-
if (d === 0) return {
|
|
1080
|
-
h: 0,
|
|
1081
|
-
s: 0,
|
|
1082
|
-
l
|
|
1083
|
-
};
|
|
1084
|
-
const s = d / (1 - Math.abs(2 * l - 1));
|
|
1085
|
-
let h;
|
|
1086
|
-
if (max === r) h = (g - b) / d % 6;
|
|
1087
|
-
else if (max === g) h = (b - r) / d + 2;
|
|
1088
|
-
else h = (r - g) / d + 4;
|
|
1089
|
-
h *= 60;
|
|
1090
|
-
if (h < 0) h += 360;
|
|
1091
|
-
return {
|
|
1092
|
-
h,
|
|
1093
|
-
s,
|
|
1094
|
-
l
|
|
1095
|
-
};
|
|
1096
|
-
}
|
|
1097
|
-
/** HSL (H degrees, S/L 0–1) → sRGB (0–1). */
|
|
1098
|
-
function hslToRgb({ h, s, l }) {
|
|
1099
|
-
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
1100
|
-
const hp = (h % 360 + 360) % 360 / 60;
|
|
1101
|
-
const x = c * (1 - Math.abs(hp % 2 - 1));
|
|
1102
|
-
const [r, g, b] = hp < 1 ? [
|
|
1103
|
-
c,
|
|
1104
|
-
x,
|
|
1105
|
-
0
|
|
1106
|
-
] : hp < 2 ? [
|
|
1107
|
-
x,
|
|
1108
|
-
c,
|
|
1109
|
-
0
|
|
1110
|
-
] : hp < 3 ? [
|
|
1111
|
-
0,
|
|
1112
|
-
c,
|
|
1113
|
-
x
|
|
1114
|
-
] : hp < 4 ? [
|
|
1115
|
-
0,
|
|
1116
|
-
x,
|
|
1117
|
-
c
|
|
1118
|
-
] : hp < 5 ? [
|
|
1119
|
-
x,
|
|
1120
|
-
0,
|
|
1121
|
-
c
|
|
1122
|
-
] : [
|
|
1123
|
-
c,
|
|
1124
|
-
0,
|
|
1125
|
-
x
|
|
1126
|
-
];
|
|
1127
|
-
const m = l - c / 2;
|
|
1128
|
-
return {
|
|
1129
|
-
r: r + m,
|
|
1130
|
-
g: g + m,
|
|
1131
|
-
b: b + m
|
|
1132
|
-
};
|
|
1133
|
-
}
|
|
1134
|
-
/**
|
|
1135
|
-
* Apply an ordered list of DrawingML colour transforms to a base sRGB hex,
|
|
1136
|
-
* returning the effective sRGB hex (and opacity, when an `alpha*` modifier set
|
|
1137
|
-
* it). Pure: no DOM, no theme lookup — the caller has already resolved the base
|
|
1138
|
-
* colour and extracted each modifier's `{ name, value }`.
|
|
1139
|
-
*
|
|
1140
|
-
* An unparseable base hex is returned unchanged (with no transforms applied); an
|
|
1141
|
-
* unparseable/`null` modifier value is skipped.
|
|
1456
|
+
* The vertical anchor (`a:bodyPr/@anchor`) a placeholder inherits from the source
|
|
1457
|
+
* layout, then master, or `null`. Resolves per-attribute: the first tier whose
|
|
1458
|
+
* placeholder `a:bodyPr` actually sets `@anchor` wins, so a layout `a:bodyPr`
|
|
1459
|
+
* present but without `@anchor` does not mask the master's. The read-model
|
|
1460
|
+
* `TextFrame.resolvedAnchor` sibling of {@link placeholderInheritedXfrm}.
|
|
1142
1461
|
*/
|
|
1143
|
-
function
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
const f = pct(value);
|
|
1152
|
-
if (f === null) break;
|
|
1153
|
-
const hsl = rgbToHsl(rgb);
|
|
1154
|
-
hsl.l = clamp01(name === "lumMod" ? hsl.l * f : hsl.l + f);
|
|
1155
|
-
rgb = hslToRgb(hsl);
|
|
1156
|
-
break;
|
|
1157
|
-
}
|
|
1158
|
-
case "satMod":
|
|
1159
|
-
case "satOff": {
|
|
1160
|
-
const f = pct(value);
|
|
1161
|
-
if (f === null) break;
|
|
1162
|
-
const hsl = rgbToHsl(rgb);
|
|
1163
|
-
hsl.s = clamp01(name === "satMod" ? hsl.s * f : hsl.s + f);
|
|
1164
|
-
rgb = hslToRgb(hsl);
|
|
1165
|
-
break;
|
|
1166
|
-
}
|
|
1167
|
-
case "hueMod":
|
|
1168
|
-
case "hueOff": {
|
|
1169
|
-
const hsl = rgbToHsl(rgb);
|
|
1170
|
-
if (name === "hueMod") {
|
|
1171
|
-
const f = pct(value);
|
|
1172
|
-
if (f === null) break;
|
|
1173
|
-
hsl.h = (hsl.h * f % 360 + 360) % 360;
|
|
1174
|
-
} else {
|
|
1175
|
-
const n = value === null ? NaN : Number(value);
|
|
1176
|
-
if (!Number.isFinite(n)) break;
|
|
1177
|
-
hsl.h = ((hsl.h + n / 6e4) % 360 + 360) % 360;
|
|
1178
|
-
}
|
|
1179
|
-
rgb = hslToRgb(hsl);
|
|
1180
|
-
break;
|
|
1181
|
-
}
|
|
1182
|
-
case "shade":
|
|
1183
|
-
case "tint": {
|
|
1184
|
-
const k = pct(value);
|
|
1185
|
-
if (k === null) break;
|
|
1186
|
-
const lin = {
|
|
1187
|
-
r: srgbToLinear(rgb.r),
|
|
1188
|
-
g: srgbToLinear(rgb.g),
|
|
1189
|
-
b: srgbToLinear(rgb.b)
|
|
1190
|
-
};
|
|
1191
|
-
const apply = (c) => clamp01(name === "shade" ? c * k : c * k + (1 - k));
|
|
1192
|
-
rgb = {
|
|
1193
|
-
r: linearToSrgb(apply(lin.r)),
|
|
1194
|
-
g: linearToSrgb(apply(lin.g)),
|
|
1195
|
-
b: linearToSrgb(apply(lin.b))
|
|
1196
|
-
};
|
|
1197
|
-
break;
|
|
1198
|
-
}
|
|
1199
|
-
case "alpha": {
|
|
1200
|
-
const f = pct(value);
|
|
1201
|
-
if (f !== null) alpha = clamp01(f);
|
|
1202
|
-
break;
|
|
1203
|
-
}
|
|
1204
|
-
case "alphaMod": {
|
|
1205
|
-
const f = pct(value);
|
|
1206
|
-
if (f !== null) alpha = clamp01((alpha ?? 1) * f);
|
|
1207
|
-
break;
|
|
1208
|
-
}
|
|
1209
|
-
case "alphaOff": {
|
|
1210
|
-
const f = pct(value);
|
|
1211
|
-
if (f !== null) alpha = clamp01((alpha ?? 1) + f);
|
|
1212
|
-
break;
|
|
1213
|
-
}
|
|
1462
|
+
function placeholderInheritedAnchor(type, idx, ctx) {
|
|
1463
|
+
for (const root of [ctx.layoutRoot, ctx.masterRoot]) {
|
|
1464
|
+
if (!root) continue;
|
|
1465
|
+
const ph = findPlaceholder(root, type, idx);
|
|
1466
|
+
const txBody = ph && firstChild(ph, "p:txBody");
|
|
1467
|
+
const bodyPr = txBody && firstChild(txBody, "a:bodyPr");
|
|
1468
|
+
const anchor = bodyPr && attr(bodyPr, "anchor");
|
|
1469
|
+
if (anchor) return anchor;
|
|
1214
1470
|
}
|
|
1215
|
-
return
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1471
|
+
return null;
|
|
1472
|
+
}
|
|
1473
|
+
/** Whether the *slide itself* already fixes this run's colour (so a rebind cannot change it). */
|
|
1474
|
+
function slideDefinesColor(run, pPr, slideLst, level) {
|
|
1475
|
+
const rPr = firstChild(run, "a:rPr");
|
|
1476
|
+
if (rPr && FILL_CHOICES.some((q) => firstChild(rPr, q))) return true;
|
|
1477
|
+
const defRPr = pPr && firstChild(pPr, "a:defRPr");
|
|
1478
|
+
if (defRPr && firstChild(defRPr, "a:solidFill")) return true;
|
|
1479
|
+
return !!lstStyleLevelFill(slideLst, level);
|
|
1480
|
+
}
|
|
1481
|
+
/** Whether the *slide itself* already fixes a run property (so a rebind cannot change it). */
|
|
1482
|
+
function slideDefinesProp(name, run, pPr, slideLst, level) {
|
|
1483
|
+
const rPr = firstChild(run, "a:rPr");
|
|
1484
|
+
if (rPr && attr(rPr, name) != null) return true;
|
|
1485
|
+
const defRPr = pPr && firstChild(pPr, "a:defRPr");
|
|
1486
|
+
if (defRPr && attr(defRPr, name) != null) return true;
|
|
1487
|
+
const slideDefRPr = lstStyleLevelDefRPr(slideLst, level);
|
|
1488
|
+
return !!(slideDefRPr && attr(slideDefRPr, name) != null);
|
|
1219
1489
|
}
|
|
1220
1490
|
//#endregion
|
|
1221
1491
|
//#region src/read/api/theme-context.ts
|
|
@@ -1459,22 +1729,44 @@ function resolveInheritedRunFontFace(ph, level, pPr, slideLstStyle, ctx) {
|
|
|
1459
1729
|
return null;
|
|
1460
1730
|
}
|
|
1461
1731
|
/**
|
|
1462
|
-
* Whether a run effectively renders
|
|
1463
|
-
* walking the same chain as
|
|
1464
|
-
*
|
|
1732
|
+
* Whether a run effectively renders with the boolean character property `name`
|
|
1733
|
+
* (`b`/`i`) when its own `a:rPr` sets none, walking the same chain as
|
|
1734
|
+
* {@link resolveInheritedRunSize}: the first `a:defRPr/@<name>` in the paragraph →
|
|
1465
1735
|
* slide → (placeholder) layout → master → `p:txStyles` → `p:defaultTextStyle`
|
|
1466
|
-
* chain.
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1736
|
+
* chain. The first tier that *states* the attribute wins, and its value is parsed
|
|
1737
|
+
* by {@link boolValue} — the same `xsd:boolean` parser the run's own `bold`/`italic`
|
|
1738
|
+
* getters use — so an unparseable value reports `null` rather than being read as
|
|
1739
|
+
* `false`. `null` when nothing in the chain states it.
|
|
1469
1740
|
*/
|
|
1470
|
-
function
|
|
1741
|
+
function resolveInheritedRunFlag(name, ph, level, pPr, slideLstStyle, ctx) {
|
|
1471
1742
|
for (const defRPr of inheritedRunDefRPrs(ph, level, pPr, slideLstStyle, ctx)) {
|
|
1472
|
-
const
|
|
1473
|
-
if (
|
|
1743
|
+
const raw = attr(defRPr, name);
|
|
1744
|
+
if (raw !== null) return boolValue(raw);
|
|
1474
1745
|
}
|
|
1475
1746
|
return null;
|
|
1476
1747
|
}
|
|
1477
1748
|
/**
|
|
1749
|
+
* Whether a run effectively renders bold when its own `a:rPr` sets no `@b`: the
|
|
1750
|
+
* first `a:defRPr/@b` in the inheritance chain (see {@link resolveInheritedRunFlag}).
|
|
1751
|
+
* A non-placeholder run skips the placeholder tiers but still reaches
|
|
1752
|
+
* `p:defaultTextStyle` (which sets no `@b` in a PowerPoint-written deck, so bold
|
|
1753
|
+
* stays `null` there). `null` when nothing in the chain defines bold.
|
|
1754
|
+
*/
|
|
1755
|
+
function resolveInheritedRunBold(ph, level, pPr, slideLstStyle, ctx) {
|
|
1756
|
+
return resolveInheritedRunFlag("b", ph, level, pPr, slideLstStyle, ctx);
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Whether a run effectively renders italic when its own `a:rPr` sets no `@i`: the
|
|
1760
|
+
* first `a:defRPr/@i` in the inheritance chain (see {@link resolveInheritedRunFlag}).
|
|
1761
|
+
* `@b` and `@i` are siblings on `CT_TextCharacterProperties` and a master text
|
|
1762
|
+
* style states them together, so this is the exact twin of
|
|
1763
|
+
* {@link resolveInheritedRunBold} one attribute along. `null` when nothing in the
|
|
1764
|
+
* chain defines italic.
|
|
1765
|
+
*/
|
|
1766
|
+
function resolveInheritedRunItalic(ph, level, pPr, slideLstStyle, ctx) {
|
|
1767
|
+
return resolveInheritedRunFlag("i", ph, level, pPr, slideLstStyle, ctx);
|
|
1768
|
+
}
|
|
1769
|
+
/**
|
|
1478
1770
|
* The vertical anchor a placeholder text frame effectively renders when its own
|
|
1479
1771
|
* `a:bodyPr` sets no `@anchor`: the value inherited from the layout → master
|
|
1480
1772
|
* placeholder `a:bodyPr` (see {@link placeholderInheritedAnchor}). `null` when the
|
|
@@ -1515,8 +1807,9 @@ function resolveInheritedFrame(ph, ctx) {
|
|
|
1515
1807
|
};
|
|
1516
1808
|
}
|
|
1517
1809
|
/**
|
|
1518
|
-
* Resolve a DrawingML colour *element* (`a:
|
|
1519
|
-
* against `ctx` into a full
|
|
1810
|
+
* Resolve a DrawingML colour *element* (every `a:EG_ColorChoice` member except
|
|
1811
|
+
* `a:scrgbClr` — see `read/oxml/theme.ts`) against `ctx` into a full
|
|
1812
|
+
* {@link ResolvedColor} — base hex, raw transform list,
|
|
1520
1813
|
* and the `effectiveHex`/`alpha` after applying those transforms. `null` when the
|
|
1521
1814
|
* element cannot be made literal (unmapped token, or a colour model we do not
|
|
1522
1815
|
* resolve). Shared by the solid-fill and gradient-stop colour reads.
|
|
@@ -1616,14 +1909,17 @@ function readGradientStops(container, ctx) {
|
|
|
1616
1909
|
const gsLst = firstChild(grad, "a:gsLst");
|
|
1617
1910
|
if (!gsLst) return [];
|
|
1618
1911
|
return getElements(gsLst, "a:gs").map((gs) => {
|
|
1912
|
+
const colorEl = firstChildElement(gs);
|
|
1913
|
+
const model = colorEl?.localName ?? null;
|
|
1619
1914
|
const pos = intValue(attr(gs, "pos"));
|
|
1620
|
-
const
|
|
1621
|
-
const
|
|
1622
|
-
const resolved = resolveColorElement(srgb ?? scheme ?? null, ctx);
|
|
1915
|
+
const resolved = resolveColorElement(colorEl, ctx);
|
|
1916
|
+
const rawOf = (local) => colorEl && model === local ? attr(colorEl, "val") : null;
|
|
1623
1917
|
return {
|
|
1624
|
-
position: pos === null ? null : pos /
|
|
1625
|
-
color:
|
|
1626
|
-
schemeColor:
|
|
1918
|
+
position: pos === null ? null : pos / PERCENT_SCALE,
|
|
1919
|
+
color: rawOf("srgbClr"),
|
|
1920
|
+
schemeColor: rawOf("schemeClr"),
|
|
1921
|
+
presetColor: rawOf("prstClr"),
|
|
1922
|
+
resolvedColor: resolved,
|
|
1627
1923
|
effectiveHex: resolved ? resolved.effectiveHex : null,
|
|
1628
1924
|
...resolved?.alpha !== void 0 ? { alpha: resolved.alpha } : {}
|
|
1629
1925
|
};
|
|
@@ -1642,7 +1938,7 @@ function readGradientFill(container, ctx) {
|
|
|
1642
1938
|
const ang = lin ? intValue(attr(lin, "ang")) : null;
|
|
1643
1939
|
return {
|
|
1644
1940
|
kind: lin ? "linear" : path ? "path" : null,
|
|
1645
|
-
angleDeg: ang === null ? null : ang /
|
|
1941
|
+
angleDeg: ang === null ? null : ang / ANGLE_UNITS_PER_DEGREE,
|
|
1646
1942
|
path: path ? attr(path, "path") ?? null : null,
|
|
1647
1943
|
stops: readGradientStops(container, ctx) ?? []
|
|
1648
1944
|
};
|
|
@@ -1664,7 +1960,7 @@ function readGradientFill(container, ctx) {
|
|
|
1664
1960
|
function readRect(rect) {
|
|
1665
1961
|
const edge = (name) => {
|
|
1666
1962
|
const v = intValue(attr(rect, name));
|
|
1667
|
-
return v === null ? 0 : v /
|
|
1963
|
+
return v === null ? 0 : v / PERCENT_SCALE;
|
|
1668
1964
|
};
|
|
1669
1965
|
return {
|
|
1670
1966
|
left: edge("l"),
|
|
@@ -1677,7 +1973,7 @@ function readRect(rect) {
|
|
|
1677
1973
|
function readTile(tile) {
|
|
1678
1974
|
const scale = (name) => {
|
|
1679
1975
|
const v = intValue(attr(tile, name));
|
|
1680
|
-
return v === null ? 1 : v /
|
|
1976
|
+
return v === null ? 1 : v / PERCENT_SCALE;
|
|
1681
1977
|
};
|
|
1682
1978
|
return {
|
|
1683
1979
|
offsetXEmu: intValue(attr(tile, "tx")) ?? 0,
|
|
@@ -1720,7 +2016,7 @@ function readPictureFill(container, rels = null) {
|
|
|
1720
2016
|
srcRect: srcRect ? readRect(srcRect) : null,
|
|
1721
2017
|
fillRect: fillRect ? readRect(fillRect) : null,
|
|
1722
2018
|
tile: tile ? readTile(tile) : null,
|
|
1723
|
-
alpha: alphaMod ? amt === null ? 1 : amt /
|
|
2019
|
+
alpha: alphaMod ? amt === null ? 1 : amt / PERCENT_SCALE : null,
|
|
1724
2020
|
dpi: intValue(attr(blipFill, "dpi")),
|
|
1725
2021
|
rotWithShape: boolValue(attr(blipFill, "rotWithShape"))
|
|
1726
2022
|
};
|
|
@@ -1862,8 +2158,8 @@ function readGeometryPath(path) {
|
|
|
1862
2158
|
cmd: "arcTo",
|
|
1863
2159
|
wR: intValue(attr(seg, "wR")) ?? 0,
|
|
1864
2160
|
hR: intValue(attr(seg, "hR")) ?? 0,
|
|
1865
|
-
stAng: (intValue(attr(seg, "stAng")) ?? 0) /
|
|
1866
|
-
swAng: (intValue(attr(seg, "swAng")) ?? 0) /
|
|
2161
|
+
stAng: (intValue(attr(seg, "stAng")) ?? 0) / ANGLE_UNITS_PER_DEGREE,
|
|
2162
|
+
swAng: (intValue(attr(seg, "swAng")) ?? 0) / ANGLE_UNITS_PER_DEGREE
|
|
1867
2163
|
});
|
|
1868
2164
|
break;
|
|
1869
2165
|
case "close": commands.push({ cmd: "close" });
|
|
@@ -1901,7 +2197,7 @@ function readBox(xfrm, offName, extName) {
|
|
|
1901
2197
|
}
|
|
1902
2198
|
function rotationDegrees(xfrm) {
|
|
1903
2199
|
const rot = intValue(attr(xfrm, "rot"));
|
|
1904
|
-
return rot === null ? 0 : rot /
|
|
2200
|
+
return rot === null ? 0 : rot / ANGLE_UNITS_PER_DEGREE;
|
|
1905
2201
|
}
|
|
1906
2202
|
function transformFlipH(xfrm) {
|
|
1907
2203
|
return boolValue(attr(xfrm, "flipH")) === true;
|
|
@@ -2045,9 +2341,10 @@ var Run = class {
|
|
|
2045
2341
|
inheritedSize;
|
|
2046
2342
|
inheritedFace;
|
|
2047
2343
|
inheritedBold;
|
|
2344
|
+
inheritedItalic;
|
|
2048
2345
|
relationships;
|
|
2049
2346
|
fontRef;
|
|
2050
|
-
constructor(element, part, themeContext, inheritedColor, inheritedSize, inheritedFace, inheritedBold, relationships, fontRef) {
|
|
2347
|
+
constructor(element, part, themeContext, inheritedColor, inheritedSize, inheritedFace, inheritedBold, inheritedItalic, relationships, fontRef) {
|
|
2051
2348
|
this.element = element;
|
|
2052
2349
|
this.part = part;
|
|
2053
2350
|
this.themeContext = themeContext;
|
|
@@ -2055,6 +2352,7 @@ var Run = class {
|
|
|
2055
2352
|
this.inheritedSize = inheritedSize;
|
|
2056
2353
|
this.inheritedFace = inheritedFace;
|
|
2057
2354
|
this.inheritedBold = inheritedBold;
|
|
2355
|
+
this.inheritedItalic = inheritedItalic;
|
|
2058
2356
|
this.relationships = relationships;
|
|
2059
2357
|
this.fontRef = fontRef;
|
|
2060
2358
|
}
|
|
@@ -2284,6 +2582,19 @@ var Run = class {
|
|
|
2284
2582
|
get resolvedBold() {
|
|
2285
2583
|
return this.bold ?? this.inheritedBold?.() ?? null;
|
|
2286
2584
|
}
|
|
2585
|
+
/**
|
|
2586
|
+
* Whether this run effectively renders italic. It is the run's own `@i`
|
|
2587
|
+
* ({@link italic}) when set; otherwise, for a run inside a placeholder, the italic
|
|
2588
|
+
* state it inherits from the placeholder/list-style chain (paragraph `a:defRPr` →
|
|
2589
|
+
* slide `a:lstStyle` → layout → master placeholder `a:lstStyle` → master
|
|
2590
|
+
* `p:txStyles`). `null` when the run sets no `@i` and inherits none — the
|
|
2591
|
+
* resolved counterpart of {@link italic}, and the twin of {@link resolvedBold}:
|
|
2592
|
+
* `@b` and `@i` are siblings a master text style states together, so a deck that
|
|
2593
|
+
* can be authored with an inherited italic can be read back with one.
|
|
2594
|
+
*/
|
|
2595
|
+
get resolvedItalic() {
|
|
2596
|
+
return this.italic ?? this.inheritedItalic?.() ?? null;
|
|
2597
|
+
}
|
|
2287
2598
|
/** Escape hatch: the underlying `a:r` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
|
|
2288
2599
|
get element_() {
|
|
2289
2600
|
return this.element;
|
|
@@ -2352,8 +2663,9 @@ var Paragraph = class {
|
|
|
2352
2663
|
const inheritedSize = this.#inheritedResolver((ph, level, pPr, slideLst, ctx) => resolveInheritedRunSize(ph, level, pPr, slideLst, ctx));
|
|
2353
2664
|
const inheritedFace = this.#inheritedResolver((ph, level, pPr, slideLst, ctx) => resolveInheritedRunFontFace(ph, level, pPr, slideLst, ctx));
|
|
2354
2665
|
const inheritedBold = this.#inheritedResolver((ph, level, pPr, slideLst, ctx) => resolveInheritedRunBold(ph, level, pPr, slideLst, ctx));
|
|
2666
|
+
const inheritedItalic = this.#inheritedResolver((ph, level, pPr, slideLst, ctx) => resolveInheritedRunItalic(ph, level, pPr, slideLst, ctx));
|
|
2355
2667
|
const fontRef = this.inherit?.placeholder.fontRef ?? null;
|
|
2356
|
-
return getElements(this.element, "a:r").map((element) => new Run(element, this.part, this.themeContext, inheritedColor, inheritedSize, inheritedFace, inheritedBold, this.relationships, fontRef));
|
|
2668
|
+
return getElements(this.element, "a:r").map((element) => new Run(element, this.part, this.themeContext, inheritedColor, inheritedSize, inheritedFace, inheritedBold, inheritedItalic, this.relationships, fontRef));
|
|
2357
2669
|
}
|
|
2358
2670
|
/**
|
|
2359
2671
|
* A memoized thunk resolving the colour every run in this paragraph inherits
|
|
@@ -2366,7 +2678,7 @@ var Paragraph = class {
|
|
|
2366
2678
|
}
|
|
2367
2679
|
/**
|
|
2368
2680
|
* Build a memoized per-paragraph thunk for one inherited run property
|
|
2369
|
-
* (colour/size/face), or `undefined` for non-placeholder paragraphs. All runs in
|
|
2681
|
+
* (colour/size/face/bold/italic), or `undefined` for non-placeholder paragraphs. All runs in
|
|
2370
2682
|
* a paragraph share its level and `a:pPr`, so each `resolve` runs at most once
|
|
2371
2683
|
* and only when a run actually lacks its own value and asks.
|
|
2372
2684
|
*/
|
|
@@ -2513,7 +2825,7 @@ var Paragraph = class {
|
|
|
2513
2825
|
#emuAttrPt(name) {
|
|
2514
2826
|
const pPr = firstChild(this.element, "a:pPr");
|
|
2515
2827
|
const emu = pPr ? intValue(attr(pPr, name)) : null;
|
|
2516
|
-
return emu === null ? null : emu /
|
|
2828
|
+
return emu === null ? null : emu / EMU_PER_POINT;
|
|
2517
2829
|
}
|
|
2518
2830
|
/**
|
|
2519
2831
|
* The paragraph's text: run (`a:r`) and field (`a:fld`) text concatenated in
|
|
@@ -2529,6 +2841,16 @@ var Paragraph = class {
|
|
|
2529
2841
|
}
|
|
2530
2842
|
return out;
|
|
2531
2843
|
}
|
|
2844
|
+
/**
|
|
2845
|
+
* Replace **this paragraph's** content with a single run, preserving the character
|
|
2846
|
+
* formatting (`a:rPr`) of its first existing run and leaving its `a:pPr` (level,
|
|
2847
|
+
* alignment, bullet) alone. Sibling paragraphs are untouched — the difference from
|
|
2848
|
+
* {@link TextFrame.text}, which collapses the whole body to one paragraph.
|
|
2849
|
+
*/
|
|
2850
|
+
set text(value) {
|
|
2851
|
+
setParagraphText(this.element, value);
|
|
2852
|
+
this.part.markDirty();
|
|
2853
|
+
}
|
|
2532
2854
|
/** Escape hatch: the underlying `a:p` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
|
|
2533
2855
|
get element_() {
|
|
2534
2856
|
return this.element;
|
|
@@ -2570,7 +2892,7 @@ var TextFrame = class {
|
|
|
2570
2892
|
const insetsPt = {};
|
|
2571
2893
|
const inset = (qn, key) => {
|
|
2572
2894
|
const v = intValue(attr(bodyPr, qn));
|
|
2573
|
-
if (v !== null) insetsPt[key] = v /
|
|
2895
|
+
if (v !== null) insetsPt[key] = v / EMU_PER_POINT;
|
|
2574
2896
|
};
|
|
2575
2897
|
inset("lIns", "left");
|
|
2576
2898
|
inset("rIns", "right");
|
|
@@ -2672,8 +2994,6 @@ function setTextBodyText(txBody, value) {
|
|
|
2672
2994
|
const doc = txBody.ownerDocument;
|
|
2673
2995
|
if (!doc) throw new InternalError("oxml/node-has-no-document", "Cannot set text: text body has no owner document");
|
|
2674
2996
|
const paragraphs = getElements(txBody, "a:p");
|
|
2675
|
-
const firstRun = paragraphs[0] && firstChild(paragraphs[0], "a:r");
|
|
2676
|
-
const rPrTemplate = firstRun && firstChild(firstRun, "a:rPr");
|
|
2677
2997
|
for (let i = paragraphs.length - 1; i >= 1; i--) {
|
|
2678
2998
|
const extra = paragraphs[i];
|
|
2679
2999
|
if (extra) txBody.removeChild(extra);
|
|
@@ -2683,6 +3003,21 @@ function setTextBodyText(txBody, value) {
|
|
|
2683
3003
|
p = createElement(doc, "a:p");
|
|
2684
3004
|
txBody.appendChild(p);
|
|
2685
3005
|
}
|
|
3006
|
+
setParagraphText(p, value);
|
|
3007
|
+
}
|
|
3008
|
+
/**
|
|
3009
|
+
* Replace **one paragraph's** content with a single run, preserving the `a:rPr` of that
|
|
3010
|
+
* paragraph's first existing run and leaving its `a:pPr` (level, alignment, bullet) alone.
|
|
3011
|
+
* Sibling paragraphs are untouched, which is the whole difference from
|
|
3012
|
+
* {@link setTextBodyText} and the reason this exists: a SmartArt drawing cache packs several
|
|
3013
|
+
* nodes' text into one `dsp:txBody`, so collapsing the body there would delete the other
|
|
3014
|
+
* nodes' strings. Does **not** mark any part dirty — the caller owns the `Part`.
|
|
3015
|
+
*/
|
|
3016
|
+
function setParagraphText(p, value) {
|
|
3017
|
+
const doc = p.ownerDocument;
|
|
3018
|
+
if (!doc) throw new InternalError("oxml/node-has-no-document", "Cannot set text: paragraph has no owner document");
|
|
3019
|
+
const firstRun = firstChild(p, "a:r");
|
|
3020
|
+
const rPrTemplate = firstRun && firstChild(firstRun, "a:rPr");
|
|
2686
3021
|
for (const child of childElements(p)) if (child.localName === "r" || child.localName === "br" || child.localName === "fld") p.removeChild(child);
|
|
2687
3022
|
const run = createElement(doc, "a:r");
|
|
2688
3023
|
if (rPrTemplate) run.appendChild(rPrTemplate.cloneNode(true));
|
|
@@ -3060,7 +3395,7 @@ var Shape = class {
|
|
|
3060
3395
|
get lineWidthPt() {
|
|
3061
3396
|
const ln = this.#line();
|
|
3062
3397
|
const w = ln ? intValue(attr(ln, "w")) : null;
|
|
3063
|
-
return w === null ? null : w /
|
|
3398
|
+
return w === null ? null : w / EMU_PER_POINT;
|
|
3064
3399
|
}
|
|
3065
3400
|
/**
|
|
3066
3401
|
* The line/border dash style (`spPr/a:ln/a:prstDash/@val`), e.g. `'dash'`,
|
|
@@ -3243,7 +3578,7 @@ var Shape = class {
|
|
|
3243
3578
|
const out = { color: null };
|
|
3244
3579
|
this.#applyEffectColor(out, firstChildElement(glow));
|
|
3245
3580
|
const rad = intValue(attr(glow, "rad"));
|
|
3246
|
-
if (rad !== null) out.radiusPt = rad /
|
|
3581
|
+
if (rad !== null) out.radiusPt = rad / EMU_PER_POINT;
|
|
3247
3582
|
return out;
|
|
3248
3583
|
}
|
|
3249
3584
|
/**
|
|
@@ -3259,14 +3594,14 @@ var Shape = class {
|
|
|
3259
3594
|
const v = intValue(attr(refl, name));
|
|
3260
3595
|
if (v !== null) out[target] = v / div;
|
|
3261
3596
|
};
|
|
3262
|
-
put("blurPt", "blurRad",
|
|
3263
|
-
put("
|
|
3264
|
-
put("angleDeg", "dir",
|
|
3265
|
-
put("fadeAngleDeg", "fadeDir",
|
|
3266
|
-
put("startAlpha", "stA",
|
|
3267
|
-
put("startPos", "stPos",
|
|
3268
|
-
put("endAlpha", "endA",
|
|
3269
|
-
put("endPos", "endPos",
|
|
3597
|
+
put("blurPt", "blurRad", EMU_PER_POINT);
|
|
3598
|
+
put("offsetPt", "dist", EMU_PER_POINT);
|
|
3599
|
+
put("angleDeg", "dir", ANGLE_UNITS_PER_DEGREE);
|
|
3600
|
+
put("fadeAngleDeg", "fadeDir", ANGLE_UNITS_PER_DEGREE);
|
|
3601
|
+
put("startAlpha", "stA", PERCENT_SCALE);
|
|
3602
|
+
put("startPos", "stPos", PERCENT_SCALE);
|
|
3603
|
+
put("endAlpha", "endA", PERCENT_SCALE);
|
|
3604
|
+
put("endPos", "endPos", PERCENT_SCALE);
|
|
3270
3605
|
return out;
|
|
3271
3606
|
}
|
|
3272
3607
|
/**
|
|
@@ -3277,7 +3612,7 @@ var Shape = class {
|
|
|
3277
3612
|
const soft = this.#effect("a:softEdge");
|
|
3278
3613
|
if (!soft) return null;
|
|
3279
3614
|
const rad = intValue(attr(soft, "rad"));
|
|
3280
|
-
return { radiusPt: rad === null ? 0 : rad /
|
|
3615
|
+
return { radiusPt: rad === null ? 0 : rad / EMU_PER_POINT };
|
|
3281
3616
|
}
|
|
3282
3617
|
/**
|
|
3283
3618
|
* The shape's pattern (hatch) fill (`spPr/a:pattFill`), or `null` when the fill
|
|
@@ -3321,13 +3656,13 @@ var Shape = class {
|
|
|
3321
3656
|
/** Decode a shadow element (`a:outerShdw`/`a:innerShdw` share the fields), resolving its colour. */
|
|
3322
3657
|
#readShadow(shdw) {
|
|
3323
3658
|
const out = { color: null };
|
|
3324
|
-
this.#applyEffectColor(out,
|
|
3659
|
+
this.#applyEffectColor(out, firstChildElement(shdw));
|
|
3325
3660
|
const blur = intValue(attr(shdw, "blurRad"));
|
|
3326
3661
|
const dist = intValue(attr(shdw, "dist"));
|
|
3327
3662
|
const dir = intValue(attr(shdw, "dir"));
|
|
3328
|
-
if (blur !== null) out.blurPt = blur /
|
|
3329
|
-
if (dist !== null) out.offsetPt = dist /
|
|
3330
|
-
if (dir !== null) out.angleDeg = dir /
|
|
3663
|
+
if (blur !== null) out.blurPt = blur / EMU_PER_POINT;
|
|
3664
|
+
if (dist !== null) out.offsetPt = dist / EMU_PER_POINT;
|
|
3665
|
+
if (dir !== null) out.angleDeg = dir / ANGLE_UNITS_PER_DEGREE;
|
|
3331
3666
|
return out;
|
|
3332
3667
|
}
|
|
3333
3668
|
/**
|
|
@@ -3633,7 +3968,7 @@ var Picture = class extends Shape {
|
|
|
3633
3968
|
if (!srcRect) return null;
|
|
3634
3969
|
const edge = (name) => {
|
|
3635
3970
|
const v = intValue(attr(srcRect, name));
|
|
3636
|
-
return v === null ? 0 : v /
|
|
3971
|
+
return v === null ? 0 : v / PERCENT_SCALE;
|
|
3637
3972
|
};
|
|
3638
3973
|
return {
|
|
3639
3974
|
left: edge("l"),
|
|
@@ -3678,14 +4013,14 @@ var Picture = class extends Shape {
|
|
|
3678
4013
|
const thresh = intValue(attr(child, "thresh"));
|
|
3679
4014
|
return {
|
|
3680
4015
|
kind: "biLevel",
|
|
3681
|
-
threshold: thresh === null ? null : thresh /
|
|
4016
|
+
threshold: thresh === null ? null : thresh / PERCENT_SCALE
|
|
3682
4017
|
};
|
|
3683
4018
|
}
|
|
3684
4019
|
case "alphaModFix": {
|
|
3685
4020
|
const amt = intValue(attr(child, "amt"));
|
|
3686
4021
|
return {
|
|
3687
4022
|
kind: "alphaModFix",
|
|
3688
|
-
amount: amt === null ? 1 : amt /
|
|
4023
|
+
amount: amt === null ? 1 : amt / PERCENT_SCALE
|
|
3689
4024
|
};
|
|
3690
4025
|
}
|
|
3691
4026
|
}
|
|
@@ -3821,6 +4156,75 @@ var Connector = class extends Shape {
|
|
|
3821
4156
|
}
|
|
3822
4157
|
};
|
|
3823
4158
|
//#endregion
|
|
4159
|
+
//#region src/read/oxml/point-cache.ts
|
|
4160
|
+
/**
|
|
4161
|
+
* The one place a chart point cache is turned into an idx-ordered array.
|
|
4162
|
+
*
|
|
4163
|
+
* Both chart families cache their category/value data the same way: a run of indexed point
|
|
4164
|
+
* elements plus a declared count, which the reader widens back into a dense array so
|
|
4165
|
+
* `series.values[3]` means the point at `idx="3"` and a gap reads as `null`. Classic `c:`
|
|
4166
|
+
* charts and 2016 `cx:` charts spell it differently — `c:ptCount/@val` and a `c:v` child
|
|
4167
|
+
* against `cx:lvl/@ptCount` and the point's own text — and nothing else about the two decodes
|
|
4168
|
+
* differs, so the shape parameterizes over exactly those two differences.
|
|
4169
|
+
*
|
|
4170
|
+
* **Why neither number out of the file is trusted.** `@ptCount` is `xsd:unsignedInt`, so
|
|
4171
|
+
* `4294967295` is schema-valid, and `new Array(n).fill(null)` at that size is not a slow path
|
|
4172
|
+
* but a process kill: V8 answers `FATAL ERROR: invalid table size` and the host dies with no
|
|
4173
|
+
* exception to catch. That was reachable through the public read API — `Presentation.load()`
|
|
4174
|
+
* on a deck with an edited `c:ptCount` returned normally and the first `chart.series` access
|
|
4175
|
+
* killed the process. A single `<c:pt idx="900000000"/>` does the same thing on its own.
|
|
4176
|
+
* Reading a deck is the one part of this library whose input comes from somewhere other than
|
|
4177
|
+
* the calling program, so both numbers are bounded here.
|
|
4178
|
+
*
|
|
4179
|
+
* The array is sized by the points that are really there, not by the declared count. The cost
|
|
4180
|
+
* of that is a *trailing* gap: a cache declaring four points but carrying three (the fourth
|
|
4181
|
+
* cell blank) reads three long rather than four. No value is lost — the dropped slots are the
|
|
4182
|
+
* ones that would have been `null` — and the disagreement is warned about either way.
|
|
4183
|
+
*/
|
|
4184
|
+
/**
|
|
4185
|
+
* The highest point index this reader will honour.
|
|
4186
|
+
*
|
|
4187
|
+
* A cache references a range in the embedded workbook, and a worksheet has 1,048,576 rows, so
|
|
4188
|
+
* a point index at or above that cannot describe data any producer could have charted. Using
|
|
4189
|
+
* the sheet bound rather than a round number keeps the ceiling something a reader can check:
|
|
4190
|
+
* below it every real cache fits, above it the file is wrong by construction. It also caps the
|
|
4191
|
+
* worst-case allocation at about 8 MB of `null` — survivable, and reported — instead of an
|
|
4192
|
+
* unbounded one that takes the process with it.
|
|
4193
|
+
*/
|
|
4194
|
+
const MAX_POINT_INDEX = 1048576;
|
|
4195
|
+
/**
|
|
4196
|
+
* Read indexed cache points into a dense, idx-ordered array.
|
|
4197
|
+
*
|
|
4198
|
+
* The result is as long as the highest `@idx` actually present, and holds `null` at every
|
|
4199
|
+
* index no point claimed. A declared count that disagrees is warned about and not obeyed; a
|
|
4200
|
+
* point indexed past {@link MAX_POINT_INDEX} is warned about and dropped.
|
|
4201
|
+
* @param pts - the point elements, in document order
|
|
4202
|
+
* @param declaredCount - the cache's own count attribute, or `null` when absent
|
|
4203
|
+
* @param valueOf - reads one point's value; the two chart families differ only here
|
|
4204
|
+
* @param label - what to call the count in a diagnostic, e.g. `c:ptCount`
|
|
4205
|
+
*/
|
|
4206
|
+
function readIndexedPoints(pts, declaredCount, valueOf, label) {
|
|
4207
|
+
let count = 0;
|
|
4208
|
+
let dropped = 0;
|
|
4209
|
+
for (const pt of pts) {
|
|
4210
|
+
const idx = intValue(attr(pt, "idx")) ?? 0;
|
|
4211
|
+
if (idx < 0 || idx >= MAX_POINT_INDEX) {
|
|
4212
|
+
dropped++;
|
|
4213
|
+
continue;
|
|
4214
|
+
}
|
|
4215
|
+
if (idx + 1 > count) count = idx + 1;
|
|
4216
|
+
}
|
|
4217
|
+
if (dropped > 0) warn("chart/point-index-out-of-range", `${label}: ${dropped} cache point(s) are indexed outside 0..1048575, which no worksheet-backed chart can reference; they were dropped`);
|
|
4218
|
+
if (declaredCount !== null && declaredCount !== count) warn("chart/point-count-mismatch", `${label} declares ${declaredCount} point(s) but the cache carries ${pts.length}; reading ${count} rather than allocating the declared size`);
|
|
4219
|
+
const points = new Array(count).fill(null);
|
|
4220
|
+
for (const pt of pts) {
|
|
4221
|
+
const idx = intValue(attr(pt, "idx")) ?? 0;
|
|
4222
|
+
if (idx < 0 || idx >= count) continue;
|
|
4223
|
+
points[idx] = valueOf(pt);
|
|
4224
|
+
}
|
|
4225
|
+
return points;
|
|
4226
|
+
}
|
|
4227
|
+
//#endregion
|
|
3824
4228
|
//#region src/read/api/chart.ts
|
|
3825
4229
|
/** A chart graphic-frame's chart, backed by its chart part. */
|
|
3826
4230
|
var Chart = class {
|
|
@@ -4094,7 +4498,7 @@ var ChartSeries = class {
|
|
|
4094
4498
|
const dash = firstChild(ln, "a:prstDash");
|
|
4095
4499
|
const solid = readSolid(ln);
|
|
4096
4500
|
return {
|
|
4097
|
-
widthPt: w === null ? null : w /
|
|
4501
|
+
widthPt: w === null ? null : w / EMU_PER_POINT,
|
|
4098
4502
|
dash: dash ? attr(dash, "val") ?? null : null,
|
|
4099
4503
|
color: solid.color,
|
|
4100
4504
|
schemeColor: solid.schemeColor,
|
|
@@ -4188,22 +4592,11 @@ function findCache(container) {
|
|
|
4188
4592
|
}
|
|
4189
4593
|
return firstChild(container, "c:numLit") ?? firstChild(container, "c:strLit");
|
|
4190
4594
|
}
|
|
4191
|
-
/** Read a cache's points (`c:pt[@idx]/c:v`) into an idx-ordered array
|
|
4595
|
+
/** Read a cache's points (`c:pt[@idx]/c:v`) into an idx-ordered array; `c:ptCount` is the declared count. */
|
|
4192
4596
|
function readPoints(cache) {
|
|
4193
4597
|
if (!cache) return [];
|
|
4194
4598
|
const ptCount = firstChild(cache, "c:ptCount");
|
|
4195
|
-
|
|
4196
|
-
const pts = getElements(cache, "c:pt");
|
|
4197
|
-
for (const pt of pts) {
|
|
4198
|
-
const idx = intValue(attr(pt, "idx")) ?? 0;
|
|
4199
|
-
if (idx + 1 > count) count = idx + 1;
|
|
4200
|
-
}
|
|
4201
|
-
const points = new Array(count).fill(null);
|
|
4202
|
-
for (const pt of pts) {
|
|
4203
|
-
const idx = intValue(attr(pt, "idx")) ?? 0;
|
|
4204
|
-
points[idx] = firstChild(pt, "c:v")?.textContent ?? null;
|
|
4205
|
-
}
|
|
4206
|
-
return points;
|
|
4599
|
+
return readIndexedPoints(getElements(cache, "c:pt"), ptCount ? intValue(attr(ptCount, "val")) : null, (pt) => firstChild(pt, "c:v")?.textContent ?? null, "c:ptCount");
|
|
4207
4600
|
}
|
|
4208
4601
|
//#endregion
|
|
4209
4602
|
//#region src/read/api/chartex.ts
|
|
@@ -4437,22 +4830,10 @@ var ChartExAxis = class {
|
|
|
4437
4830
|
this.chart.part.markDirty();
|
|
4438
4831
|
}
|
|
4439
4832
|
};
|
|
4440
|
-
/** Read a `cx:lvl`'s points (`cx:pt[@idx]` text) into an idx-ordered array
|
|
4833
|
+
/** Read a `cx:lvl`'s points (`cx:pt[@idx]` text) into an idx-ordered array; `@ptCount` is the declared count. */
|
|
4441
4834
|
function readLevelPoints(lvl) {
|
|
4442
4835
|
if (!lvl) return [];
|
|
4443
|
-
|
|
4444
|
-
const pts = getElements(lvl, "cx:pt");
|
|
4445
|
-
let count = ptCount ?? 0;
|
|
4446
|
-
for (const pt of pts) {
|
|
4447
|
-
const idx = intValue(attr(pt, "idx")) ?? 0;
|
|
4448
|
-
if (idx + 1 > count) count = idx + 1;
|
|
4449
|
-
}
|
|
4450
|
-
const points = new Array(count).fill(null);
|
|
4451
|
-
for (const pt of pts) {
|
|
4452
|
-
const idx = intValue(attr(pt, "idx")) ?? 0;
|
|
4453
|
-
points[idx] = pt.textContent ?? null;
|
|
4454
|
-
}
|
|
4455
|
-
return points;
|
|
4836
|
+
return readIndexedPoints(getElements(lvl, "cx:pt"), intValue(attr(lvl, "ptCount")), (pt) => pt.textContent ?? null, "cx:lvl/@ptCount");
|
|
4456
4837
|
}
|
|
4457
4838
|
/** Parse an attribute as a boolean (`1`/`true` → true, `0`/`false` → false), or `null` when absent. */
|
|
4458
4839
|
function boolAttr(element, name) {
|
|
@@ -4468,6 +4849,55 @@ function floatValue(value) {
|
|
|
4468
4849
|
}
|
|
4469
4850
|
//#endregion
|
|
4470
4851
|
//#region src/read/api/diagram.ts
|
|
4852
|
+
/**
|
|
4853
|
+
* Read proxies for a SmartArt diagram (`dgm:dataModel`) hosted in a `p:graphicFrame`.
|
|
4854
|
+
*
|
|
4855
|
+
* SmartArt is a four-part construct, and the frame itself holds none of it: the
|
|
4856
|
+
* `a:graphicData` carries only a `dgm:relIds` with four relationship ids pointing at the
|
|
4857
|
+
* data, layout, quick-style and colours parts under `/ppt/diagrams/`. The **data** part is
|
|
4858
|
+
* the one with content in it — a flat `dgm:ptLst` of points plus a `dgm:cxnLst` of
|
|
4859
|
+
* connections that give the points their tree — and it is what this surface decodes. The
|
|
4860
|
+
* other three are generated presets (`urn:microsoft.com/office/officeart/…`) describing how
|
|
4861
|
+
* PowerPoint *draws* the graph rather than what it says; they surface as parts, not getters.
|
|
4862
|
+
*
|
|
4863
|
+
* The text is ordinary DrawingML: `dgm:pt/dgm:t` is an `a:CT_TextBody`, the same type a
|
|
4864
|
+
* shape's `p:txBody` is, so a point's text reads back through the same
|
|
4865
|
+
* {@link TextFrame}/`Paragraph`/`Run` proxies as any other text on the slide, run formatting
|
|
4866
|
+
* included.
|
|
4867
|
+
*
|
|
4868
|
+
* **Not every point is content.** A saved data model interleaves the user's nodes with
|
|
4869
|
+
* points the layout engine generated (`pres`), the diagram root (`doc`), and the transition
|
|
4870
|
+
* points sitting on each edge (`parTrans`/`sibTrans`, which carry text only where a layout
|
|
4871
|
+
* labels its arrows). {@link Diagram.text} applies exactly that filter; {@link Diagram.points}
|
|
4872
|
+
* applies none, so a consumer that needs the raw graph gets it.
|
|
4873
|
+
*
|
|
4874
|
+
* **The structure is in the connections, and {@link Diagram.nodes} is the view of it.** A
|
|
4875
|
+
* `parOf` edge names the parent in `@srcId`, the child in `@destId` and the child's sibling
|
|
4876
|
+
* position in `@srcOrd`; `points` order is document order and says nothing about depth. Three
|
|
4877
|
+
* decisions that tree makes, each of which could defensibly have gone the other way:
|
|
4878
|
+
*
|
|
4879
|
+
* - **`asst` points are in it.** An assistant is user content, and an org chart merely draws
|
|
4880
|
+
* it off the main branch rather than under it. {@link DiagramPoint.type} carries the
|
|
4881
|
+
* distinction, so folding it silently in with `node` would hide something a consumer can
|
|
4882
|
+
* act on while omitting it would lose authored text.
|
|
4883
|
+
* - **Transition points are not.** A `parTrans`/`sibTrans` labels an *edge*, not a node, and
|
|
4884
|
+
* reaches its edge through {@link DiagramConnection.parentTransitionId} /
|
|
4885
|
+
* `siblingTransitionId`. Hanging one off `children` would make the tree disagree with what
|
|
4886
|
+
* PowerPoint's own text pane shows.
|
|
4887
|
+
* - **A cycle in `parOf` throws.** It is a corrupt model rather than a shape the format can
|
|
4888
|
+
* express, and the walk would not terminate; see `diagram/parent-edge-cycle`.
|
|
4889
|
+
*
|
|
4890
|
+
* **A point's text is stored twice.** The data model is what PowerPoint reads, but a deck
|
|
4891
|
+
* also carries a *drawing* part (`dsp:drawing`) holding a copy of every drawn string, and
|
|
4892
|
+
* every renderer without a SmartArt layout engine — LibreOffice, Google Slides, thumbnailers
|
|
4893
|
+
* — paints that copy and nothing else. {@link DiagramPoint.drawnShape} is the link between
|
|
4894
|
+
* the two, and {@link DiagramPoint.text}'s setter is what keeps them in step.
|
|
4895
|
+
*
|
|
4896
|
+
* Authoring a SmartArt graphic from nothing is out of scope: the layout part is a
|
|
4897
|
+
* constraint-solver program PowerPoint executes, and the presentation tree it generates is
|
|
4898
|
+
* not derivable from the user's content. Editing the text of one that already exists is
|
|
4899
|
+
* supported — see {@link DiagramPoint.text}.
|
|
4900
|
+
*/
|
|
4471
4901
|
const POINT_TYPES = [
|
|
4472
4902
|
"node",
|
|
4473
4903
|
"asst",
|
|
@@ -4484,17 +4914,100 @@ const CONNECTION_TYPES = [
|
|
|
4484
4914
|
];
|
|
4485
4915
|
/** The MS extension (`dgm:extLst/a:ext`) whose `@relId` names the fallback drawing part. */
|
|
4486
4916
|
const DRAWING_EXT_URI = "http://schemas.microsoft.com/office/drawing/2008/diagram";
|
|
4917
|
+
/**
|
|
4918
|
+
* The node → drawn-shape index of one diagram: the `presOf` edges of the data model and the
|
|
4919
|
+
* `dsp:sp` elements of the drawing part, both keyed for lookup.
|
|
4920
|
+
*
|
|
4921
|
+
* Built once per {@link Diagram}, and only when a point is actually asked what draws it — the
|
|
4922
|
+
* drawing part is a second XML DOM and a consumer reading node text should not pay to parse
|
|
4923
|
+
* it. The consequence of that memo: a consumer who *adds* or *removes* shapes in the drawing
|
|
4924
|
+
* part through the escape hatches must re-reach the diagram to see them here.
|
|
4925
|
+
*/
|
|
4926
|
+
var DrawingIndex = class {
|
|
4927
|
+
drawingPart;
|
|
4928
|
+
themeContext;
|
|
4929
|
+
/** `presOf` arms out of each source point, in `@srcOrd` order. */
|
|
4930
|
+
#arms = /* @__PURE__ */ new Map();
|
|
4931
|
+
/** Each `dsp:sp` by the `pres` modelId it draws. */
|
|
4932
|
+
#shapes = /* @__PURE__ */ new Map();
|
|
4933
|
+
constructor(root, drawingPart, themeContext) {
|
|
4934
|
+
this.drawingPart = drawingPart;
|
|
4935
|
+
this.themeContext = themeContext;
|
|
4936
|
+
const cxnLst = root && firstChild(root, "dgm:cxnLst");
|
|
4937
|
+
for (const cxn of cxnLst ? getElements(cxnLst, "dgm:cxn") : []) {
|
|
4938
|
+
if (attr(cxn, "type") !== "presOf") continue;
|
|
4939
|
+
const srcId = attr(cxn, "srcId");
|
|
4940
|
+
const destId = attr(cxn, "destId");
|
|
4941
|
+
if (!srcId || !destId) continue;
|
|
4942
|
+
const arm = {
|
|
4943
|
+
destId,
|
|
4944
|
+
destinationOrder: intValue(attr(cxn, "destOrd")) ?? 0,
|
|
4945
|
+
sourceOrder: intValue(attr(cxn, "srcOrd")) ?? 0
|
|
4946
|
+
};
|
|
4947
|
+
const list = this.#arms.get(srcId);
|
|
4948
|
+
if (list) list.push(arm);
|
|
4949
|
+
else this.#arms.set(srcId, [arm]);
|
|
4950
|
+
}
|
|
4951
|
+
for (const list of this.#arms.values()) list.sort((a, b) => a.sourceOrder - b.sourceOrder);
|
|
4952
|
+
const drawingRoot = drawingPart?.dom.documentElement ?? null;
|
|
4953
|
+
for (const sp of drawingRoot ? descendantsByTag(drawingRoot, OOXML_NS.dsp, "sp") : []) {
|
|
4954
|
+
const modelId = attr(sp, "modelId");
|
|
4955
|
+
if (modelId !== null && !this.#shapes.has(modelId)) this.#shapes.set(modelId, sp);
|
|
4956
|
+
}
|
|
4957
|
+
}
|
|
4958
|
+
/**
|
|
4959
|
+
* Resolve one authored point to the `pres` point that presents it and to the drawn
|
|
4960
|
+
* paragraph carrying its text.
|
|
4961
|
+
*
|
|
4962
|
+
* A point commonly has **several** `presOf` arms — an org-chart node's box and the
|
|
4963
|
+
* connector beneath it are two presentations of one node — so the arm is chosen by what it
|
|
4964
|
+
* reaches rather than by its `@srcOrd`: the first, in `@srcOrd` order, whose `pres` point
|
|
4965
|
+
* draws a `dsp:sp` that has a `dsp:txBody`. That selector produced a unique hit for all 90
|
|
4966
|
+
* authored points measured across five layout families, and it degrades to "no arm" rather
|
|
4967
|
+
* than to "the wrong arm" on a layout that was not.
|
|
4968
|
+
*/
|
|
4969
|
+
resolve(modelId) {
|
|
4970
|
+
const arms = (modelId === null ? void 0 : this.#arms.get(modelId)) ?? [];
|
|
4971
|
+
const first = arms[0];
|
|
4972
|
+
if (!first) return {
|
|
4973
|
+
presentationId: null,
|
|
4974
|
+
drawnShape: null
|
|
4975
|
+
};
|
|
4976
|
+
for (const arm of arms) {
|
|
4977
|
+
const sp = this.#shapes.get(arm.destId);
|
|
4978
|
+
const txBody = sp && firstChild(sp, "dsp:txBody");
|
|
4979
|
+
if (!sp || !txBody || !this.drawingPart) continue;
|
|
4980
|
+
const paragraph = getElements(txBody, "a:p")[arm.destinationOrder];
|
|
4981
|
+
return {
|
|
4982
|
+
presentationId: arm.destId,
|
|
4983
|
+
drawnShape: paragraph ? {
|
|
4984
|
+
part: this.drawingPart,
|
|
4985
|
+
modelId: arm.destId,
|
|
4986
|
+
paragraphIndex: arm.destinationOrder,
|
|
4987
|
+
textFrame: new TextFrame(txBody, this.drawingPart, this.themeContext),
|
|
4988
|
+
element_: sp
|
|
4989
|
+
} : null
|
|
4990
|
+
};
|
|
4991
|
+
}
|
|
4992
|
+
return {
|
|
4993
|
+
presentationId: first.destId,
|
|
4994
|
+
drawnShape: null
|
|
4995
|
+
};
|
|
4996
|
+
}
|
|
4997
|
+
};
|
|
4487
4998
|
/** One point (`dgm:pt`) of a diagram's data model. */
|
|
4488
4999
|
var DiagramPoint = class {
|
|
4489
5000
|
pt;
|
|
4490
5001
|
part;
|
|
4491
5002
|
themeContext;
|
|
4492
5003
|
relationships;
|
|
4493
|
-
|
|
5004
|
+
drawing;
|
|
5005
|
+
constructor(pt, part, themeContext, relationships, drawing) {
|
|
4494
5006
|
this.pt = pt;
|
|
4495
5007
|
this.part = part;
|
|
4496
5008
|
this.themeContext = themeContext;
|
|
4497
5009
|
this.relationships = relationships;
|
|
5010
|
+
this.drawing = drawing;
|
|
4498
5011
|
}
|
|
4499
5012
|
/** This point's id (`@modelId`), which connections reference. */
|
|
4500
5013
|
get modelId() {
|
|
@@ -4530,15 +5043,87 @@ var DiagramPoint = class {
|
|
|
4530
5043
|
* This point's text body (`dgm:t`) as a {@link TextFrame}, or `null` when the point
|
|
4531
5044
|
* carries none. It is an `a:CT_TextBody` like any other, so `paragraphs`, `runs` and the
|
|
4532
5045
|
* `resolved*` getters all apply.
|
|
5046
|
+
*
|
|
5047
|
+
* **Writing through this edits the data model only**, and leaves the drawing cache
|
|
5048
|
+
* holding the old string — which is what PowerPoint-less renderers draw. It is the escape
|
|
5049
|
+
* hatch for run-level formatting, so it does exactly what it is told and nothing more;
|
|
5050
|
+
* {@link text}'s setter is the path that mirrors.
|
|
4533
5051
|
*/
|
|
4534
5052
|
get textFrame() {
|
|
4535
5053
|
const t = firstChild(this.pt, "dgm:t");
|
|
4536
5054
|
return t ? new TextFrame(t, this.part, this.themeContext, void 0, this.relationships) : null;
|
|
4537
5055
|
}
|
|
5056
|
+
/**
|
|
5057
|
+
* The generated `pres` point that presents this one (`dgm:cxn[@type="presOf"]/@destId`),
|
|
5058
|
+
* or `null` when nothing presents it — the normal state of an unlabelled transition point.
|
|
5059
|
+
*
|
|
5060
|
+
* Where a point has several `presOf` arms the one named here is the arm that draws text;
|
|
5061
|
+
* see {@link drawnShape}, which resolves both.
|
|
5062
|
+
*/
|
|
5063
|
+
get presentationId() {
|
|
5064
|
+
return this.drawing?.().resolve(this.modelId).presentationId ?? null;
|
|
5065
|
+
}
|
|
5066
|
+
/**
|
|
5067
|
+
* The paragraph of the fallback drawing part (`dsp:drawing`) that carries this point's
|
|
5068
|
+
* text, or `null` when nothing draws it.
|
|
5069
|
+
*
|
|
5070
|
+
* The mapping runs through the `pres` point rather than directly: a `dsp:sp/@modelId` is
|
|
5071
|
+
* always a `pres` point's id, so a lookup keyed on the authored point's own id finds
|
|
5072
|
+
* nothing at all. It is many-to-one in both directions — one shape draws several points
|
|
5073
|
+
* (`@destOrd` says which paragraph is whose, and it can contradict document order), and
|
|
5074
|
+
* one point has several presentations, of which at most one holds text.
|
|
5075
|
+
*
|
|
5076
|
+
* `null` is a defined outcome, not a failure, and covers four real cases: the package
|
|
5077
|
+
* carries no drawing part; the point has no `presOf` edge (every unlabelled
|
|
5078
|
+
* `parTrans`/`sibTrans`); the `pres` point draws no `dsp:sp`; and the shape it draws has
|
|
5079
|
+
* no `dsp:txBody` (a connector, or a picture node's filled rectangle).
|
|
5080
|
+
*/
|
|
5081
|
+
get drawnShape() {
|
|
5082
|
+
return this.drawing?.().resolve(this.modelId).drawnShape ?? null;
|
|
5083
|
+
}
|
|
4538
5084
|
/** This point's text, paragraphs joined by `\n`; `''` when it carries none. */
|
|
4539
5085
|
get text() {
|
|
4540
5086
|
return this.textFrame?.text ?? "";
|
|
4541
5087
|
}
|
|
5088
|
+
/**
|
|
5089
|
+
* Replace this point's text, in the data model **and** in the drawing cache.
|
|
5090
|
+
*
|
|
5091
|
+
* A diagram stores every string twice. `dgm:t` is what PowerPoint reads, and it recomputes
|
|
5092
|
+
* the drawing from the data model on open; the `dsp:drawing` part is what every other
|
|
5093
|
+
* renderer paints, and none of them recompute anything. Writing only the first is an edit
|
|
5094
|
+
* that is invisible in LibreOffice, Google Slides, thumbnailers and web previews until
|
|
5095
|
+
* someone opens the deck in PowerPoint and saves it.
|
|
5096
|
+
*
|
|
5097
|
+
* The data-model write always happens. The mirror is best-effort: when the point resolves
|
|
5098
|
+
* to no drawn paragraph (see {@link drawnShape} for the four ways that occurs) the cache
|
|
5099
|
+
* keeps the old string and a `diagram/drawing-cache-not-updated` diagnostic says so.
|
|
5100
|
+
* Throwing instead would make the common case unusable in order to report the rare one,
|
|
5101
|
+
* and returning a status would be a shape no other text setter here has.
|
|
5102
|
+
*
|
|
5103
|
+
* Two things it deliberately does not do. It does **not** recompute geometry: the drawn
|
|
5104
|
+
* shape keeps its cached position and size, so a much longer string overflows its box in
|
|
5105
|
+
* those same renderers until PowerPoint re-lays the diagram out. And it does not *create*
|
|
5106
|
+
* a place to draw text — a transition point whose layout has no label slot has no
|
|
5107
|
+
* `dsp:sp`, and PowerPoint strips text put on one, so the honest outcome is the
|
|
5108
|
+
* diagnostic. Like every other `text` setter here it collapses the point to one run,
|
|
5109
|
+
* keeping the first run's `a:rPr`; use {@link textFrame} for run-level work.
|
|
5110
|
+
*/
|
|
5111
|
+
set text(value) {
|
|
5112
|
+
const frame = this.textFrame;
|
|
5113
|
+
if (!frame) {
|
|
5114
|
+
warn("diagram/point-has-no-text-body", `SmartArt point ${this.#label()} (type ${this.type}) has no dgm:t, so it is not a point text can be written to; nothing was changed`);
|
|
5115
|
+
return;
|
|
5116
|
+
}
|
|
5117
|
+
frame.text = value;
|
|
5118
|
+
const drawn = this.drawnShape;
|
|
5119
|
+
const paragraph = drawn?.textFrame.paragraphs[drawn.paragraphIndex];
|
|
5120
|
+
if (!drawn || !paragraph) {
|
|
5121
|
+
warn("diagram/drawing-cache-not-updated", `SmartArt point ${this.#label()} resolves to no drawn paragraph, so ${this.part.partName} now holds the new text but the drawing cache still holds the old one; PowerPoint redraws it on open, other renderers do not`);
|
|
5122
|
+
return;
|
|
5123
|
+
}
|
|
5124
|
+
setParagraphText(paragraph.element_, value);
|
|
5125
|
+
drawn.part.markDirty();
|
|
5126
|
+
}
|
|
4542
5127
|
/** Escape hatch: the underlying `dgm:pt` element. After mutating it call {@link Diagram.markDirty}. */
|
|
4543
5128
|
get element_() {
|
|
4544
5129
|
return this.pt;
|
|
@@ -4546,7 +5131,29 @@ var DiagramPoint = class {
|
|
|
4546
5131
|
#prSet() {
|
|
4547
5132
|
return firstChild(this.pt, "dgm:prSet");
|
|
4548
5133
|
}
|
|
5134
|
+
/** How a diagnostic names this point: its `@modelId`, which is all a corrupt point may have. */
|
|
5135
|
+
#label() {
|
|
5136
|
+
return this.modelId ?? "(no modelId)";
|
|
5137
|
+
}
|
|
5138
|
+
};
|
|
5139
|
+
/**
|
|
5140
|
+
* One user-authored point in its place in the diagram's tree — a `node` or an `asst`, never a
|
|
5141
|
+
* generated `pres` point or a transition label. See {@link Diagram.nodes}.
|
|
5142
|
+
*/
|
|
5143
|
+
var DiagramNode = class {
|
|
5144
|
+
point;
|
|
5145
|
+
parent;
|
|
5146
|
+
level;
|
|
5147
|
+
/** Child nodes, ordered by their `parOf` edge's `@srcOrd`. Empty for a leaf. */
|
|
5148
|
+
children = [];
|
|
5149
|
+
constructor(point, parent, level) {
|
|
5150
|
+
this.point = point;
|
|
5151
|
+
this.parent = parent;
|
|
5152
|
+
this.level = level;
|
|
5153
|
+
}
|
|
4549
5154
|
};
|
|
5155
|
+
/** Sort key for a root with no `parOf` edge at all, so it lands after the ordered ones. */
|
|
5156
|
+
const MAX_ORDER = Number.MAX_SAFE_INTEGER;
|
|
4550
5157
|
/** A SmartArt graphic frame's diagram, backed by its `dgm:dataModel` part. */
|
|
4551
5158
|
var Diagram = class {
|
|
4552
5159
|
part;
|
|
@@ -4554,6 +5161,9 @@ var Diagram = class {
|
|
|
4554
5161
|
opc;
|
|
4555
5162
|
frameRelationships;
|
|
4556
5163
|
themeContext;
|
|
5164
|
+
#relationships;
|
|
5165
|
+
#docPrSetCache;
|
|
5166
|
+
#drawing;
|
|
4557
5167
|
constructor(part, relIds, opc, frameRelationships, themeContext) {
|
|
4558
5168
|
this.part = part;
|
|
4559
5169
|
this.relIds = relIds;
|
|
@@ -4568,14 +5178,88 @@ var Diagram = class {
|
|
|
4568
5178
|
/**
|
|
4569
5179
|
* Every point (`dgm:ptLst/dgm:pt`) in document order, unfiltered — generated `pres`
|
|
4570
5180
|
* points and the `doc` root included. Filter on {@link DiagramPoint.type} for the user's
|
|
4571
|
-
* nodes; {@link text} is the shortcut for the common case.
|
|
5181
|
+
* nodes; {@link text} is the shortcut for the common case, {@link nodes} the structured one.
|
|
5182
|
+
*
|
|
5183
|
+
* Built per access like every other read proxy (`docs/reference/pptx-read.md`, "Object
|
|
5184
|
+
* model"), so `points[0] !== points[0]` while both wrap the same `dgm:pt`. Key a `Map`
|
|
5185
|
+
* on {@link DiagramPoint.modelId}, not on the point.
|
|
4572
5186
|
*/
|
|
4573
5187
|
get points() {
|
|
4574
5188
|
const root = this.#root();
|
|
4575
5189
|
const ptLst = root && firstChild(root, "dgm:ptLst");
|
|
4576
5190
|
if (!ptLst) return [];
|
|
4577
|
-
const relationships = this.opc.relationshipsFor(this.part.partName);
|
|
4578
|
-
|
|
5191
|
+
const relationships = this.#relationships ??= this.opc.relationshipsFor(this.part.partName);
|
|
5192
|
+
const drawing = () => this.#drawingIndex();
|
|
5193
|
+
return getElements(ptLst, "dgm:pt").map((pt) => new DiagramPoint(pt, this.part, this.themeContext, relationships, drawing));
|
|
5194
|
+
}
|
|
5195
|
+
/**
|
|
5196
|
+
* The authored tree — every `node` and `asst` point in its place, roots in `@srcOrd`
|
|
5197
|
+
* order — as a view over {@link points} and {@link connections} rather than a replacement
|
|
5198
|
+
* for either.
|
|
5199
|
+
*
|
|
5200
|
+
* A root is a content point whose `parOf` parent is not itself content, which in a
|
|
5201
|
+
* PowerPoint-authored model means the `doc` point. Transition points are not members; see
|
|
5202
|
+
* this module's header for that decision and the two beside it.
|
|
5203
|
+
*
|
|
5204
|
+
* @throws PackageReadError `diagram/parent-edge-cycle` when the `parOf` edges make a
|
|
5205
|
+
* point its own ancestor, which is a corrupt model rather than a diagram shape.
|
|
5206
|
+
*/
|
|
5207
|
+
get nodes() {
|
|
5208
|
+
const content = /* @__PURE__ */ new Map();
|
|
5209
|
+
for (const point of this.points) {
|
|
5210
|
+
const modelId = point.modelId;
|
|
5211
|
+
if (modelId !== null && (point.type === "node" || point.type === "asst")) content.set(modelId, point);
|
|
5212
|
+
}
|
|
5213
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
5214
|
+
const edgeTo = /* @__PURE__ */ new Map();
|
|
5215
|
+
for (const connection of this.connections) {
|
|
5216
|
+
const { sourceId, destinationId } = connection;
|
|
5217
|
+
if (connection.type !== "parOf" || sourceId === null || destinationId === null) continue;
|
|
5218
|
+
if (!content.has(destinationId)) continue;
|
|
5219
|
+
const edge = {
|
|
5220
|
+
parentId: sourceId,
|
|
5221
|
+
childId: destinationId,
|
|
5222
|
+
order: connection.sourceOrder ?? 0
|
|
5223
|
+
};
|
|
5224
|
+
const list = childrenOf.get(sourceId);
|
|
5225
|
+
if (list) list.push(edge);
|
|
5226
|
+
else childrenOf.set(sourceId, [edge]);
|
|
5227
|
+
edgeTo.set(destinationId, edge);
|
|
5228
|
+
}
|
|
5229
|
+
for (const list of childrenOf.values()) list.sort((a, b) => a.order - b.order);
|
|
5230
|
+
const roots = [...content].filter(([modelId]) => {
|
|
5231
|
+
const parentId = edgeTo.get(modelId)?.parentId;
|
|
5232
|
+
return parentId === void 0 || !content.has(parentId);
|
|
5233
|
+
});
|
|
5234
|
+
roots.sort(([a], [b]) => (edgeTo.get(a)?.order ?? MAX_ORDER) - (edgeTo.get(b)?.order ?? MAX_ORDER));
|
|
5235
|
+
const placed = /* @__PURE__ */ new Set();
|
|
5236
|
+
const build = (point, parent, level, path) => {
|
|
5237
|
+
const modelId = point.modelId;
|
|
5238
|
+
if (modelId !== null && path.has(modelId)) throw this.#cycleError(modelId);
|
|
5239
|
+
const node = new DiagramNode(point, parent, level);
|
|
5240
|
+
if (modelId === null) return node;
|
|
5241
|
+
placed.add(modelId);
|
|
5242
|
+
path.add(modelId);
|
|
5243
|
+
for (const edge of childrenOf.get(modelId) ?? []) {
|
|
5244
|
+
const child = content.get(edge.childId);
|
|
5245
|
+
if (child) node.children.push(build(child, node, level + 1, path));
|
|
5246
|
+
}
|
|
5247
|
+
path.delete(modelId);
|
|
5248
|
+
return node;
|
|
5249
|
+
};
|
|
5250
|
+
const tree = roots.map(([, point]) => build(point, null, 0, /* @__PURE__ */ new Set()));
|
|
5251
|
+
if (placed.size !== content.size) {
|
|
5252
|
+
const orphan = [...content.keys()].find((modelId) => !placed.has(modelId));
|
|
5253
|
+
throw this.#cycleError(orphan ?? "(unidentified)");
|
|
5254
|
+
}
|
|
5255
|
+
return tree;
|
|
5256
|
+
}
|
|
5257
|
+
/**
|
|
5258
|
+
* The point with this `@modelId`, or `null` — the lookup every connection getter implies,
|
|
5259
|
+
* since a `DiagramConnection` names its ends by id and nothing else resolves them.
|
|
5260
|
+
*/
|
|
5261
|
+
point(modelId) {
|
|
5262
|
+
return this.points.find((candidate) => candidate.modelId === modelId) ?? null;
|
|
4579
5263
|
}
|
|
4580
5264
|
/** Every edge (`dgm:cxnLst/dgm:cxn`) in document order. */
|
|
4581
5265
|
get connections() {
|
|
@@ -4666,14 +5350,32 @@ var Diagram = class {
|
|
|
4666
5350
|
#root() {
|
|
4667
5351
|
return this.part.dom.documentElement;
|
|
4668
5352
|
}
|
|
4669
|
-
#
|
|
5353
|
+
#cycleError(modelId) {
|
|
5354
|
+
return new PackageReadError("diagram/parent-edge-cycle", `Diagram ${this.part.partName} has a parOf cycle reaching point ${modelId}, so its points do not form a tree`);
|
|
5355
|
+
}
|
|
5356
|
+
/**
|
|
5357
|
+
* The `doc` point's `dgm:prSet`, which carries all three preset ids — resolved once
|
|
5358
|
+
* rather than once per getter, since each lookup is a scan of the whole `ptLst`.
|
|
5359
|
+
* `undefined` means "not looked up yet"; `null` means "looked up, not there".
|
|
5360
|
+
*/
|
|
5361
|
+
#docPrSet() {
|
|
5362
|
+
if (this.#docPrSetCache !== void 0) return this.#docPrSetCache;
|
|
4670
5363
|
const root = this.#root();
|
|
4671
5364
|
const ptLst = root && firstChild(root, "dgm:ptLst");
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
5365
|
+
const doc = ptLst && getElements(ptLst, "dgm:pt").find((pt) => attr(pt, "type") === "doc");
|
|
5366
|
+
return this.#docPrSetCache = doc && firstChild(doc, "dgm:prSet") || null;
|
|
5367
|
+
}
|
|
5368
|
+
#docPrSetAttr(name) {
|
|
5369
|
+
const prSet = this.#docPrSet();
|
|
4675
5370
|
return prSet ? attr(prSet, name) : null;
|
|
4676
5371
|
}
|
|
5372
|
+
/**
|
|
5373
|
+
* The drawing index, built on first use and kept — see {@link DrawingIndex} for what that
|
|
5374
|
+
* memo costs a consumer who mutates the drawing part's shape tree by hand.
|
|
5375
|
+
*/
|
|
5376
|
+
#drawingIndex() {
|
|
5377
|
+
return this.#drawing ??= new DrawingIndex(this.#root(), this.drawingPart, this.themeContext);
|
|
5378
|
+
}
|
|
4677
5379
|
#relPart(qname) {
|
|
4678
5380
|
return this.#partForRelId(attr(this.relIds, qname));
|
|
4679
5381
|
}
|
|
@@ -5588,7 +6290,7 @@ var TableCell = class {
|
|
|
5588
6290
|
removeChildrenByQName(tcPr, [qname]);
|
|
5589
6291
|
const doc = ownerDocumentOf(tcPr);
|
|
5590
6292
|
const ln = createElement(doc, qname);
|
|
5591
|
-
if (border.widthPt !== void 0 && border.widthPt !== null) setAttr(ln, "w", String(checkFiniteEmu(border.widthPt *
|
|
6293
|
+
if (border.widthPt !== void 0 && border.widthPt !== null) setAttr(ln, "w", String(checkFiniteEmu(border.widthPt * EMU_PER_POINT, "widthPt", "table/invalid-cell-border")));
|
|
5592
6294
|
if (border.noFill) ln.appendChild(createElement(doc, "a:noFill"));
|
|
5593
6295
|
else if (border.schemeColor || border.color) {
|
|
5594
6296
|
const fill = createElement(doc, "a:solidFill");
|
|
@@ -5778,7 +6480,8 @@ var TableCell = class {
|
|
|
5778
6480
|
/**
|
|
5779
6481
|
* The cell's edge borders (`a:tcPr/a:lnL|lnR|lnT|lnB|lnTlToBr|lnBlToTr`), or
|
|
5780
6482
|
* `null` when the cell defines none. Each present edge decodes to a
|
|
5781
|
-
* {@link CellBorder} (width / dash / resolved + raw
|
|
6483
|
+
* {@link CellBorder} (width / dash / resolved colour + its raw token and transform
|
|
6484
|
+
* list / suppressed flag);
|
|
5782
6485
|
* absent edges are `null`. Cell borders are the biggest visible table gap — a
|
|
5783
6486
|
* replica built only from geometry and fill draws every cell edge-to-edge with
|
|
5784
6487
|
* no rule, so this surfaces the per-side stroke the writer's `border` option emits.
|
|
@@ -5794,8 +6497,9 @@ var TableCell = class {
|
|
|
5794
6497
|
const scheme = this.#fillSchemeColorOf(ln);
|
|
5795
6498
|
const resolved = this.themeColors ? resolveSolidFillColor(ln, this.themeColors) : null;
|
|
5796
6499
|
return {
|
|
5797
|
-
widthPt: w === null ? null : w /
|
|
6500
|
+
widthPt: w === null ? null : w / EMU_PER_POINT,
|
|
5798
6501
|
dash: dash ? attr(dash, "val") ?? null : null,
|
|
6502
|
+
resolvedColor: resolved,
|
|
5799
6503
|
color: resolved ? resolved.effectiveHex : null,
|
|
5800
6504
|
schemeColor: scheme,
|
|
5801
6505
|
noFill: !!firstChild(ln, "a:noFill")
|
|
@@ -5860,7 +6564,7 @@ var TableCell = class {
|
|
|
5860
6564
|
const rig = firstChild(cell3D, "a:lightRig");
|
|
5861
6565
|
const pts = (value) => {
|
|
5862
6566
|
const emu = intValue(value);
|
|
5863
|
-
return emu === null ? null : emu /
|
|
6567
|
+
return emu === null ? null : emu / EMU_PER_POINT;
|
|
5864
6568
|
};
|
|
5865
6569
|
return {
|
|
5866
6570
|
material: attr(cell3D, "prstMaterial") ?? null,
|
|
@@ -6242,6 +6946,6 @@ function findShapeByIdDeep(shapes, id) {
|
|
|
6242
6946
|
}
|
|
6243
6947
|
}
|
|
6244
6948
|
//#endregion
|
|
6245
|
-
export { collectElements as $,
|
|
6949
|
+
export { collectElements as $, spPrXfrmEmu as A, resolveRelativePartName as At, LST_STYLE_LEVELS as B, firstChildElement as Bt, Connector as C, SPPR_LN_AFTER as Ct, Paragraph as D, partNameToZipPath as Dt, Shape as E, partNameExtension as Et, resolveLayoutColorContext as F, childElements as Ft, placeholderInheritedRunProps as G, ownerDocumentOf as Gt, placeholderInheritedAnchor as H, getOrAddChild as Ht, resolveMasterColorContext as I, createElement as It, slideDefinesColor as J, removeChildrenByQName as Jt, placeholderInheritedXfrm as K, parseXml as Kt, resolveNotesColorContext as L, descendantsByTag as Lt, readPictureFill as M, zipPathToPartName as Mt, readGradientFill as N, attr as Nt, Run as O, relativePartName as Ot, resolveColorElement as P, boolValue as Pt, carriedDecorations as Q, resolveSlideColorContext as R, escapeXmlAttribute as Rt, ChartSeries as S, SPPR_FILL_AFTER as St, AutoShape as T, SPPR_SP3D_AFTER as Tt, placeholderInheritedColor as U, insertInOrder as Ut, RUN_PROP_NAMES as V, getElements as Vt, placeholderInheritedListStyles as W, intValue as Wt, cSldName as X, serializeXml as Xt, slideDefinesProp as Y, replaceInParent as Yt, cSldOf as Z, setAttr as Zt, ChartEx as _, FILL_CHOICES as _t, isConnector as a, fmtEntry as at, Chart as b, SPPR_AFTER_XFRM as bt, isPicture as c, parseClrMap as ct, Table as d, resolveSchemeToken as dt, firstShapeChild as et, TableCell as f, styleRefFill as ft, DiagramPoint as g, applyColorTransforms as gt, DiagramNode as h, presetColorHex as ht, isAutoShape as i, SCHEME_SLOTS as it, readPatternFill as j, resolveSingleRel as jt, TextFrame as k, relsPartNameFor as kt, wrapShapeElement as l, parseClrScheme as lt, Diagram as m, substitutePhClr as mt, buildShapes as n, nvPrOf as nt, isGraphicFrame as o, intAttr as ot, TableRow as p, styleRefLine as pt, placeholderOf as q, removeAttr as qt, findShapeByIdDeep as r, spTreeOf as rt, isGroupShape as s, isA as st, GroupShape as t, nthShapeChild as tt, GraphicFrame as u, resolveColor as ut, ChartExAxis as v, RPR_FILL_AFTER as vt, Picture as w, SPPR_SCENE3D_AFTER as wt, ChartAxis as x, SPPR_EFFECT_AFTER as xt, ChartExSeries as y, SHAPE_AFTER_SPPR as yt, resolveSlideThemeParts as z, firstChild as zt };
|
|
6246
6950
|
|
|
6247
|
-
//# sourceMappingURL=shapes-
|
|
6951
|
+
//# sourceMappingURL=shapes-BemroU-z.js.map
|