pptx-react-viewer 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/index.js +587 -288
  2. package/dist/index.mjs +587 -288
  3. package/dist/pptx-viewer.css +1 -1
  4. package/dist/viewer/index.js +587 -288
  5. package/dist/viewer/index.mjs +587 -288
  6. package/node_modules/emf-converter/package.json +2 -2
  7. package/node_modules/mtx-decompressor/package.json +2 -2
  8. package/node_modules/pptx-viewer-core/dist/{SvgExporter--H1PDfAY.d.ts → SvgExporter-0TxiiorD.d.ts} +1 -1
  9. package/node_modules/pptx-viewer-core/dist/{SvgExporter-Dq_2eV_r.d.mts → SvgExporter-BQ4KbRO9.d.mts} +1 -1
  10. package/node_modules/pptx-viewer-core/dist/cli/index.d.mts +2 -2
  11. package/node_modules/pptx-viewer-core/dist/cli/index.d.ts +2 -2
  12. package/node_modules/pptx-viewer-core/dist/cli/index.js +2875 -321
  13. package/node_modules/pptx-viewer-core/dist/cli/index.mjs +2875 -321
  14. package/node_modules/pptx-viewer-core/dist/converter/index.d.mts +3 -3
  15. package/node_modules/pptx-viewer-core/dist/converter/index.d.ts +3 -3
  16. package/node_modules/pptx-viewer-core/dist/index.d.mts +713 -44
  17. package/node_modules/pptx-viewer-core/dist/index.d.ts +713 -44
  18. package/node_modules/pptx-viewer-core/dist/index.js +2958 -390
  19. package/node_modules/pptx-viewer-core/dist/index.mjs +2949 -390
  20. package/node_modules/pptx-viewer-core/dist/{presentation-BozkirFp.d.mts → presentation-ArhfImJ5.d.mts} +225 -8
  21. package/node_modules/pptx-viewer-core/dist/{presentation-BozkirFp.d.ts → presentation-ArhfImJ5.d.ts} +225 -8
  22. package/node_modules/pptx-viewer-core/dist/{text-operations-B2JbPA5H.d.mts → text-operations-CLj-sJyk.d.mts} +1 -1
  23. package/node_modules/pptx-viewer-core/dist/{text-operations-zwF6i4eH.d.ts → text-operations-rhJV-A_W.d.ts} +1 -1
  24. package/node_modules/pptx-viewer-core/package.json +5 -5
  25. package/package.json +20 -20
@@ -676,12 +676,25 @@ function svgToCustomGeometryPaths(pathData, width, height) {
676
676
  function pointToXml(pt2) {
677
677
  return { "@_x": String(Math.round(pt2.x)), "@_y": String(Math.round(pt2.y)) };
678
678
  }
679
- function customGeometryPathsToXml(paths) {
679
+ function customGeometryPathsToXml(paths, rawData) {
680
680
  const xmlPaths = paths.map((path) => {
681
681
  const pathXml = {
682
682
  "@_w": String(Math.round(path.width)),
683
683
  "@_h": String(Math.round(path.height))
684
684
  };
685
+ if (path.fillMode) {
686
+ pathXml["@_fill"] = path.fillMode;
687
+ }
688
+ if (path.stroke === false) {
689
+ pathXml["@_stroke"] = "0";
690
+ } else if (path.stroke === true) {
691
+ pathXml["@_stroke"] = "1";
692
+ }
693
+ if (path.extrusionOk === true) {
694
+ pathXml["@_extrusionOk"] = "1";
695
+ } else if (path.extrusionOk === false) {
696
+ pathXml["@_extrusionOk"] = "0";
697
+ }
685
698
  const moveToList = [];
686
699
  const lnToList = [];
687
700
  const cubicBezToList = [];
@@ -739,12 +752,12 @@ function customGeometryPathsToXml(paths) {
739
752
  }
740
753
  return pathXml;
741
754
  });
742
- return {
755
+ const result = {
743
756
  "a:avLst": {},
744
- "a:gdLst": {},
745
- "a:ahLst": {},
746
- "a:cxnLst": {},
747
- "a:rect": {
757
+ "a:gdLst": rawData?.gdLstXml ?? {},
758
+ "a:ahLst": rawData?.ahLstXml ?? {},
759
+ "a:cxnLst": rawData?.cxnLstXml ?? {},
760
+ "a:rect": rawData?.rectXml ?? {
748
761
  "@_l": "l",
749
762
  "@_t": "t",
750
763
  "@_r": "r",
@@ -754,6 +767,7 @@ function customGeometryPathsToXml(paths) {
754
767
  "a:path": xmlPaths.length === 1 ? xmlPaths[0] : xmlPaths
755
768
  }
756
769
  };
770
+ return result;
757
771
  }
758
772
 
759
773
  // src/core/builders/sdk/ElementFactory.ts
@@ -1441,7 +1455,11 @@ function isoNow() {
1441
1455
  return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z");
1442
1456
  }
1443
1457
  var STANDARD_LAYOUTS = [
1444
- { name: "Title Slide", type: "ctrTitle" },
1458
+ // `type` is ST_SlideLayoutType per ECMA-376 §19.7.15. The Title Slide
1459
+ // layout uses `title`; `ctrTitle` is a placeholder type (ST_PlaceholderType)
1460
+ // and is not valid here — PowerPoint's OPC loader rejects the package
1461
+ // with ERROR_FILE_CORRUPT (0x80070570) when it sees it.
1462
+ { name: "Title Slide", type: "title" },
1445
1463
  { name: "Title and Content", type: "obj" },
1446
1464
  { name: "Section Header", type: "secHead" },
1447
1465
  { name: "Two Content", type: "twoObj" },
@@ -1475,7 +1493,7 @@ ${slideOverrides}
1475
1493
  <Override PartName="/ppt/viewProps.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml"/>
1476
1494
  <Override PartName="/ppt/tableStyles.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml"/>
1477
1495
  <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
1478
- <Override PartName="/docProps/app.xml" ContentType="application/vnd.ms-officedocument.extended-properties+xml"/>
1496
+ <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
1479
1497
  </Types>`;
1480
1498
  }
1481
1499
  function rootRelsXml() {
@@ -1499,6 +1517,9 @@ ${Array.from(
1499
1517
  <p:presentation xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
1500
1518
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
1501
1519
  xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
1520
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
1521
+ xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main"
1522
+ xmlns:p15="http://schemas.microsoft.com/office/powerpoint/2012/main"
1502
1523
  saveSubsetFonts="1">
1503
1524
  <p:sldMasterIdLst>
1504
1525
  <p:sldMasterId id="2147483648" r:id="rId1"/>
@@ -2801,9 +2822,40 @@ var PptxPresentationSlidesReconciler = class {
2801
2822
  "@_r:id": slide.rId
2802
2823
  };
2803
2824
  });
2804
- presentation["p:sldIdLst"] = slideIdList;
2805
- input.presentationData["p:presentation"] = presentation;
2825
+ input.presentationData["p:presentation"] = this.insertSlideIdListInOrder(
2826
+ presentation,
2827
+ slideIdList
2828
+ );
2829
+ }
2830
+ }
2831
+ /**
2832
+ * Return a new presentation XML object whose `p:sldIdLst` child sits in the
2833
+ * schema-mandated position (after `sldMasterIdLst` / `notesMasterIdLst` /
2834
+ * `handoutMasterIdLst`, before `sldSz`). Non-sldIdLst keys keep their
2835
+ * relative order; attribute keys (`@_...`) stay at the front.
2836
+ */
2837
+ insertSlideIdListInOrder(presentation, slideIdList) {
2838
+ const before = /* @__PURE__ */ new Set([
2839
+ "p:sldMasterIdLst",
2840
+ "p:notesMasterIdLst",
2841
+ "p:handoutMasterIdLst"
2842
+ ]);
2843
+ const rebuilt = {};
2844
+ let inserted = false;
2845
+ for (const key of Object.keys(presentation)) {
2846
+ if (key === "p:sldIdLst") {
2847
+ continue;
2848
+ }
2849
+ if (!inserted && !key.startsWith("@_") && !before.has(key)) {
2850
+ rebuilt["p:sldIdLst"] = slideIdList;
2851
+ inserted = true;
2852
+ }
2853
+ rebuilt[key] = presentation[key];
2806
2854
  }
2855
+ if (!inserted) {
2856
+ rebuilt["p:sldIdLst"] = slideIdList;
2857
+ }
2858
+ return rebuilt;
2807
2859
  }
2808
2860
  async attachNewSlide(init) {
2809
2861
  const sourceSlidePath = init.input.findSourceSlidePath(init.slide.sourceSlideId);
@@ -2889,6 +2941,22 @@ var PptxPresentationSlidesReconciler = class {
2889
2941
  };
2890
2942
 
2891
2943
  // src/core/core/builders/PptxSlideRelationshipRegistry.ts
2944
+ function isExternalTarget(target) {
2945
+ const normalized = target.trim();
2946
+ if (normalized.length === 0) {
2947
+ return false;
2948
+ }
2949
+ const colonIdx = normalized.indexOf(":");
2950
+ if (colonIdx <= 0) {
2951
+ return false;
2952
+ }
2953
+ const slashIdx = normalized.indexOf("/");
2954
+ if (slashIdx !== -1 && slashIdx < colonIdx) {
2955
+ return false;
2956
+ }
2957
+ const scheme = normalized.slice(0, colonIdx);
2958
+ return /^[A-Za-z][A-Za-z0-9+\-.]*$/.test(scheme);
2959
+ }
2892
2960
  var PptxSlideRelationshipRegistry = class {
2893
2961
  relationships;
2894
2962
  usedRelationshipIds = /* @__PURE__ */ new Set();
@@ -2959,7 +3027,7 @@ var PptxSlideRelationshipRegistry = class {
2959
3027
  return existingRelationshipId;
2960
3028
  }
2961
3029
  const relationshipId = this.nextRelationshipId();
2962
- const targetMode = /^(https?:|mailto:|ftp:|file:)/i.test(normalizedTarget) ? "External" : void 0;
3030
+ const targetMode = isExternalTarget(normalizedTarget) ? "External" : void 0;
2963
3031
  this.upsertRelationship(
2964
3032
  relationshipId,
2965
3033
  this.hyperlinkRelationshipType,
@@ -3209,6 +3277,82 @@ var PptxSlideNotesPartUpdater = class {
3209
3277
  }
3210
3278
  };
3211
3279
 
3280
+ // src/core/utils/xml-reorder.ts
3281
+ function reorderObjectKeys(obj, schemaOrder) {
3282
+ const result = {};
3283
+ const consumed = /* @__PURE__ */ new Set();
3284
+ for (const key of schemaOrder) {
3285
+ if (Object.hasOwn(obj, key)) {
3286
+ const value = obj[key];
3287
+ if (value !== void 0) {
3288
+ result[key] = value;
3289
+ }
3290
+ consumed.add(key);
3291
+ }
3292
+ }
3293
+ for (const key of Object.keys(obj)) {
3294
+ if (consumed.has(key)) {
3295
+ continue;
3296
+ }
3297
+ const value = obj[key];
3298
+ if (value !== void 0) {
3299
+ result[key] = value;
3300
+ }
3301
+ }
3302
+ return result;
3303
+ }
3304
+ var EFFECT_LST_ORDER = [
3305
+ "a:blur",
3306
+ "a:fillOverlay",
3307
+ "a:glow",
3308
+ "a:innerShdw",
3309
+ "a:outerShdw",
3310
+ "a:prstShdw",
3311
+ "a:reflection",
3312
+ "a:softEdge"
3313
+ ];
3314
+ var SP_PR_ORDER = [
3315
+ "a:xfrm",
3316
+ "a:custGeom",
3317
+ "a:prstGeom",
3318
+ "a:noFill",
3319
+ "a:solidFill",
3320
+ "a:gradFill",
3321
+ "a:blipFill",
3322
+ "a:pattFill",
3323
+ "a:grpFill",
3324
+ "a:ln",
3325
+ "a:effectLst",
3326
+ "a:effectDag",
3327
+ "a:scene3d",
3328
+ "a:sp3d",
3329
+ "a:extLst"
3330
+ ];
3331
+ var TC_PR_BORDERS_ORDER = [
3332
+ "a:lnL",
3333
+ "a:lnR",
3334
+ "a:lnT",
3335
+ "a:lnB",
3336
+ "a:lnTlToBr",
3337
+ "a:lnBlToTr",
3338
+ "a:cell3D",
3339
+ "a:noFill",
3340
+ "a:solidFill",
3341
+ "a:gradFill",
3342
+ "a:blipFill",
3343
+ "a:pattFill",
3344
+ "a:grpFill",
3345
+ "a:headers",
3346
+ "a:extLst"
3347
+ ];
3348
+ var BLIP_FILL_ORDER = ["a:blip", "a:srcRect", "a:tile", "a:stretch"];
3349
+ var SHAPE_STYLE_ORDER = [
3350
+ "a:lnRef",
3351
+ "a:fillRef",
3352
+ "a:effectRef",
3353
+ "a:fontRef"
3354
+ ];
3355
+
3212
3356
  // src/core/core/builders/PptxSlideBackgroundBuilder.ts
3213
3357
  var PptxSlideBackgroundBuilder = class {
3214
3358
  applyBackground(init) {
@@ -3244,10 +3388,13 @@ var PptxSlideBackgroundBuilder = class {
3244
3388
  init.slideImageRelationshipType,
3245
3389
  relativeBackgroundImagePath
3246
3390
  );
3247
- backgroundProperties["a:blipFill"] = {
3248
- "a:blip": { "@_r:embed": backgroundRelationshipId },
3249
- "a:stretch": { "a:fillRect": {} }
3250
- };
3391
+ backgroundProperties["a:blipFill"] = reorderObjectKeys(
3392
+ {
3393
+ "a:blip": { "@_r:embed": backgroundRelationshipId },
3394
+ "a:stretch": { "a:fillRect": {} }
3395
+ },
3396
+ BLIP_FILL_ORDER
3397
+ );
3251
3398
  }
3252
3399
  } else if (hasBackgroundColor && init.slide.backgroundColor) {
3253
3400
  backgroundProperties["a:solidFill"] = {
@@ -4069,6 +4216,45 @@ var PptxGradientStyleCodec = class {
4069
4216
  b: Number.isFinite(b) ? this.context.clampUnitInterval(b / 1e5) : 0
4070
4217
  };
4071
4218
  }
4219
+ extractGradientFlip(gradFill) {
4220
+ const flipRaw = String(gradFill["@_flip"] || "").trim().toLowerCase();
4221
+ if (flipRaw === "x" || flipRaw === "y" || flipRaw === "xy" || flipRaw === "none") {
4222
+ return flipRaw;
4223
+ }
4224
+ return void 0;
4225
+ }
4226
+ extractGradientRotWithShape(gradFill) {
4227
+ const rot = gradFill["@_rotWithShape"];
4228
+ if (rot === void 0 || rot === null) {
4229
+ return void 0;
4230
+ }
4231
+ const token = String(rot).trim().toLowerCase();
4232
+ if (token === "1" || token === "true") {
4233
+ return true;
4234
+ }
4235
+ if (token === "0" || token === "false") {
4236
+ return false;
4237
+ }
4238
+ return void 0;
4239
+ }
4240
+ extractGradientScaled(gradFill) {
4241
+ const lin = gradFill["a:lin"];
4242
+ if (!lin) {
4243
+ return void 0;
4244
+ }
4245
+ const scaled = lin["@_scaled"];
4246
+ if (scaled === void 0 || scaled === null) {
4247
+ return void 0;
4248
+ }
4249
+ const token = String(scaled).trim().toLowerCase();
4250
+ if (token === "1" || token === "true") {
4251
+ return true;
4252
+ }
4253
+ if (token === "0" || token === "false") {
4254
+ return false;
4255
+ }
4256
+ return void 0;
4257
+ }
4072
4258
  extractGradientAngle(gradFill) {
4073
4259
  const angleRaw = Number.parseInt(
4074
4260
  String(gradFill["a:lin"]?.["@_ang"] || ""),
@@ -4155,11 +4341,14 @@ var PptxGradientStyleCodec = class {
4155
4341
  return void 0;
4156
4342
  }
4157
4343
  const gradientType = shapeStyle.fillGradientType || "linear";
4158
- const gradientXml = {
4159
- "a:gsLst": {
4160
- "a:gs": stops
4161
- }
4162
- };
4344
+ const gradientXml = {};
4345
+ if (shapeStyle.fillGradientFlip && shapeStyle.fillGradientFlip !== "none") {
4346
+ gradientXml["@_flip"] = shapeStyle.fillGradientFlip;
4347
+ }
4348
+ if (shapeStyle.fillGradientRotWithShape !== void 0) {
4349
+ gradientXml["@_rotWithShape"] = shapeStyle.fillGradientRotWithShape ? "1" : "0";
4350
+ }
4351
+ gradientXml["a:gsLst"] = { "a:gs": stops };
4163
4352
  if (gradientType === "radial") {
4164
4353
  const pathType = shapeStyle.fillGradientPathType || "circle";
4165
4354
  const pathXml = {
@@ -4189,10 +4378,15 @@ var PptxGradientStyleCodec = class {
4189
4378
  gradientXml["a:path"] = pathXml;
4190
4379
  } else {
4191
4380
  const normalizedAngle = typeof shapeStyle.fillGradientAngle === "number" && Number.isFinite(shapeStyle.fillGradientAngle) ? shapeStyle.fillGradientAngle : 90;
4192
- gradientXml["a:lin"] = {
4193
- "@_ang": String(Math.round(normalizedAngle * 6e4)),
4194
- "@_scaled": "1"
4381
+ const linNode = {
4382
+ "@_ang": String(Math.round(normalizedAngle * 6e4))
4195
4383
  };
4384
+ if (shapeStyle.fillGradientScaled !== void 0) {
4385
+ linNode["@_scaled"] = shapeStyle.fillGradientScaled ? "1" : "0";
4386
+ } else {
4387
+ linNode["@_scaled"] = "1";
4388
+ }
4389
+ gradientXml["a:lin"] = linNode;
4196
4390
  }
4197
4391
  return gradientXml;
4198
4392
  }
@@ -4589,6 +4783,30 @@ var PRESET_SHADOW_OPACITY_MAP = {
4589
4783
  };
4590
4784
 
4591
4785
  // src/core/core/builders/PptxShapeEffectStyleExtractor.ts
4786
+ var VALID_ALIGNMENTS = /* @__PURE__ */ new Set(["tl", "t", "tr", "l", "ctr", "r", "bl", "b", "br"]);
4787
+ function parseIntAttr(value) {
4788
+ if (value === void 0 || value === null || value === "") {
4789
+ return void 0;
4790
+ }
4791
+ const parsed = Number.parseInt(String(value), 10);
4792
+ return Number.isFinite(parsed) ? parsed : void 0;
4793
+ }
4794
+ function parseAlignmentAttr(value) {
4795
+ const v = String(value ?? "").trim();
4796
+ return VALID_ALIGNMENTS.has(v) ? v : void 0;
4797
+ }
4798
+ function parseBoolAttr(value) {
4799
+ if (typeof value === "boolean") {
4800
+ return value;
4801
+ }
4802
+ if (value === "1" || value === "true") {
4803
+ return true;
4804
+ }
4805
+ if (value === "0" || value === "false") {
4806
+ return false;
4807
+ }
4808
+ return void 0;
4809
+ }
4592
4810
  var PptxShapeEffectStyleExtractor = class {
4593
4811
  context;
4594
4812
  constructor(context) {
@@ -4612,7 +4830,12 @@ var PptxShapeEffectStyleExtractor = class {
4612
4830
  const shadowOffsetX = distance !== void 0 ? Math.round(Math.cos(directionRadians) * distance * 100) / 100 : void 0;
4613
4831
  const shadowOffsetY = distance !== void 0 ? Math.round(Math.sin(directionRadians) * distance * 100) / 100 : void 0;
4614
4832
  const rotateWithShape = outerShadow["@_rotWithShape"];
4615
- const shadowRotateWithShape = typeof rotateWithShape === "boolean" ? rotateWithShape : rotateWithShape === "1" || rotateWithShape === "true" ? true : void 0;
4833
+ const shadowRotateWithShape = typeof rotateWithShape === "boolean" ? rotateWithShape : rotateWithShape === "1" || rotateWithShape === "true" ? true : rotateWithShape === "0" || rotateWithShape === "false" ? false : void 0;
4834
+ const shadowScaleX = parseIntAttr(outerShadow["@_sx"]);
4835
+ const shadowScaleY = parseIntAttr(outerShadow["@_sy"]);
4836
+ const shadowSkewX = parseIntAttr(outerShadow["@_kx"]);
4837
+ const shadowSkewY = parseIntAttr(outerShadow["@_ky"]);
4838
+ const shadowAlignment = parseAlignmentAttr(outerShadow["@_algn"]);
4616
4839
  return {
4617
4840
  shadowColor,
4618
4841
  shadowOpacity,
@@ -4621,7 +4844,12 @@ var PptxShapeEffectStyleExtractor = class {
4621
4844
  shadowOffsetY,
4622
4845
  shadowAngle: directionDegrees,
4623
4846
  shadowDistance: distance,
4624
- shadowRotateWithShape
4847
+ shadowRotateWithShape,
4848
+ shadowScaleX,
4849
+ shadowScaleY,
4850
+ shadowSkewX,
4851
+ shadowSkewY,
4852
+ shadowAlignment
4625
4853
  };
4626
4854
  }
4627
4855
  extractPresetShadowStyle(effectLstParent) {
@@ -4667,12 +4895,14 @@ var PptxShapeEffectStyleExtractor = class {
4667
4895
  const directionRadians = directionDegrees * Math.PI / 180;
4668
4896
  const innerShadowOffsetX = distance !== void 0 ? Math.round(Math.cos(directionRadians) * distance * 100) / 100 : void 0;
4669
4897
  const innerShadowOffsetY = distance !== void 0 ? Math.round(Math.sin(directionRadians) * distance * 100) / 100 : void 0;
4898
+ const innerShadowRotateWithShape = parseBoolAttr(innerShadow["@_rotWithShape"]);
4670
4899
  return {
4671
4900
  innerShadowColor,
4672
4901
  innerShadowOpacity,
4673
4902
  innerShadowBlur,
4674
4903
  innerShadowOffsetX,
4675
- innerShadowOffsetY
4904
+ innerShadowOffsetY,
4905
+ innerShadowRotateWithShape
4676
4906
  };
4677
4907
  }
4678
4908
  extractGlowStyle(shapeProps) {
@@ -4721,6 +4951,16 @@ var PptxShapeEffectStyleExtractor = class {
4721
4951
  const reflectionRotation = Number.isFinite(rotationRaw) ? rotationRaw / 6e4 : void 0;
4722
4952
  const distanceRaw = Number.parseInt(String(reflectionNode["@_dist"] || ""), 10);
4723
4953
  const reflectionDistance = Number.isFinite(distanceRaw) && distanceRaw >= 0 ? distanceRaw / this.context.emuPerPx : void 0;
4954
+ const fadeDirRaw = parseIntAttr(reflectionNode["@_fadeDir"]);
4955
+ const reflectionFadeDirection = fadeDirRaw !== void 0 ? fadeDirRaw / 6e4 : void 0;
4956
+ const reflectionScaleX = parseIntAttr(reflectionNode["@_sx"]);
4957
+ const reflectionScaleY = parseIntAttr(reflectionNode["@_sy"]);
4958
+ const reflectionSkewX = parseIntAttr(reflectionNode["@_kx"]);
4959
+ const reflectionSkewY = parseIntAttr(reflectionNode["@_ky"]);
4960
+ const reflectionAlignment = parseAlignmentAttr(reflectionNode["@_algn"]);
4961
+ const reflectionRotateWithShape = parseBoolAttr(reflectionNode["@_rotWithShape"]);
4962
+ const stPosRaw = parseIntAttr(reflectionNode["@_stPos"]);
4963
+ const reflectionStartPosition = stPosRaw !== void 0 ? stPosRaw / 1e5 : void 0;
4724
4964
  return {
4725
4965
  reflectionBlurRadius,
4726
4966
  reflectionStartOpacity,
@@ -4728,7 +4968,15 @@ var PptxShapeEffectStyleExtractor = class {
4728
4968
  reflectionEndPosition,
4729
4969
  reflectionDirection,
4730
4970
  reflectionRotation,
4731
- reflectionDistance
4971
+ reflectionDistance,
4972
+ reflectionFadeDirection,
4973
+ reflectionScaleX,
4974
+ reflectionScaleY,
4975
+ reflectionSkewX,
4976
+ reflectionSkewY,
4977
+ reflectionAlignment,
4978
+ reflectionRotateWithShape,
4979
+ reflectionStartPosition
4732
4980
  };
4733
4981
  }
4734
4982
  extractBlurStyle(shapeProps) {
@@ -4780,11 +5028,56 @@ var PptxShapeEffectXmlBuilder = class {
4780
5028
  }
4781
5029
  }
4782
5030
  };
5031
+ if (typeof shapeStyle.shadowScaleX === "number") {
5032
+ xmlObj["@_sx"] = String(Math.round(shapeStyle.shadowScaleX));
5033
+ }
5034
+ if (typeof shapeStyle.shadowScaleY === "number") {
5035
+ xmlObj["@_sy"] = String(Math.round(shapeStyle.shadowScaleY));
5036
+ }
5037
+ if (typeof shapeStyle.shadowSkewX === "number") {
5038
+ xmlObj["@_kx"] = String(Math.round(shapeStyle.shadowSkewX));
5039
+ }
5040
+ if (typeof shapeStyle.shadowSkewY === "number") {
5041
+ xmlObj["@_ky"] = String(Math.round(shapeStyle.shadowSkewY));
5042
+ }
5043
+ if (shapeStyle.shadowAlignment) {
5044
+ xmlObj["@_algn"] = shapeStyle.shadowAlignment;
5045
+ }
4783
5046
  if (typeof shapeStyle.shadowRotateWithShape === "boolean") {
4784
5047
  xmlObj["@_rotWithShape"] = shapeStyle.shadowRotateWithShape ? "1" : "0";
4785
5048
  }
4786
5049
  return xmlObj;
4787
5050
  }
5051
+ buildPresetShadowXml(shapeStyle) {
5052
+ const preset = shapeStyle.presetShadowName;
5053
+ if (!preset || preset.length === 0) {
5054
+ return void 0;
5055
+ }
5056
+ const shadowColor = String(shapeStyle.shadowColor || "#000000").trim();
5057
+ const shadowOpacity = typeof shapeStyle.shadowOpacity === "number" && Number.isFinite(shapeStyle.shadowOpacity) ? this.context.clampUnitInterval(shapeStyle.shadowOpacity) : 0.5;
5058
+ let distance;
5059
+ let directionDegrees;
5060
+ if (typeof shapeStyle.shadowAngle === "number" && typeof shapeStyle.shadowDistance === "number") {
5061
+ directionDegrees = shapeStyle.shadowAngle;
5062
+ distance = shapeStyle.shadowDistance;
5063
+ } else {
5064
+ const ox = typeof shapeStyle.shadowOffsetX === "number" ? shapeStyle.shadowOffsetX : 0;
5065
+ const oy = typeof shapeStyle.shadowOffsetY === "number" ? shapeStyle.shadowOffsetY : 0;
5066
+ distance = Math.sqrt(ox * ox + oy * oy);
5067
+ directionDegrees = (Math.atan2(oy, ox) * 180 / Math.PI + 360) % 360;
5068
+ }
5069
+ return {
5070
+ "@_prst": preset,
5071
+ "@_dist": String(Math.round(distance * this.context.emuPerPx)),
5072
+ "@_dir": String(Math.round(directionDegrees * 6e4)),
5073
+ "a:srgbClr": {
5074
+ "@_val": shadowColor.replace("#", ""),
5075
+ "a:alpha": {
5076
+ "@_val": String(Math.round(shadowOpacity * 1e5))
5077
+ }
5078
+ }
5079
+ };
5080
+ }
4788
5081
  buildInnerShadowXml(shapeStyle) {
4789
5082
  const innerColor = String(shapeStyle.innerShadowColor || "").trim();
4790
5083
  if (innerColor.length === 0 || innerColor === "transparent") {
@@ -4796,7 +5089,7 @@ var PptxShapeEffectXmlBuilder = class {
4796
5089
  const opacity = typeof shapeStyle.innerShadowOpacity === "number" && Number.isFinite(shapeStyle.innerShadowOpacity) ? this.context.clampUnitInterval(shapeStyle.innerShadowOpacity) : 0.5;
4797
5090
  const distance = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
4798
5091
  const directionDegrees = (Math.atan2(offsetY, offsetX) * 180 / Math.PI + 360) % 360;
4799
- return {
5092
+ const xmlObj = {
4800
5093
  "@_blurRad": String(Math.round(blurValue * this.context.emuPerPx)),
4801
5094
  "@_dist": String(Math.round(distance * this.context.emuPerPx)),
4802
5095
  "@_dir": String(Math.round(directionDegrees * 6e4)),
@@ -4807,6 +5100,10 @@ var PptxShapeEffectXmlBuilder = class {
4807
5100
  }
4808
5101
  }
4809
5102
  };
5103
+ if (typeof shapeStyle.innerShadowRotateWithShape === "boolean") {
5104
+ xmlObj["@_rotWithShape"] = shapeStyle.innerShadowRotateWithShape ? "1" : "0";
5105
+ }
5106
+ return xmlObj;
4810
5107
  }
4811
5108
  buildGlowXml(shapeStyle) {
4812
5109
  const glowColor = String(shapeStyle.glowColor || "").trim();
@@ -4868,6 +5165,30 @@ var PptxShapeEffectXmlBuilder = class {
4868
5165
  Math.round(shapeStyle.reflectionDistance * this.context.emuPerPx)
4869
5166
  );
4870
5167
  }
5168
+ if (typeof shapeStyle.reflectionFadeDirection === "number") {
5169
+ reflectionXml["@_fadeDir"] = String(Math.round(shapeStyle.reflectionFadeDirection * 6e4));
5170
+ }
5171
+ if (typeof shapeStyle.reflectionScaleX === "number") {
5172
+ reflectionXml["@_sx"] = String(Math.round(shapeStyle.reflectionScaleX));
5173
+ }
5174
+ if (typeof shapeStyle.reflectionScaleY === "number") {
5175
+ reflectionXml["@_sy"] = String(Math.round(shapeStyle.reflectionScaleY));
5176
+ }
5177
+ if (typeof shapeStyle.reflectionSkewX === "number") {
5178
+ reflectionXml["@_kx"] = String(Math.round(shapeStyle.reflectionSkewX));
5179
+ }
5180
+ if (typeof shapeStyle.reflectionSkewY === "number") {
5181
+ reflectionXml["@_ky"] = String(Math.round(shapeStyle.reflectionSkewY));
5182
+ }
5183
+ if (shapeStyle.reflectionAlignment) {
5184
+ reflectionXml["@_algn"] = shapeStyle.reflectionAlignment;
5185
+ }
5186
+ if (typeof shapeStyle.reflectionRotateWithShape === "boolean") {
5187
+ reflectionXml["@_rotWithShape"] = shapeStyle.reflectionRotateWithShape ? "1" : "0";
5188
+ }
5189
+ if (typeof shapeStyle.reflectionStartPosition === "number") {
5190
+ reflectionXml["@_stPos"] = String(Math.round(shapeStyle.reflectionStartPosition * 1e5));
5191
+ }
4871
5192
  return reflectionXml;
4872
5193
  }
4873
5194
  buildBlurXml(shapeStyle) {
@@ -4975,6 +5296,9 @@ var PptxShapeEffectXmlCodec = class {
4975
5296
  buildOuterShadowXml(shapeStyle) {
4976
5297
  return this.builder.buildOuterShadowXml(shapeStyle);
4977
5298
  }
5299
+ buildPresetShadowXml(shapeStyle) {
5300
+ return this.builder.buildPresetShadowXml(shapeStyle);
5301
+ }
4978
5302
  buildInnerShadowXml(shapeStyle) {
4979
5303
  return this.builder.buildInnerShadowXml(shapeStyle);
4980
5304
  }
@@ -5135,6 +5459,9 @@ var PptxColorStyleCodec = class {
5135
5459
  buildOuterShadowXml(shapeStyle) {
5136
5460
  return this.shapeEffectXmlCodec.buildOuterShadowXml(shapeStyle);
5137
5461
  }
5462
+ buildPresetShadowXml(shapeStyle) {
5463
+ return this.shapeEffectXmlCodec.buildPresetShadowXml(shapeStyle);
5464
+ }
5138
5465
  buildInnerShadowXml(shapeStyle) {
5139
5466
  return this.shapeEffectXmlCodec.buildInnerShadowXml(shapeStyle);
5140
5467
  }
@@ -5156,6 +5483,15 @@ var PptxColorStyleCodec = class {
5156
5483
  extractGradientFillColor(gradFill) {
5157
5484
  return this.gradientStyleCodec.extractGradientFillColor(gradFill);
5158
5485
  }
5486
+ extractGradientFlip(gradFill) {
5487
+ return this.gradientStyleCodec.extractGradientFlip(gradFill);
5488
+ }
5489
+ extractGradientRotWithShape(gradFill) {
5490
+ return this.gradientStyleCodec.extractGradientRotWithShape(gradFill);
5491
+ }
5492
+ extractGradientScaled(gradFill) {
5493
+ return this.gradientStyleCodec.extractGradientScaled(gradFill);
5494
+ }
5159
5495
  extractGradientPathType(gradFill) {
5160
5496
  return this.gradientStyleCodec.extractGradientPathType(gradFill);
5161
5497
  }
@@ -5167,6 +5503,61 @@ var PptxColorStyleCodec = class {
5167
5503
  }
5168
5504
  };
5169
5505
 
5506
+ // src/core/utils/color-xml-preservation.ts
5507
+ var COLOR_CHOICE_KEYS = [
5508
+ "a:srgbClr",
5509
+ "a:schemeClr",
5510
+ "a:sysClr",
5511
+ "a:prstClr",
5512
+ "a:scrgbClr",
5513
+ "a:hslClr"
5514
+ ];
5515
+ function extractColorChoiceXml(parent) {
5516
+ if (!parent) {
5517
+ return void 0;
5518
+ }
5519
+ for (const key of COLOR_CHOICE_KEYS) {
5520
+ if (parent[key] !== void 0) {
5521
+ return { [key]: parent[key] };
5522
+ }
5523
+ }
5524
+ return void 0;
5525
+ }
5526
+ function normalizeHex(value) {
5527
+ const raw = String(value ?? "").trim();
5528
+ if (raw.length === 0) {
5529
+ return "";
5530
+ }
5531
+ const hex = raw.replace(/^#/, "");
5532
+ if (/^[0-9a-fA-F]{6}$/.test(hex)) {
5533
+ return hex.toUpperCase();
5534
+ }
5535
+ return raw.toLowerCase();
5536
+ }
5537
+ function colorsEqual(left, right) {
5538
+ if (left === void 0 || right === void 0) {
5539
+ return false;
5540
+ }
5541
+ return normalizeHex(left) === normalizeHex(right);
5542
+ }
5543
+ function buildSrgbColorChoice(hex, opacity) {
5544
+ const normalized = String(hex || "").replace(/^#/, "");
5545
+ const srgb = { "@_val": normalized };
5546
+ if (typeof opacity === "number" && Number.isFinite(opacity) && opacity >= 0 && opacity < 1) {
5547
+ const alphaPct = Math.round(Math.max(0, Math.min(1, opacity)) * 1e5);
5548
+ srgb["a:alpha"] = { "@_val": String(alphaPct) };
5549
+ }
5550
+ return { "a:srgbClr": srgb };
5551
+ }
5552
+ function serializeColorChoice(originalColorXml, currentResolvedHex, fallbackHex, opacity, options = {}) {
5553
+ if (originalColorXml && colorsEqual(currentResolvedHex, fallbackHex)) {
5554
+ if (options.preserveAlphaFromOriginal !== false) {
5555
+ return originalColorXml;
5556
+ }
5557
+ }
5558
+ return buildSrgbColorChoice(fallbackHex, opacity);
5559
+ }
5560
+
5170
5561
  // src/core/core/builders/shape-style-3d-helpers.ts
5171
5562
  function applyScene3dStyle(shapeProps, style) {
5172
5563
  const scene3dNode = shapeProps["a:scene3d"];
@@ -5252,6 +5643,10 @@ function applyStrokeColor(lineNode, style, context) {
5252
5643
  const lineFill = lineNode["a:solidFill"];
5253
5644
  style.strokeColor = context.parseColor(lineFill);
5254
5645
  style.strokeOpacity = context.extractColorOpacity(lineFill);
5646
+ const strokeColorXml = extractColorChoiceXml(lineFill);
5647
+ if (strokeColorXml) {
5648
+ style.strokeColorXml = strokeColorXml;
5649
+ }
5255
5650
  } else if (lineNode["a:gradFill"]) {
5256
5651
  style.strokeColor = context.extractGradientFillColor(lineNode["a:gradFill"]);
5257
5652
  style.strokeOpacity = context.extractGradientOpacity(lineNode["a:gradFill"]);
@@ -5319,6 +5714,14 @@ function applyJoinCapCompound(lineNode, style) {
5319
5714
  style.lineJoin = "bevel";
5320
5715
  } else if ("a:miter" in lineNode) {
5321
5716
  style.lineJoin = "miter";
5717
+ const miterNode = lineNode["a:miter"];
5718
+ const limRaw = miterNode?.["@_lim"];
5719
+ if (limRaw !== void 0 && limRaw !== "") {
5720
+ const parsed = parseInt(String(limRaw), 10);
5721
+ if (Number.isFinite(parsed)) {
5722
+ style.miterLimit = parsed;
5723
+ }
5724
+ }
5322
5725
  }
5323
5726
  const capValue = String(lineNode["@_cap"] || "").trim().toLowerCase();
5324
5727
  if (capValue === "rnd" || capValue === "sq" || capValue === "flat") {
@@ -5375,6 +5778,10 @@ var PptxShapeStyleExtractor = class {
5375
5778
  style.fillMode = "solid";
5376
5779
  style.fillColor = this.context.parseColor(solidFill);
5377
5780
  style.fillOpacity = this.context.extractColorOpacity(solidFill);
5781
+ const solidFillColorXml = extractColorChoiceXml(solidFill);
5782
+ if (solidFillColorXml) {
5783
+ style.fillColorXml = solidFillColorXml;
5784
+ }
5378
5785
  } else if (gradFill) {
5379
5786
  style.fillMode = "gradient";
5380
5787
  style.fillColor = this.context.extractGradientFillColor(gradFill);
@@ -5386,6 +5793,18 @@ var PptxShapeStyleExtractor = class {
5386
5793
  style.fillGradientPathType = this.context.extractGradientPathType(gradFill);
5387
5794
  style.fillGradientFocalPoint = this.context.extractGradientFocalPoint(gradFill);
5388
5795
  style.fillGradientFillToRect = this.context.extractGradientFillToRect(gradFill);
5796
+ const gradFlip = this.context.extractGradientFlip(gradFill);
5797
+ if (gradFlip) {
5798
+ style.fillGradientFlip = gradFlip;
5799
+ }
5800
+ const gradRot = this.context.extractGradientRotWithShape(gradFill);
5801
+ if (gradRot !== void 0) {
5802
+ style.fillGradientRotWithShape = gradRot;
5803
+ }
5804
+ const gradScaled = this.context.extractGradientScaled(gradFill);
5805
+ if (gradScaled !== void 0) {
5806
+ style.fillGradientScaled = gradScaled;
5807
+ }
5389
5808
  } else if (pattFill) {
5390
5809
  style.fillMode = "pattern";
5391
5810
  style.fillColor = this.context.parseColor(pattFill["a:fgClr"]) || this.context.parseColor(pattFill["a:bgClr"]);
@@ -5467,10 +5886,45 @@ var PptxShapeStyleExtractor = class {
5467
5886
  if (styleNode?.["a:effectRef"]) {
5468
5887
  this.context.resolveThemeEffectRef(styleNode["a:effectRef"], style);
5469
5888
  }
5889
+ const fontRef = styleNode?.["a:fontRef"];
5890
+ if (fontRef) {
5891
+ const idxAttr = String(fontRef["@_idx"] || "").trim();
5892
+ if (idxAttr.length > 0) {
5893
+ style.fontRefIdx = idxAttr;
5894
+ }
5895
+ const overrideColorXml = this.extractFontRefColorXml(fontRef);
5896
+ if (overrideColorXml) {
5897
+ style.fontRefColorXml = overrideColorXml;
5898
+ }
5899
+ }
5470
5900
  applyScene3dStyle(shapeProps, style);
5471
5901
  applyShape3dStyle(shapeProps, style, this.context);
5472
5902
  return style;
5473
5903
  }
5904
+ /**
5905
+ * Pull the verbatim colour-choice child out of an `a:fontRef` element,
5906
+ * preserving any contained colour transforms for round-trip.
5907
+ */
5908
+ extractFontRefColorXml(refNode) {
5909
+ if (!refNode) {
5910
+ return void 0;
5911
+ }
5912
+ const keys = [
5913
+ "a:scrgbClr",
5914
+ "a:srgbClr",
5915
+ "a:hslClr",
5916
+ "a:sysClr",
5917
+ "a:schemeClr",
5918
+ "a:prstClr"
5919
+ ];
5920
+ for (const key of keys) {
5921
+ const child = refNode[key];
5922
+ if (child !== void 0) {
5923
+ return { [key]: child };
5924
+ }
5925
+ }
5926
+ return void 0;
5927
+ }
5474
5928
  /**
5475
5929
  * Extract p14:hiddenFill from the shape properties extension list.
5476
5930
  * URI: {AF507438-7753-43E0-B8FC-AC1667EBCBE1}
@@ -5521,10 +5975,15 @@ var PptxShapeStyleExtractor = class {
5521
5975
  function applyCellFillStyle(cellProperties, style, context) {
5522
5976
  let hasStyle = false;
5523
5977
  if (cellProperties?.["a:solidFill"]) {
5524
- const fillColor = context.parseColor(cellProperties["a:solidFill"]);
5978
+ const solidFillNode = cellProperties["a:solidFill"];
5979
+ const fillColor = context.parseColor(solidFillNode);
5525
5980
  if (fillColor) {
5526
5981
  style.fillMode = "solid";
5527
5982
  style.backgroundColor = fillColor;
5983
+ const bgColorXml = extractColorChoiceXml(solidFillNode);
5984
+ if (bgColorXml) {
5985
+ style.backgroundColorXml = bgColorXml;
5986
+ }
5528
5987
  hasStyle = true;
5529
5988
  }
5530
5989
  }
@@ -5561,6 +6020,10 @@ function applyCellFillStyle(cellProperties, style, context) {
5561
6020
  }
5562
6021
  }
5563
6022
  }
6023
+ if (cellProperties?.["a:noFill"] !== void 0) {
6024
+ style.fillMode = "none";
6025
+ hasStyle = true;
6026
+ }
5564
6027
  if (cellProperties?.["a:pattFill"]) {
5565
6028
  const pattFill = cellProperties["a:pattFill"];
5566
6029
  const fgColor = context.parseColor(pattFill["a:fgClr"]);
@@ -5867,8 +6330,7 @@ var PptxTableDataParser = class {
5867
6330
  return width / totalWidthEmu;
5868
6331
  }) : gridColumns.map(() => 1 / Math.max(gridColumns.length, 1));
5869
6332
  const tableProperties = tableNode["a:tblPr"] || {};
5870
- const tableStyleNode = tableProperties["a:tblStyle"];
5871
- const tableStyleId = String(tableStyleNode?.["@_val"] || tableProperties["@_tblStyle"] || "").trim() || void 0;
6333
+ const tableStyleId = this.extractTableStyleId(tableProperties);
5872
6334
  const xmlRows = this.context.ensureArray(tableNode["a:tr"]);
5873
6335
  const rows = xmlRows.map((rowNode) => {
5874
6336
  const rowHeightEmu = parseInt(String(rowNode?.["@_h"] || "0"), 10) || 0;
@@ -5903,6 +6365,28 @@ var PptxTableDataParser = class {
5903
6365
  return void 0;
5904
6366
  }
5905
6367
  }
6368
+ /**
6369
+ * Read the table style ID from `a:tblPr`.
6370
+ *
6371
+ * ECMA-376 §21.1.3.13 defines `<a:tableStyleId>{GUID}</a:tableStyleId>` as
6372
+ * a child element of `a:tblPr` carrying the GUID as element text. Older
6373
+ * inputs (and earlier versions of this library) used the legacy
6374
+ * `<a:tblStyle val="{GUID}"/>` child element or a `@_tblStyle` attribute.
6375
+ * Accept all three; the spec form takes precedence.
6376
+ */
6377
+ extractTableStyleId(tableProperties) {
6378
+ const tableStyleIdNode = tableProperties["a:tableStyleId"];
6379
+ if (tableStyleIdNode !== void 0 && tableStyleIdNode !== null) {
6380
+ const direct = typeof tableStyleIdNode === "string" || typeof tableStyleIdNode === "number" ? String(tableStyleIdNode) : String(tableStyleIdNode["#text"] ?? "");
6381
+ const trimmed = direct.trim();
6382
+ if (trimmed.length > 0) {
6383
+ return trimmed;
6384
+ }
6385
+ }
6386
+ const tableStyleNode = tableProperties["a:tblStyle"];
6387
+ const legacy = String(tableStyleNode?.["@_val"] || tableProperties["@_tblStyle"] || "").trim();
6388
+ return legacy.length > 0 ? legacy : void 0;
6389
+ }
5906
6390
  extractTableCellText(tableCell) {
5907
6391
  const paragraphs = this.context.ensureArray(tableCell?.["a:txBody"]?.["a:p"]);
5908
6392
  const lines = [];
@@ -6199,6 +6683,19 @@ var PptxGraphicFrameParser = class {
6199
6683
  if (graphicData["a:videoFile"] || graphicData["a:audioFile"] || uri.includes("/drawingml/2006/media")) {
6200
6684
  return "media";
6201
6685
  }
6686
+ if (graphicData["aink:ink"] || uri.includes("/2010/ink") || uri.includes("drawing/2010/ink")) {
6687
+ return "ink";
6688
+ }
6689
+ const alternateContent = graphicData["mc:AlternateContent"];
6690
+ if (alternateContent) {
6691
+ const choices = Array.isArray(alternateContent["mc:Choice"]) ? alternateContent["mc:Choice"] : alternateContent["mc:Choice"] ? [alternateContent["mc:Choice"]] : [];
6692
+ for (const choice of choices) {
6693
+ const requires = String(choice?.["@_Requires"] || "").toLowerCase();
6694
+ if (requires.includes("aink") || choice?.["aink:ink"]) {
6695
+ return "ink";
6696
+ }
6697
+ }
6698
+ }
6202
6699
  return "unknown";
6203
6700
  }
6204
6701
  };
@@ -7100,6 +7597,7 @@ var PptxDocumentPropertiesUpdater = class {
7100
7597
  }));
7101
7598
  if (sanitized.length === 0) {
7102
7599
  this.context.zip.remove("docProps/custom.xml");
7600
+ await this.removeCustomPropertiesPackagingArtifacts();
7103
7601
  return;
7104
7602
  }
7105
7603
  const customXml = {
@@ -7119,6 +7617,116 @@ var PptxDocumentPropertiesUpdater = class {
7119
7617
  }
7120
7618
  };
7121
7619
  this.context.zip.file("docProps/custom.xml", this.context.builder.build(customXml));
7620
+ await this.ensureCustomPropertiesPackagingArtifacts();
7621
+ }
7622
+ /**
7623
+ * Ensure `[Content_Types].xml` has an `Override` for `docProps/custom.xml`
7624
+ * and the root `_rels/.rels` references it (ECMA-376 §15.2.12.2 +
7625
+ * Part 2 §10.1.2.5). Without these, the package fails OPC validation
7626
+ * and Office strips the custom properties on next save.
7627
+ */
7628
+ async ensureCustomPropertiesPackagingArtifacts() {
7629
+ const customContentType = "application/vnd.openxmlformats-officedocument.custom-properties+xml";
7630
+ const customRelType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties";
7631
+ const ctFile = this.context.zip.file("[Content_Types].xml");
7632
+ if (ctFile) {
7633
+ try {
7634
+ const ctXml = await ctFile.async("string");
7635
+ const ctData = this.context.parser.parse(ctXml);
7636
+ const types = ctData["Types"];
7637
+ if (types) {
7638
+ const overrides = Array.isArray(types["Override"]) ? types["Override"] : types["Override"] ? [types["Override"]] : [];
7639
+ const hasCustomOverride = overrides.some(
7640
+ (o) => String(o?.["@_PartName"] || "") === "/docProps/custom.xml"
7641
+ );
7642
+ if (!hasCustomOverride) {
7643
+ overrides.push({
7644
+ "@_PartName": "/docProps/custom.xml",
7645
+ "@_ContentType": customContentType
7646
+ });
7647
+ types["Override"] = overrides.length === 1 ? overrides[0] : overrides;
7648
+ this.context.zip.file("[Content_Types].xml", this.context.builder.build(ctData));
7649
+ }
7650
+ }
7651
+ } catch (error) {
7652
+ console.warn("Failed to update [Content_Types].xml for custom properties:", error);
7653
+ }
7654
+ }
7655
+ const relsFile = this.context.zip.file("_rels/.rels");
7656
+ if (relsFile) {
7657
+ try {
7658
+ const relsXml = await relsFile.async("string");
7659
+ const relsData = this.context.parser.parse(relsXml);
7660
+ const relationships = relsData["Relationships"];
7661
+ if (relationships) {
7662
+ const rels = Array.isArray(relationships["Relationship"]) ? relationships["Relationship"] : relationships["Relationship"] ? [relationships["Relationship"]] : [];
7663
+ const hasCustomRel = rels.some((r) => String(r?.["@_Type"] || "") === customRelType);
7664
+ if (!hasCustomRel) {
7665
+ let maxId = 0;
7666
+ for (const rel of rels) {
7667
+ const id = String(rel?.["@_Id"] || "");
7668
+ const num = Number.parseInt(id.replace(/^rId/, ""), 10);
7669
+ if (Number.isFinite(num) && num > maxId) {
7670
+ maxId = num;
7671
+ }
7672
+ }
7673
+ rels.push({
7674
+ "@_Id": `rId${maxId + 1}`,
7675
+ "@_Type": customRelType,
7676
+ "@_Target": "docProps/custom.xml"
7677
+ });
7678
+ relationships["Relationship"] = rels;
7679
+ this.context.zip.file("_rels/.rels", this.context.builder.build(relsData));
7680
+ }
7681
+ }
7682
+ } catch (error) {
7683
+ console.warn("Failed to update _rels/.rels for custom properties:", error);
7684
+ }
7685
+ }
7686
+ }
7687
+ /**
7688
+ * Remove the Override + root rel for `docProps/custom.xml` when the
7689
+ * caller has emptied custom properties so the package doesn't keep an
7690
+ * orphan content-type entry referencing a deleted part.
7691
+ */
7692
+ async removeCustomPropertiesPackagingArtifacts() {
7693
+ const customRelType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties";
7694
+ const ctFile = this.context.zip.file("[Content_Types].xml");
7695
+ if (ctFile) {
7696
+ try {
7697
+ const ctXml = await ctFile.async("string");
7698
+ const ctData = this.context.parser.parse(ctXml);
7699
+ const types = ctData["Types"];
7700
+ if (types) {
7701
+ const overrides = Array.isArray(types["Override"]) ? types["Override"] : types["Override"] ? [types["Override"]] : [];
7702
+ const filtered = overrides.filter(
7703
+ (o) => String(o?.["@_PartName"] || "") !== "/docProps/custom.xml"
7704
+ );
7705
+ if (filtered.length !== overrides.length) {
7706
+ types["Override"] = filtered.length === 1 ? filtered[0] : filtered;
7707
+ this.context.zip.file("[Content_Types].xml", this.context.builder.build(ctData));
7708
+ }
7709
+ }
7710
+ } catch {
7711
+ }
7712
+ }
7713
+ const relsFile = this.context.zip.file("_rels/.rels");
7714
+ if (relsFile) {
7715
+ try {
7716
+ const relsXml = await relsFile.async("string");
7717
+ const relsData = this.context.parser.parse(relsXml);
7718
+ const relationships = relsData["Relationships"];
7719
+ if (relationships) {
7720
+ const rels = Array.isArray(relationships["Relationship"]) ? relationships["Relationship"] : relationships["Relationship"] ? [relationships["Relationship"]] : [];
7721
+ const filtered = rels.filter((r) => String(r?.["@_Type"] || "") !== customRelType);
7722
+ if (filtered.length !== rels.length) {
7723
+ relationships["Relationship"] = filtered;
7724
+ this.context.zip.file("_rels/.rels", this.context.builder.build(relsData));
7725
+ }
7726
+ }
7727
+ } catch {
7728
+ }
7729
+ }
7122
7730
  }
7123
7731
  normalizeCustomPropertyType(type) {
7124
7732
  const supportedTypes = /* @__PURE__ */ new Set([
@@ -7471,6 +8079,7 @@ var PptxSlideLoaderService = class {
7471
8079
  await params.loadSlideRelationships(path, slideRelsPath);
7472
8080
  const clrMapOverride = params.parseSlideClrMapOverride(slideXmlObj);
7473
8081
  params.setCurrentSlideClrMapOverride(clrMapOverride);
8082
+ await params.setActiveMasterForSlide?.(path);
7474
8083
  let restoreThemeOverride;
7475
8084
  try {
7476
8085
  const layoutPathForOverride = params.findLayoutPathForSlide(path);
@@ -12446,6 +13055,20 @@ var AXIS_TYPE_MAP = {
12446
13055
  dateAx: "dateAx",
12447
13056
  serAx: "serAx"
12448
13057
  };
13058
+ function upsertChartAxisChild(parent, localName, value, getLocalName) {
13059
+ const existingKey = Object.keys(parent).find((k) => getLocalName(k) === localName);
13060
+ if (value === void 0) {
13061
+ if (existingKey) {
13062
+ delete parent[existingKey];
13063
+ }
13064
+ return;
13065
+ }
13066
+ if (existingKey) {
13067
+ parent[existingKey]["@_val"] = value;
13068
+ } else {
13069
+ parent[`c:${localName}`] = { "@_val": value };
13070
+ }
13071
+ }
12449
13072
  function parseChartAxes(plotArea, xmlLookup, colorParser, getLocalName) {
12450
13073
  const result = [];
12451
13074
  for (const key of Object.keys(plotArea)) {
@@ -12566,6 +13189,27 @@ function parseSingleAxis(axisNode, axisType, xmlLookup, colorParser) {
12566
13189
  if (dispUnitsNode) {
12567
13190
  parseDisplayUnits(dispUnitsNode, xmlLookup, result);
12568
13191
  }
13192
+ const majorUnitNode = xmlLookup.getChildByLocalName(axisNode, "majorUnit");
13193
+ if (majorUnitNode) {
13194
+ const majorVal = parseFloat(String(majorUnitNode["@_val"]));
13195
+ if (Number.isFinite(majorVal)) {
13196
+ result.majorUnit = majorVal;
13197
+ }
13198
+ }
13199
+ const minorUnitNode = xmlLookup.getChildByLocalName(axisNode, "minorUnit");
13200
+ if (minorUnitNode) {
13201
+ const minorVal = parseFloat(String(minorUnitNode["@_val"]));
13202
+ if (Number.isFinite(minorVal)) {
13203
+ result.minorUnit = minorVal;
13204
+ }
13205
+ }
13206
+ const tickLblPosNode = xmlLookup.getChildByLocalName(axisNode, "tickLblPos");
13207
+ if (tickLblPosNode) {
13208
+ const v = String(tickLblPosNode["@_val"] || "").trim();
13209
+ if (v === "high" || v === "low" || v === "nextTo" || v === "none") {
13210
+ result.tickLblPos = v;
13211
+ }
13212
+ }
12569
13213
  return result;
12570
13214
  }
12571
13215
  var VALID_DISPLAY_UNITS = /* @__PURE__ */ new Set([
@@ -13878,23 +14522,55 @@ var SHAPE_TREE_ELEMENT_TAGS = /* @__PURE__ */ new Set([
13878
14522
  "p16:model3D",
13879
14523
  ...VML_SHAPE_TAGS
13880
14524
  ]);
14525
+ function diagnoseSelection(ac) {
14526
+ const choices = ensureArray2(ac["mc:Choice"]);
14527
+ for (let i = 0; i < choices.length; i++) {
14528
+ const choice = choices[i];
14529
+ const requires = String(choice?.["@_Requires"] ?? "").trim();
14530
+ if (requires.length === 0 || areNamespacesSupported(requires)) {
14531
+ const resolved = resolveNestedAlternateContent(choice);
14532
+ return { branch: "choice", choiceIndex: i, resolved };
14533
+ }
14534
+ }
14535
+ const fallback = ac["mc:Fallback"];
14536
+ if (fallback) {
14537
+ return { branch: "fallback", resolved: resolveNestedAlternateContent(fallback) };
14538
+ }
14539
+ return void 0;
14540
+ }
13881
14541
  function unwrapAlternateContent(container) {
13882
14542
  const altContents = ensureArray2(container["mc:AlternateContent"]);
13883
14543
  if (altContents.length === 0) {
13884
- return;
14544
+ return [];
13885
14545
  }
14546
+ const blocks = [];
13886
14547
  for (const ac of altContents) {
13887
- const branch = selectAlternateContentBranch(ac);
13888
- if (!branch) {
14548
+ const diagnosis = diagnoseSelection(ac);
14549
+ if (!diagnosis) {
13889
14550
  continue;
13890
14551
  }
14552
+ const block = {
14553
+ rawAc: ac,
14554
+ selectedBranch: diagnosis.branch,
14555
+ choiceIndex: diagnosis.branch === "choice" ? diagnosis.choiceIndex : void 0,
14556
+ childRefs: []
14557
+ };
14558
+ const branch = diagnosis.resolved;
13891
14559
  for (const tag of SHAPE_TREE_ELEMENT_TAGS) {
13892
14560
  const children = ensureArray2(branch[tag]);
13893
14561
  if (children.length > 0) {
13894
14562
  container[tag] = [...ensureArray2(container[tag]), ...children];
14563
+ for (const child of children) {
14564
+ block.childRefs.push({ tag, node: child });
14565
+ }
13895
14566
  }
13896
14567
  }
14568
+ if (block.childRefs.length > 0) {
14569
+ blocks.push(block);
14570
+ }
13897
14571
  }
14572
+ delete container["mc:AlternateContent"];
14573
+ return blocks;
13898
14574
  }
13899
14575
  function isNamespaceSupported(ns) {
13900
14576
  return SUPPORTED_MC_NAMESPACES.has(ns);
@@ -13912,7 +14588,7 @@ function ensureArray2(val) {
13912
14588
 
13913
14589
  // src/core/utils/body-properties-parser.ts
13914
14590
  function parseBodyPrBooleanAttrs(bodyPr, textStyle) {
13915
- const parseBoolAttr = (attr) => {
14591
+ const parseBoolAttr2 = (attr) => {
13916
14592
  const raw = bodyPr[attr];
13917
14593
  if (raw === void 0) {
13918
14594
  return void 0;
@@ -13920,19 +14596,19 @@ function parseBodyPrBooleanAttrs(bodyPr, textStyle) {
13920
14596
  const val = String(raw).trim().toLowerCase();
13921
14597
  return val === "1" || val === "true";
13922
14598
  };
13923
- const compatLnSpc = parseBoolAttr("@_compatLnSpc");
14599
+ const compatLnSpc = parseBoolAttr2("@_compatLnSpc");
13924
14600
  if (compatLnSpc !== void 0) {
13925
14601
  textStyle.compatibleLineSpacing = compatLnSpc;
13926
14602
  }
13927
- const forceAA = parseBoolAttr("@_forceAA");
14603
+ const forceAA = parseBoolAttr2("@_forceAA");
13928
14604
  if (forceAA !== void 0) {
13929
14605
  textStyle.forceAntiAlias = forceAA;
13930
14606
  }
13931
- const upright = parseBoolAttr("@_upright");
14607
+ const upright = parseBoolAttr2("@_upright");
13932
14608
  if (upright !== void 0) {
13933
14609
  textStyle.upright = upright;
13934
14610
  }
13935
- const fromWordArt = parseBoolAttr("@_fromWordArt");
14611
+ const fromWordArt = parseBoolAttr2("@_fromWordArt");
13936
14612
  if (fromWordArt !== void 0) {
13937
14613
  textStyle.fromWordArt = fromWordArt;
13938
14614
  }
@@ -13955,100 +14631,6 @@ function writeBodyPrBooleanAttrs(bodyPr, textStyle) {
13955
14631
  }
13956
14632
  }
13957
14633
 
13958
- // src/core/utils/theme-override-utils.ts
13959
- var COLOR_MAP_ALIAS_KEYS = [
13960
- "bg1",
13961
- "tx1",
13962
- "bg2",
13963
- "tx2",
13964
- "accent1",
13965
- "accent2",
13966
- "accent3",
13967
- "accent4",
13968
- "accent5",
13969
- "accent6",
13970
- "hlink",
13971
- "folHlink"
13972
- ];
13973
- var DEFAULT_COLOR_MAP = {
13974
- bg1: "lt1",
13975
- tx1: "dk1",
13976
- bg2: "lt2",
13977
- tx2: "dk2",
13978
- accent1: "accent1",
13979
- accent2: "accent2",
13980
- accent3: "accent3",
13981
- accent4: "accent4",
13982
- accent5: "accent5",
13983
- accent6: "accent6",
13984
- hlink: "hlink",
13985
- folHlink: "folHlink"
13986
- };
13987
- function buildClrMapOverrideXml(override) {
13988
- if (!override || Object.keys(override).length === 0) {
13989
- return { "a:masterClrMapping": {} };
13990
- }
13991
- const attrs2 = {};
13992
- for (const key of COLOR_MAP_ALIAS_KEYS) {
13993
- attrs2[`@_${key}`] = override[key] ?? DEFAULT_COLOR_MAP[key];
13994
- }
13995
- return { "a:overrideClrMapping": attrs2 };
13996
- }
13997
- function mergeThemeColorOverride(base, override) {
13998
- if (!override || Object.keys(override).length === 0) {
13999
- return { ...base };
14000
- }
14001
- const slotLookup = {};
14002
- for (const key of THEME_COLOR_SCHEME_KEYS) {
14003
- slotLookup[key] = base[key];
14004
- }
14005
- slotLookup["bg1"] = base.lt1;
14006
- slotLookup["tx1"] = base.dk1;
14007
- slotLookup["bg2"] = base.lt2;
14008
- slotLookup["tx2"] = base.dk2;
14009
- const result = { ...base };
14010
- for (const [alias, targetSlot] of Object.entries(override)) {
14011
- const resolvedColor = slotLookup[targetSlot] ?? base[targetSlot];
14012
- if (!resolvedColor) {
14013
- continue;
14014
- }
14015
- switch (alias) {
14016
- case "bg1":
14017
- result.lt1 = resolvedColor;
14018
- break;
14019
- case "tx1":
14020
- result.dk1 = resolvedColor;
14021
- break;
14022
- case "bg2":
14023
- result.lt2 = resolvedColor;
14024
- break;
14025
- case "tx2":
14026
- result.dk2 = resolvedColor;
14027
- break;
14028
- default: {
14029
- const schemeKey = alias;
14030
- if (schemeKey in result) {
14031
- result[schemeKey] = resolvedColor;
14032
- }
14033
- break;
14034
- }
14035
- }
14036
- }
14037
- return result;
14038
- }
14039
- function hasNonTrivialOverride(override) {
14040
- if (!override) {
14041
- return false;
14042
- }
14043
- for (const key of COLOR_MAP_ALIAS_KEYS) {
14044
- const overrideValue = override[key];
14045
- if (overrideValue && overrideValue !== DEFAULT_COLOR_MAP[key]) {
14046
- return true;
14047
- }
14048
- }
14049
- return false;
14050
- }
14051
-
14052
14634
  // src/core/utils/clone-utils.ts
14053
14635
  function cloneTextStyle(style) {
14054
14636
  if (!style) {
@@ -17089,6 +17671,100 @@ function resolveLayoutCategory(layoutType) {
17089
17671
  return "list";
17090
17672
  }
17091
17673
 
17674
+ // src/core/utils/theme-override-utils.ts
17675
+ var COLOR_MAP_ALIAS_KEYS = [
17676
+ "bg1",
17677
+ "tx1",
17678
+ "bg2",
17679
+ "tx2",
17680
+ "accent1",
17681
+ "accent2",
17682
+ "accent3",
17683
+ "accent4",
17684
+ "accent5",
17685
+ "accent6",
17686
+ "hlink",
17687
+ "folHlink"
17688
+ ];
17689
+ var DEFAULT_COLOR_MAP = {
17690
+ bg1: "lt1",
17691
+ tx1: "dk1",
17692
+ bg2: "lt2",
17693
+ tx2: "dk2",
17694
+ accent1: "accent1",
17695
+ accent2: "accent2",
17696
+ accent3: "accent3",
17697
+ accent4: "accent4",
17698
+ accent5: "accent5",
17699
+ accent6: "accent6",
17700
+ hlink: "hlink",
17701
+ folHlink: "folHlink"
17702
+ };
17703
+ function buildClrMapOverrideXml(override) {
17704
+ if (!override || Object.keys(override).length === 0) {
17705
+ return { "a:masterClrMapping": {} };
17706
+ }
17707
+ const attrs2 = {};
17708
+ for (const key of COLOR_MAP_ALIAS_KEYS) {
17709
+ attrs2[`@_${key}`] = override[key] ?? DEFAULT_COLOR_MAP[key];
17710
+ }
17711
+ return { "a:overrideClrMapping": attrs2 };
17712
+ }
17713
+ function mergeThemeColorOverride(base, override) {
17714
+ if (!override || Object.keys(override).length === 0) {
17715
+ return { ...base };
17716
+ }
17717
+ const slotLookup = {};
17718
+ for (const key of THEME_COLOR_SCHEME_KEYS) {
17719
+ slotLookup[key] = base[key];
17720
+ }
17721
+ slotLookup["bg1"] = base.lt1;
17722
+ slotLookup["tx1"] = base.dk1;
17723
+ slotLookup["bg2"] = base.lt2;
17724
+ slotLookup["tx2"] = base.dk2;
17725
+ const result = { ...base };
17726
+ for (const [alias, targetSlot] of Object.entries(override)) {
17727
+ const resolvedColor = slotLookup[targetSlot] ?? base[targetSlot];
17728
+ if (!resolvedColor) {
17729
+ continue;
17730
+ }
17731
+ switch (alias) {
17732
+ case "bg1":
17733
+ result.lt1 = resolvedColor;
17734
+ break;
17735
+ case "tx1":
17736
+ result.dk1 = resolvedColor;
17737
+ break;
17738
+ case "bg2":
17739
+ result.lt2 = resolvedColor;
17740
+ break;
17741
+ case "tx2":
17742
+ result.dk2 = resolvedColor;
17743
+ break;
17744
+ default: {
17745
+ const schemeKey = alias;
17746
+ if (schemeKey in result) {
17747
+ result[schemeKey] = resolvedColor;
17748
+ }
17749
+ break;
17750
+ }
17751
+ }
17752
+ }
17753
+ return result;
17754
+ }
17755
+ function hasNonTrivialOverride(override) {
17756
+ if (!override) {
17757
+ return false;
17758
+ }
17759
+ for (const key of COLOR_MAP_ALIAS_KEYS) {
17760
+ const overrideValue = override[key];
17761
+ if (overrideValue && overrideValue !== DEFAULT_COLOR_MAP[key]) {
17762
+ return true;
17763
+ }
17764
+ }
17765
+ return false;
17766
+ }
17767
+
17092
17768
  // src/core/utils/encryption-detection.ts
17093
17769
  var OLE_MAGIC = new Uint8Array([208, 207, 17, 224, 161, 27, 26, 225]);
17094
17770
  var ZIP_MAGIC = new Uint8Array([80, 75]);
@@ -24313,7 +24989,7 @@ async function repairPptx(buffer) {
24313
24989
  }
24314
24990
 
24315
24991
  // src/core/utils/theme-switching.ts
24316
- function normalizeHex(hex) {
24992
+ function normalizeHex2(hex) {
24317
24993
  if (!hex) {
24318
24994
  return "";
24319
24995
  }
@@ -24323,8 +24999,8 @@ function buildColorRemapTable(oldColorMap, newColorMap) {
24323
24999
  const remap = /* @__PURE__ */ new Map();
24324
25000
  const allKeys = [...THEME_COLOR_SCHEME_KEYS, "tx1", "bg1", "tx2", "bg2"];
24325
25001
  for (const key of allKeys) {
24326
- const oldVal = normalizeHex(oldColorMap[key]);
24327
- const newVal = normalizeHex(newColorMap[key]);
25002
+ const oldVal = normalizeHex2(oldColorMap[key]);
25003
+ const newVal = normalizeHex2(newColorMap[key]);
24328
25004
  if (oldVal && newVal && oldVal !== newVal) {
24329
25005
  remap.set(oldVal, `#${newVal}`);
24330
25006
  remap.set(`#${oldVal}`, `#${newVal}`);
@@ -24336,7 +25012,7 @@ function remapColor(color, remap) {
24336
25012
  if (!color) {
24337
25013
  return color;
24338
25014
  }
24339
- const normalized = normalizeHex(color);
25015
+ const normalized = normalizeHex2(color);
24340
25016
  const remapped = remap.get(normalized) ?? remap.get(`#${normalized}`);
24341
25017
  return remapped ?? color;
24342
25018
  }
@@ -24476,7 +25152,7 @@ function remapSlideColors(slide, remap) {
24476
25152
  function buildThemeColorMap(colorScheme) {
24477
25153
  const map = {};
24478
25154
  for (const key of THEME_COLOR_SCHEME_KEYS) {
24479
- map[key] = normalizeHex(colorScheme[key]);
25155
+ map[key] = normalizeHex2(colorScheme[key]);
24480
25156
  }
24481
25157
  map.tx1 = map.dk1;
24482
25158
  map.bg1 = map.lt1;
@@ -25449,8 +26125,11 @@ function relayoutSmartArt(smartArtData, containerWidth, containerHeight) {
25449
26125
 
25450
26126
  // src/core/core/runtime/PptxHandlerRuntimeSaveParagraphHelpers.ts
25451
26127
  var EMU_PER_PX5 = 9525;
25452
- function buildParagraphPropertiesXml(textStyle, paragraphAlign, bulletInfo, spacing) {
26128
+ function buildParagraphPropertiesXml(textStyle, paragraphAlign, bulletInfo, spacing, level) {
25453
26129
  const paragraphProps = {};
26130
+ if (typeof level === "number" && Number.isFinite(level) && level > 0) {
26131
+ paragraphProps["@_lvl"] = String(Math.min(Math.max(Math.round(level), 0), 8));
26132
+ }
25454
26133
  if (paragraphAlign) {
25455
26134
  paragraphProps["@_algn"] = paragraphAlign;
25456
26135
  }
@@ -25522,23 +26201,28 @@ function applyBulletProperties(paragraphProps, bulletInfo) {
25522
26201
  paragraphProps["a:buNone"] = {};
25523
26202
  return;
25524
26203
  }
25525
- if (bulletInfo.color) {
26204
+ if (bulletInfo.colorInherit) {
26205
+ paragraphProps["a:buClrTx"] = {};
26206
+ } else if (bulletInfo.color) {
25526
26207
  const colorHex = bulletInfo.color.replace("#", "");
25527
26208
  paragraphProps["a:buClr"] = {
25528
26209
  "a:srgbClr": { "@_val": colorHex }
25529
26210
  };
25530
26211
  }
25531
- if (bulletInfo.sizePercent !== void 0) {
26212
+ if (bulletInfo.sizeInherit) {
26213
+ paragraphProps["a:buSzTx"] = {};
26214
+ } else if (bulletInfo.sizePercent !== void 0) {
25532
26215
  paragraphProps["a:buSzPct"] = {
25533
26216
  "@_val": String(Math.round(bulletInfo.sizePercent * 1e3))
25534
26217
  };
25535
- }
25536
- if (bulletInfo.sizePts !== void 0) {
26218
+ } else if (bulletInfo.sizePts !== void 0) {
25537
26219
  paragraphProps["a:buSzPts"] = {
25538
26220
  "@_val": String(Math.round(bulletInfo.sizePts * 100))
25539
26221
  };
25540
26222
  }
25541
- if (bulletInfo.fontFamily) {
26223
+ if (bulletInfo.fontInherit) {
26224
+ paragraphProps["a:buFontTx"] = {};
26225
+ } else if (bulletInfo.fontFamily) {
25542
26226
  paragraphProps["a:buFont"] = {
25543
26227
  "@_typeface": bulletInfo.fontFamily
25544
26228
  };
@@ -25561,7 +26245,7 @@ function applyBulletProperties(paragraphProps, bulletInfo) {
25561
26245
  };
25562
26246
  }
25563
26247
  }
25564
- function assembleParagraphXml(runs, paragraphProps) {
26248
+ function assembleParagraphXml(runs, paragraphProps, endParaRunProperties) {
25565
26249
  const paragraph = {
25566
26250
  "a:pPr": paragraphProps
25567
26251
  };
@@ -25583,7 +26267,11 @@ function assembleParagraphXml(runs, paragraphProps) {
25583
26267
  if (cleanRegularRuns.length === 0 && fieldRuns.length === 0) {
25584
26268
  paragraph["a:r"] = runs.length > 1 ? runs : runs[0];
25585
26269
  }
25586
- paragraph["a:endParaRPr"] = { "@_lang": "en-US" };
26270
+ if (endParaRunProperties && typeof endParaRunProperties === "object") {
26271
+ paragraph["a:endParaRPr"] = endParaRunProperties;
26272
+ } else {
26273
+ paragraph["a:endParaRPr"] = { "@_lang": "en-US" };
26274
+ }
25587
26275
  return paragraph;
25588
26276
  }
25589
26277
  function computeUniformSegmentOverrides(textStyle, textSegments) {
@@ -25887,6 +26575,140 @@ var PptxHandlerRuntime = class {
25887
26575
  * `p:clrMapOvr / a:overrideClrMapping`.
25888
26576
  */
25889
26577
  currentSlideClrMapOverride = null;
26578
+ /**
26579
+ * Per-master colour map alias dictionaries parsed from each master's
26580
+ * `<p:clrMap>` element (e.g. `bg1 → lt1`, `tx1 → dk1`, `accent1 → accent1`).
26581
+ *
26582
+ * `clrMap` is the *aliasing* layer between logical colour names used in
26583
+ * DrawingML and the raw theme scheme slots. Per ECMA-376 §19.3.1.7 it
26584
+ * lives on each `p:sldMaster`, and slide layouts/slides may further
26585
+ * override it via `p:clrMapOvr`. Resolution must happen at colour-lookup
26586
+ * time, *not* by baking it into {@link themeColorMap}.
26587
+ *
26588
+ * Phase 2 Stream B / C-H4.
26589
+ */
26590
+ masterClrMaps = /* @__PURE__ */ new Map();
26591
+ /**
26592
+ * Per-master theme color maps. Each master may reference its own theme
26593
+ * file via `_rels/slideMasterN.xml.rels`. For multi-master decks, slides
26594
+ * must resolve scheme colours against their *own* master's theme.
26595
+ *
26596
+ * Falls back to {@link themeColorMap} when a master entry is missing.
26597
+ *
26598
+ * Phase 2 Stream B / C-H4.
26599
+ */
26600
+ masterThemeColorMaps = /* @__PURE__ */ new Map();
26601
+ /**
26602
+ * Per-master theme font maps. Same rationale as
26603
+ * {@link masterThemeColorMaps}: multi-master decks may have one font
26604
+ * scheme per theme.
26605
+ */
26606
+ masterThemeFontMaps = /* @__PURE__ */ new Map();
26607
+ /**
26608
+ * Per-master format schemes (fmtScheme). For multi-master decks each
26609
+ * master's slides should resolve fill/line/effect refs against the
26610
+ * matrix from that master's theme.
26611
+ */
26612
+ masterThemeFormatSchemes = /* @__PURE__ */ new Map();
26613
+ /**
26614
+ * Per-master mapping from slide-master path to the theme path it
26615
+ * references via `_rels/slideMasterN.xml.rels`. Populated by
26616
+ * {@link loadPerMasterThemes} during load. Used by the save-side
26617
+ * theme writer to know which themeN.xml to (re)emit for each master.
26618
+ *
26619
+ * Phase 4 Stream A / C-H3.
26620
+ */
26621
+ masterThemePaths = /* @__PURE__ */ new Map();
26622
+ /**
26623
+ * Per-script font tables for major and minor fonts. Captured per master
26624
+ * theme. Keys are master paths; values map `mj`/`mn` -> script tag (e.g.
26625
+ * `Hans`, `Hant`, `Arab`, `Hebr`, `Thai`, `Beng`, …) -> typeface name.
26626
+ *
26627
+ * Phase 4 Stream A / M4.
26628
+ */
26629
+ masterThemeMajorFontScripts = /* @__PURE__ */ new Map();
26630
+ masterThemeMinorFontScripts = /* @__PURE__ */ new Map();
26631
+ /**
26632
+ * Theme name attribute (`<a:theme @name>`) per master theme path.
26633
+ * Captured for byte-stable round-trip.
26634
+ */
26635
+ masterThemeNames = /* @__PURE__ */ new Map();
26636
+ /**
26637
+ * `<a:fontScheme @name>` per master theme path.
26638
+ */
26639
+ masterThemeFontSchemeNames = /* @__PURE__ */ new Map();
26640
+ /**
26641
+ * `<a:clrScheme @name>` per master theme path.
26642
+ */
26643
+ masterThemeColorSchemeNames = /* @__PURE__ */ new Map();
26644
+ /**
26645
+ * Raw original theme XML keyed by theme path. Captured at load-time.
26646
+ * Used by the save pipeline to passthrough the full theme XML when no
26647
+ * in-memory mutation has occurred — preserving fillStyleLst /
26648
+ * lnStyleLst / effectStyleLst / bgFillStyleLst /
26649
+ * extraClrSchemeLst / objectDefaults / extLst exactly as written.
26650
+ *
26651
+ * Phase 4 Stream A / C-H3.
26652
+ */
26653
+ originalThemeXmlByPath = /* @__PURE__ */ new Map();
26654
+ /**
26655
+ * Set of theme paths whose in-memory state has been mutated since
26656
+ * load. Saving a theme path that's NOT dirty is a no-op (the original
26657
+ * file already exists in the ZIP). Saving a dirty theme path
26658
+ * regenerates the part from in-memory state.
26659
+ *
26660
+ * Phase 4 Stream A / C-H3.
26661
+ */
26662
+ dirtyThemePaths = /* @__PURE__ */ new Set();
26663
+ /**
26664
+ * Per-master parsed `<p:txStyles>` (titleStyle/bodyStyle/otherStyle).
26665
+ * Populated by {@link enrichSlideMastersWithTxStyles} during load so the
26666
+ * inheritance chain can find the master text-style cascade without
26667
+ * re-parsing master XML on every lookup. Phase 4 Stream B / P-H1.
26668
+ */
26669
+ masterTxStylesCache = /* @__PURE__ */ new Map();
26670
+ /**
26671
+ * Captured `<a:objectDefaults>` snapshot per master theme path. The
26672
+ * full ECMA-376 inheritance chain (master / layout / placeholder /
26673
+ * objectDefaults) is non-trivial; we store the raw spDef/lnDef/txDef
26674
+ * subtrees and re-emit them verbatim for round-trip.
26675
+ *
26676
+ * Phase 4 Stream A / M5.
26677
+ */
26678
+ masterThemeObjectDefaults = /* @__PURE__ */ new Map();
26679
+ /**
26680
+ * Captured `<a:extraClrSchemeLst>` raw subtree per master theme path
26681
+ * for verbatim round-trip.
26682
+ *
26683
+ * Phase 4 Stream A.
26684
+ */
26685
+ masterThemeExtraClrSchemeLst = /* @__PURE__ */ new Map();
26686
+ /**
26687
+ * Captured `<a:custClrLst>` raw subtree per master theme path
26688
+ * for verbatim round-trip.
26689
+ *
26690
+ * Phase 4 Stream A.
26691
+ */
26692
+ masterThemeCustClrLst = /* @__PURE__ */ new Map();
26693
+ /**
26694
+ * Captured theme-level `<a:extLst>` raw subtree per master theme path.
26695
+ */
26696
+ masterThemeExtLst = /* @__PURE__ */ new Map();
26697
+ /**
26698
+ * Active master's clrMap for the slide currently being parsed. Walked
26699
+ * after `currentSlideClrMapOverride` (slide and layout overrides take
26700
+ * precedence). `null` means "fall through to themeColorMap directly".
26701
+ */
26702
+ currentMasterClrMap = null;
26703
+ /**
26704
+ * Snapshot of the global theme state taken right after
26705
+ * {@link loadThemeData} completes. Used as the fallback when a slide's
26706
+ * master has no per-master theme entry, so per-slide multi-master
26707
+ * switching does not leak the previous slide's master state.
26708
+ */
26709
+ globalThemeColorMapSnapshot = {};
26710
+ globalThemeFontMapSnapshot = {};
26711
+ globalThemeFormatSchemeSnapshot;
25890
26712
  /** Thumbnail image data from `docProps/thumbnail.jpeg` preserved for round-trip. */
25891
26713
  thumbnailData = null;
25892
26714
  /** Raw VBA project binary preserved for macro-enabled (.pptm) round-trip. */
@@ -25897,6 +26719,19 @@ var PptxHandlerRuntime = class {
25897
26719
  signatureDetection = null;
25898
26720
  /** Custom XML data parts parsed from `customXml/` in the OPC package. */
25899
26721
  customXmlParts = [];
26722
+ /**
26723
+ * Maps an element's `rawXml` reference to the `mc:AlternateContent`
26724
+ * envelope that originally wrapped it (CC-4). Populated during slide
26725
+ * (and `p:grpSp`) parsing; consulted at save time to re-emit the
26726
+ * original `<mc:Choice>` / `<mc:Fallback>` shape so legacy renderers
26727
+ * keep their fallback content.
26728
+ *
26729
+ * Multiple sibling elements may share the same `AlternateContentBlock`
26730
+ * value (a single AC envelope often wraps several child shapes — e.g.
26731
+ * `p14:media` + its `p:pic` fallback nest one each). WeakMap so AC
26732
+ * envelopes are GC'd if the parsed XmlObject is dropped.
26733
+ */
26734
+ alternateContentBlockByRawXml = /* @__PURE__ */ new WeakMap();
25900
26735
  /** Embedded fonts extracted during load, preserved for automatic re-embedding on save. */
25901
26736
  loadedEmbeddedFonts = [];
25902
26737
  /** Map of comment author IDs to display names (from `ppt/commentAuthors.xml`). */
@@ -27710,7 +28545,12 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
27710
28545
  const bgColor = this.parseBackgroundColor(bg);
27711
28546
  const spTree = master["p:cSld"]?.["p:spTree"];
27712
28547
  const placeholders = this.extractPlaceholderList(spTree);
27713
- return { path, backgroundColor: bgColor, placeholders };
28548
+ const result = { path, backgroundColor: bgColor, placeholders };
28549
+ const hf = parseHeaderFooterFlags(master["p:hf"]);
28550
+ if (hf) {
28551
+ result.headerFooter = hf;
28552
+ }
28553
+ return result;
27714
28554
  } catch (e) {
27715
28555
  console.warn("Failed to parse handout master:", e);
27716
28556
  return void 0;
@@ -27736,7 +28576,12 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
27736
28576
  const bgColor = this.parseBackgroundColor(bg);
27737
28577
  const spTree = master["p:cSld"]?.["p:spTree"];
27738
28578
  const placeholders = this.extractPlaceholderList(spTree);
27739
- return { path, backgroundColor: bgColor, placeholders };
28579
+ const result = { path, backgroundColor: bgColor, placeholders };
28580
+ const hf = parseHeaderFooterFlags(master["p:hf"]);
28581
+ if (hf) {
28582
+ result.headerFooter = hf;
28583
+ }
28584
+ return result;
27740
28585
  } catch (e) {
27741
28586
  console.warn("Failed to parse notes master:", e);
27742
28587
  return void 0;
@@ -27781,6 +28626,10 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
27781
28626
  const uVal = String(userDrawn).trim().toLowerCase();
27782
28627
  layout.userDrawn = uVal === "1" || uVal === "true";
27783
28628
  }
28629
+ const hf = parseHeaderFooterFlags(sldLayout["p:hf"]);
28630
+ if (hf) {
28631
+ layout.headerFooter = hf;
28632
+ }
27784
28633
  const clrMapOvr = sldLayout["p:clrMapOvr"];
27785
28634
  if (clrMapOvr && clrMapOvr["a:masterClrMapping"] === void 0) {
27786
28635
  const overrideNode = clrMapOvr["a:overrideClrMapping"];
@@ -28386,6 +29235,18 @@ function buildClrChangeNode(style) {
28386
29235
  }
28387
29236
 
28388
29237
  // src/core/core/runtime/PptxHandlerRuntimeSaveRunProperties.ts
29238
+ function applyFontMetadata(fontNode, panose, pitchFamily, charset) {
29239
+ if (panose && panose.length > 0) {
29240
+ fontNode["@_panose"] = panose;
29241
+ }
29242
+ if (typeof pitchFamily === "number" && Number.isFinite(pitchFamily)) {
29243
+ fontNode["@_pitchFamily"] = String(pitchFamily);
29244
+ }
29245
+ if (typeof charset === "number" && Number.isFinite(charset)) {
29246
+ fontNode["@_charset"] = String(charset);
29247
+ }
29248
+ return fontNode;
29249
+ }
28389
29250
  var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime11 {
28390
29251
  createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId) {
28391
29252
  const runProps = {
@@ -28443,6 +29304,12 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
28443
29304
  if (style.bookmark) {
28444
29305
  runProps["@_bmk"] = style.bookmark;
28445
29306
  }
29307
+ if (style.altLanguage) {
29308
+ runProps["@_altLang"] = style.altLanguage;
29309
+ }
29310
+ if (typeof style.smartTagId === "number" && Number.isFinite(style.smartTagId)) {
29311
+ runProps["@_smtId"] = String(style.smartTagId);
29312
+ }
28446
29313
  if (style.textOutlineWidth || style.textOutlineColor) {
28447
29314
  const lnObj = {};
28448
29315
  if (typeof style.textOutlineWidth === "number" && style.textOutlineWidth > 0) {
@@ -28458,11 +29325,12 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
28458
29325
  runProps["a:ln"] = lnObj;
28459
29326
  }
28460
29327
  if (style.color) {
28461
- runProps["a:solidFill"] = {
28462
- "a:srgbClr": {
28463
- "@_val": style.color.replace("#", "")
28464
- }
28465
- };
29328
+ const resolvedOriginalColor = style.colorXml ? this.parseColor(style.colorXml) : void 0;
29329
+ runProps["a:solidFill"] = serializeColorChoice(
29330
+ style.colorXml,
29331
+ resolvedOriginalColor,
29332
+ style.color
29333
+ );
28466
29334
  } else if (style.textFillGradientStops && style.textFillGradientStops.length > 0) {
28467
29335
  const gradStops = style.textFillGradientStops.filter((stop) => Boolean(stop?.color)).map((stop) => {
28468
29336
  const rawPos = (stop.position ?? 0) / 100;
@@ -28535,16 +29403,32 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
28535
29403
  };
28536
29404
  }
28537
29405
  if (style.fontFamily) {
28538
- runProps["a:latin"] = { "@_typeface": style.fontFamily };
28539
- runProps["a:ea"] = {
28540
- "@_typeface": style.eastAsiaFont || style.fontFamily
28541
- };
28542
- runProps["a:cs"] = {
28543
- "@_typeface": style.complexScriptFont || style.fontFamily
28544
- };
29406
+ runProps["a:latin"] = applyFontMetadata(
29407
+ { "@_typeface": style.fontFamily },
29408
+ style.latinFontPanose,
29409
+ style.latinFontPitchFamily,
29410
+ style.latinFontCharset
29411
+ );
29412
+ runProps["a:ea"] = applyFontMetadata(
29413
+ { "@_typeface": style.eastAsiaFont || style.fontFamily },
29414
+ style.eastAsiaFontPanose,
29415
+ style.eastAsiaFontPitchFamily,
29416
+ style.eastAsiaFontCharset
29417
+ );
29418
+ runProps["a:cs"] = applyFontMetadata(
29419
+ { "@_typeface": style.complexScriptFont || style.fontFamily },
29420
+ style.complexScriptFontPanose,
29421
+ style.complexScriptFontPitchFamily,
29422
+ style.complexScriptFontCharset
29423
+ );
28545
29424
  }
28546
29425
  if (style.symbolFont) {
28547
- runProps["a:sym"] = { "@_typeface": style.symbolFont };
29426
+ runProps["a:sym"] = applyFontMetadata(
29427
+ { "@_typeface": style.symbolFont },
29428
+ style.symbolFontPanose,
29429
+ style.symbolFontPitchFamily,
29430
+ style.symbolFontCharset
29431
+ );
28548
29432
  }
28549
29433
  if (style.hyperlink && resolveHyperlinkRelationshipId) {
28550
29434
  const hyperlinkTarget = String(style.hyperlink).trim();
@@ -28619,14 +29503,15 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
28619
29503
  lineSpacing: this.createLineSpacingXmlFromMultiplier(textStyle?.lineSpacing),
28620
29504
  lineSpacingExactPt: textStyle?.lineSpacingExactPt
28621
29505
  };
28622
- const createParagraph = (runs, bulletInfo) => {
29506
+ const createParagraph = (runs, bulletInfo, level, endParaRunProperties) => {
28623
29507
  const paragraphProps = buildParagraphPropertiesXml(
28624
29508
  textStyle,
28625
29509
  paragraphAlign,
28626
29510
  bulletInfo,
28627
- spacing
29511
+ spacing,
29512
+ level
28628
29513
  );
28629
- return assembleParagraphXml(runs, paragraphProps);
29514
+ return assembleParagraphXml(runs, paragraphProps, endParaRunProperties);
28630
29515
  };
28631
29516
  const createRun = (runText, style) => ({
28632
29517
  "a:rPr": this.createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId),
@@ -28674,13 +29559,19 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
28674
29559
  const paragraphs = [];
28675
29560
  let currentRuns = [];
28676
29561
  let currentBulletInfo;
29562
+ let currentLevel;
29563
+ let currentEndParaRunProperties;
28677
29564
  const pushParagraph = () => {
28678
29565
  if (currentRuns.length === 0) {
28679
29566
  currentRuns.push(createRun("", textStyle));
28680
29567
  }
28681
- paragraphs.push(createParagraph(currentRuns, currentBulletInfo));
29568
+ paragraphs.push(
29569
+ createParagraph(currentRuns, currentBulletInfo, currentLevel, currentEndParaRunProperties)
29570
+ );
28682
29571
  currentRuns = [];
28683
29572
  currentBulletInfo = void 0;
29573
+ currentLevel = void 0;
29574
+ currentEndParaRunProperties = void 0;
28684
29575
  };
28685
29576
  if (textSegments && textSegments.length > 0) {
28686
29577
  const uniformSegmentOverrides = computeUniformSegmentOverrides(textStyle, textSegments);
@@ -28692,8 +29583,16 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
28692
29583
  };
28693
29584
  const segmentText = String(segment.text ?? "");
28694
29585
  const lineParts = segmentText.split("\n");
28695
- if (currentRuns.length === 0 && segment.bulletInfo) {
28696
- currentBulletInfo = segment.bulletInfo;
29586
+ if (currentRuns.length === 0) {
29587
+ if (segment.bulletInfo) {
29588
+ currentBulletInfo = segment.bulletInfo;
29589
+ }
29590
+ if (segment.paragraphLevel !== void 0) {
29591
+ currentLevel = segment.paragraphLevel;
29592
+ }
29593
+ if (segment.endParaRunProperties) {
29594
+ currentEndParaRunProperties = segment.endParaRunProperties;
29595
+ }
28697
29596
  }
28698
29597
  lineParts.forEach((linePart, lineIndex) => {
28699
29598
  if (segment.rubyText !== void 0) {
@@ -28791,7 +29690,201 @@ var PptxHandlerRuntime14 = class extends PptxHandlerRuntime13 {
28791
29690
  };
28792
29691
 
28793
29692
  // src/core/core/runtime/PptxHandlerRuntimeSaveShapeXml.ts
29693
+ var OLE_OBJECT_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
29694
+ var IMAGE_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
29695
+ var OLE_GRAPHIC_DATA_URI = "http://schemas.openxmlformats.org/presentationml/2006/ole";
28794
29696
  var PptxHandlerRuntime15 = class _PptxHandlerRuntime extends PptxHandlerRuntime14 {
29697
+ /**
29698
+ * Build a `p:graphicFrame` XML skeleton for an SDK-created table.
29699
+ *
29700
+ * Tables round-trip as `<p:graphicFrame>/<a:graphic>/<a:graphicData
29701
+ * uri=".../drawingml/2006/table">/<a:tbl>` inside `p:spTree`. When the
29702
+ * element was loaded from an existing file, `el.rawXml` already contains
29703
+ * this envelope and the downstream `serializeTableDataToXml` path
29704
+ * populates cells in place. When the element was created via the SDK
29705
+ * (`SlideBuilder.addTable`), there is no `rawXml`, so this method
29706
+ * fabricates a minimal envelope with an empty `a:tbl`. The element
29707
+ * writer then calls `serializeTableDataToXml`, which triggers
29708
+ * `rebuildTableXmlFromData` and fills in `a:tblGrid` / `a:tr` children.
29709
+ */
29710
+ createTableGraphicFrameXml(el) {
29711
+ const EMU = _PptxHandlerRuntime.EMU_PER_PX;
29712
+ const offX = String(Math.round(el.x * EMU));
29713
+ const offY = String(Math.round(el.y * EMU));
29714
+ const extCx = String(Math.round(Math.max(el.width, 1) * EMU));
29715
+ const extCy = String(Math.round(Math.max(el.height, 1) * EMU));
29716
+ const tblPr = {
29717
+ "@_firstRow": el.tableData?.firstRowHeader ? "1" : "0",
29718
+ "@_bandRow": el.tableData?.bandedRows ? "1" : "0"
29719
+ };
29720
+ if (el.tableData?.tableStyleId) {
29721
+ tblPr["a:tableStyleId"] = el.tableData.tableStyleId;
29722
+ }
29723
+ return {
29724
+ "p:nvGraphicFramePr": {
29725
+ "p:cNvPr": { "@_id": "0", "@_name": el.name || "Table" },
29726
+ "p:cNvGraphicFramePr": {
29727
+ "a:graphicFrameLocks": { "@_noGrp": "1" }
29728
+ },
29729
+ "p:nvPr": {}
29730
+ },
29731
+ "p:xfrm": {
29732
+ "a:off": { "@_x": offX, "@_y": offY },
29733
+ "a:ext": { "@_cx": extCx, "@_cy": extCy }
29734
+ },
29735
+ "a:graphic": {
29736
+ "a:graphicData": {
29737
+ "@_uri": "http://schemas.openxmlformats.org/drawingml/2006/table",
29738
+ "a:tbl": {
29739
+ "a:tblPr": tblPr,
29740
+ "a:tblGrid": {}
29741
+ }
29742
+ }
29743
+ }
29744
+ };
29745
+ }
29746
+ /**
29747
+ * Build a `p:graphicFrame` XML skeleton for an OLE object element.
29748
+ *
29749
+ * Used both for SDK-created OLE elements (no `rawXml`) and to refresh
29750
+ * a few key attributes on a loaded element when the typed fields have
29751
+ * been mutated. The output is the canonical
29752
+ * `p:graphicFrame > a:graphic > a:graphicData uri="…/ole" > p:oleObj`
29753
+ * shape per ECMA-376 §19.3.1.34 / §13.3.4.
29754
+ *
29755
+ * The caller (`processSlideElement`) is responsible for ensuring the
29756
+ * embed / preview-image relationships referenced from `r:id` / `r:embed`
29757
+ * exist in the slide's rels file. This method does not register them
29758
+ * itself because the typed model does not currently carry the binary
29759
+ * payload — the binary part must already be in the package (loaded from
29760
+ * the original file). A fully-fabricated SDK OLE element therefore
29761
+ * still requires the consumer to attach the binary out-of-band; this
29762
+ * method simply emits a schema-valid envelope referencing the
29763
+ * specified relationship ID.
29764
+ */
29765
+ createOleGraphicFrameXml(el, embedRelationshipId) {
29766
+ const EMU = _PptxHandlerRuntime.EMU_PER_PX;
29767
+ const offX = String(Math.round(el.x * EMU));
29768
+ const offY = String(Math.round(el.y * EMU));
29769
+ const extCx = String(Math.round(Math.max(el.width, 1) * EMU));
29770
+ const extCy = String(Math.round(Math.max(el.height, 1) * EMU));
29771
+ const oleObj = {
29772
+ "@_showAsIcon": "0",
29773
+ "@_imgW": extCx,
29774
+ "@_imgH": extCy
29775
+ };
29776
+ if (el.oleProgId) {
29777
+ oleObj["@_progId"] = el.oleProgId;
29778
+ }
29779
+ if (el.oleName) {
29780
+ oleObj["@_name"] = el.oleName;
29781
+ }
29782
+ if (el.oleClsId) {
29783
+ oleObj["@_classid"] = el.oleClsId;
29784
+ }
29785
+ if (embedRelationshipId) {
29786
+ oleObj["@_r:id"] = embedRelationshipId;
29787
+ }
29788
+ if (el.isLinked) {
29789
+ oleObj["p:link"] = {
29790
+ "@_r:id": embedRelationshipId,
29791
+ "@_updateAutomatic": "1"
29792
+ };
29793
+ } else {
29794
+ oleObj["p:embed"] = {};
29795
+ }
29796
+ oleObj["p:pic"] = {
29797
+ "p:nvPicPr": {
29798
+ "p:cNvPr": { "@_id": "0", "@_name": el.oleName || "OleObject" },
29799
+ "p:cNvPicPr": {},
29800
+ "p:nvPr": {}
29801
+ },
29802
+ "p:blipFill": {
29803
+ "a:blip": {},
29804
+ "a:stretch": { "a:fillRect": {} }
29805
+ },
29806
+ "p:spPr": {
29807
+ "a:xfrm": {
29808
+ "a:off": { "@_x": offX, "@_y": offY },
29809
+ "a:ext": { "@_cx": extCx, "@_cy": extCy }
29810
+ },
29811
+ "a:prstGeom": { "@_prst": "rect", "a:avLst": {} }
29812
+ }
29813
+ };
29814
+ return {
29815
+ "p:nvGraphicFramePr": {
29816
+ "p:cNvPr": { "@_id": "0", "@_name": el.oleName || el.fileName || "OleObject" },
29817
+ "p:cNvGraphicFramePr": {
29818
+ "a:graphicFrameLocks": { "@_noChangeAspect": "1" }
29819
+ },
29820
+ "p:nvPr": {}
29821
+ },
29822
+ "p:xfrm": {
29823
+ "a:off": { "@_x": offX, "@_y": offY },
29824
+ "a:ext": { "@_cx": extCx, "@_cy": extCy }
29825
+ },
29826
+ "a:graphic": {
29827
+ "a:graphicData": {
29828
+ "@_uri": OLE_GRAPHIC_DATA_URI,
29829
+ "p:oleObj": oleObj
29830
+ }
29831
+ }
29832
+ };
29833
+ }
29834
+ /**
29835
+ * Refresh editable typed-field attributes on a loaded OLE graphicFrame's
29836
+ * raw XML. Only attributes that round-trip through the typed model
29837
+ * (`progId`, `name`, `classid`) are touched so unknown extension data
29838
+ * passes through verbatim.
29839
+ */
29840
+ applyOleTypedFieldUpdates(shape, el) {
29841
+ const oleObj = shape["a:graphic"]?.["a:graphicData"]?.["p:oleObj"];
29842
+ if (!oleObj) {
29843
+ return;
29844
+ }
29845
+ if (el.oleProgId) {
29846
+ oleObj["@_progId"] = el.oleProgId;
29847
+ }
29848
+ if (el.oleName !== void 0) {
29849
+ if (el.oleName.length > 0) {
29850
+ oleObj["@_name"] = el.oleName;
29851
+ } else {
29852
+ delete oleObj["@_name"];
29853
+ }
29854
+ }
29855
+ if (el.oleClsId) {
29856
+ oleObj["@_classid"] = el.oleClsId;
29857
+ }
29858
+ }
29859
+ /** Look up the existing OLE binary relationship ID for this slide, if any. */
29860
+ resolveOleEmbedRelationshipId(slideRelationships, oleTarget) {
29861
+ if (!oleTarget) {
29862
+ return void 0;
29863
+ }
29864
+ const normalisedTarget = oleTarget.replace(/^ppt\//, "../").replace(/^\/+/, "");
29865
+ const lowerTarget = normalisedTarget.toLowerCase();
29866
+ for (const rel of slideRelationships) {
29867
+ const relType = String(rel?.["@_Type"] || "");
29868
+ if (relType !== OLE_OBJECT_RELATIONSHIP_TYPE) {
29869
+ continue;
29870
+ }
29871
+ const target = String(rel?.["@_Target"] || "").toLowerCase().trim();
29872
+ if (target === lowerTarget || target.endsWith(lowerTarget) || lowerTarget.endsWith(target)) {
29873
+ const relId = String(rel?.["@_Id"] || "").trim();
29874
+ if (relId.length > 0) {
29875
+ return relId;
29876
+ }
29877
+ }
29878
+ }
29879
+ const fallback = slideRelationships.find(
29880
+ (rel) => String(rel?.["@_Type"] || "") === OLE_OBJECT_RELATIONSHIP_TYPE
29881
+ );
29882
+ const fallbackId = String(fallback?.["@_Id"] || "").trim();
29883
+ return fallbackId.length > 0 ? fallbackId : void 0;
29884
+ }
29885
+ /** Constants are exposed so the element-writer mixin can reuse them. */
29886
+ static OLE_OBJECT_RELATIONSHIP_TYPE = OLE_OBJECT_RELATIONSHIP_TYPE;
29887
+ static OLE_IMAGE_RELATIONSHIP_TYPE = IMAGE_RELATIONSHIP_TYPE;
28795
29888
  /**
28796
29889
  * Build a p:sp XML object for an ink annotation element.
28797
29890
  * Each ink path becomes a separate a:path within a:pathLst,
@@ -29108,6 +30201,9 @@ var PptxHandlerRuntime16 = class extends PptxHandlerRuntime15 {
29108
30201
  buildOuterShadowXml(shapeStyle) {
29109
30202
  return this.colorStyleCodec.buildOuterShadowXml(shapeStyle);
29110
30203
  }
30204
+ buildPresetShadowXml(shapeStyle) {
30205
+ return this.colorStyleCodec.buildPresetShadowXml(shapeStyle);
30206
+ }
29111
30207
  buildInnerShadowXml(shapeStyle) {
29112
30208
  return this.colorStyleCodec.buildInnerShadowXml(shapeStyle);
29113
30209
  }
@@ -29658,6 +30754,10 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
29658
30754
  const solidFill = runProperties["a:solidFill"];
29659
30755
  if (solidFill) {
29660
30756
  style.color = this.parseColor(solidFill);
30757
+ const colorXml = extractColorChoiceXml(solidFill);
30758
+ if (colorXml) {
30759
+ style.colorXml = colorXml;
30760
+ }
29661
30761
  }
29662
30762
  this.applyHyperlinkStyle(style, runProperties, relationshipMap);
29663
30763
  const capAttr = String(runProperties["@_cap"] || "").trim().toLowerCase();
@@ -29705,12 +30805,86 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
29705
30805
  if (bmk) {
29706
30806
  style.bookmark = bmk;
29707
30807
  }
30808
+ const altLang = String(runProperties["@_altLang"] || "").trim();
30809
+ if (altLang) {
30810
+ style.altLanguage = altLang;
30811
+ }
30812
+ if (runProperties["@_smtId"] !== void 0) {
30813
+ const smtIdRaw = Number.parseInt(String(runProperties["@_smtId"]), 10);
30814
+ if (Number.isFinite(smtIdRaw)) {
30815
+ style.smartTagId = smtIdRaw;
30816
+ }
30817
+ }
30818
+ this.applyTextFontMetadata(style, latin, "latin");
30819
+ this.applyTextFontMetadata(style, eastAsian, "eastAsia");
30820
+ this.applyTextFontMetadata(style, complexScript, "complexScript");
30821
+ this.applyTextFontMetadata(style, runProperties["a:sym"], "symbol");
29708
30822
  const runEffectList = runProperties["a:effectLst"];
29709
30823
  if (runEffectList) {
29710
30824
  this.applyTextRunEffects(style, runEffectList);
29711
30825
  }
29712
30826
  return style;
29713
30827
  }
30828
+ /**
30829
+ * Copy `@panose` / `@pitchFamily` / `@charset` from a font child node
30830
+ * (`a:latin`, `a:ea`, `a:cs`, `a:sym`) onto the matching `*Font*`
30831
+ * fields of `style`.
30832
+ */
30833
+ applyTextFontMetadata(style, fontNode, kind) {
30834
+ if (!fontNode) {
30835
+ return;
30836
+ }
30837
+ const panose = String(fontNode["@_panose"] || "").trim();
30838
+ const pitchRaw = fontNode["@_pitchFamily"];
30839
+ const charsetRaw = fontNode["@_charset"];
30840
+ const pitch = pitchRaw !== void 0 && pitchRaw !== null ? Number.parseInt(String(pitchRaw), 10) : void 0;
30841
+ const charset = charsetRaw !== void 0 && charsetRaw !== null ? Number.parseInt(String(charsetRaw), 10) : void 0;
30842
+ if (kind === "latin") {
30843
+ if (panose) {
30844
+ style.latinFontPanose = panose;
30845
+ }
30846
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30847
+ style.latinFontPitchFamily = pitch;
30848
+ }
30849
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30850
+ style.latinFontCharset = charset;
30851
+ }
30852
+ return;
30853
+ }
30854
+ if (kind === "eastAsia") {
30855
+ if (panose) {
30856
+ style.eastAsiaFontPanose = panose;
30857
+ }
30858
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30859
+ style.eastAsiaFontPitchFamily = pitch;
30860
+ }
30861
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30862
+ style.eastAsiaFontCharset = charset;
30863
+ }
30864
+ return;
30865
+ }
30866
+ if (kind === "complexScript") {
30867
+ if (panose) {
30868
+ style.complexScriptFontPanose = panose;
30869
+ }
30870
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30871
+ style.complexScriptFontPitchFamily = pitch;
30872
+ }
30873
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30874
+ style.complexScriptFontCharset = charset;
30875
+ }
30876
+ return;
30877
+ }
30878
+ if (panose) {
30879
+ style.symbolFontPanose = panose;
30880
+ }
30881
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30882
+ style.symbolFontPitchFamily = pitch;
30883
+ }
30884
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30885
+ style.symbolFontCharset = charset;
30886
+ }
30887
+ }
29714
30888
  };
29715
30889
 
29716
30890
  // src/core/core/runtime/PptxHandlerRuntimeTextEditing.ts
@@ -30146,7 +31320,7 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
30146
31320
  };
30147
31321
 
30148
31322
  // src/core/core/runtime/table-cell-save-helpers.ts
30149
- function writeCellFill(tcPr, style) {
31323
+ function writeCellFill(tcPr, style, resolveColorXml) {
30150
31324
  if (style.fillMode === "gradient" && style.gradientFillStops && style.gradientFillStops.length > 0) {
30151
31325
  delete tcPr["a:solidFill"];
30152
31326
  delete tcPr["a:pattFill"];
@@ -30225,11 +31399,12 @@ function writeCellFill(tcPr, style) {
30225
31399
  } else if (style.backgroundColor) {
30226
31400
  delete tcPr["a:gradFill"];
30227
31401
  delete tcPr["a:pattFill"];
30228
- tcPr["a:solidFill"] = {
30229
- "a:srgbClr": {
30230
- "@_val": style.backgroundColor.replace("#", "")
30231
- }
30232
- };
31402
+ const resolvedOriginal = style.backgroundColorXml && resolveColorXml ? resolveColorXml(style.backgroundColorXml) : void 0;
31403
+ tcPr["a:solidFill"] = serializeColorChoice(
31404
+ style.backgroundColorXml,
31405
+ resolvedOriginal,
31406
+ style.backgroundColor
31407
+ );
30233
31408
  }
30234
31409
  }
30235
31410
  function writeDiagonalBorders(tcPr, style, emuPerPx) {
@@ -30273,14 +31448,15 @@ function writeCellTextFormatting(xmlCell, style, ensureArray6) {
30273
31448
  const paragraphs = ensureArray6(xmlCell["a:txBody"]?.["a:p"]);
30274
31449
  for (const paragraph of paragraphs) {
30275
31450
  const runs = ensureArray6(paragraph?.["a:r"]);
31451
+ const rebuiltRuns = [];
31452
+ let runsChanged = false;
30276
31453
  for (const run of runs) {
30277
31454
  if (!run) {
31455
+ rebuiltRuns.push(run);
30278
31456
  continue;
30279
31457
  }
30280
- if (!run["a:rPr"]) {
30281
- run["a:rPr"] = {};
30282
- }
30283
- const rPr = run["a:rPr"];
31458
+ const existingRPr = run["a:rPr"] ?? {};
31459
+ const rPr = { ...existingRPr };
30284
31460
  if (style.bold !== void 0) {
30285
31461
  rPr["@_b"] = style.bold ? "1" : "0";
30286
31462
  }
@@ -30300,6 +31476,18 @@ function writeCellTextFormatting(xmlCell, style, ensureArray6) {
30300
31476
  }
30301
31477
  };
30302
31478
  }
31479
+ const rebuilt = { "a:rPr": rPr };
31480
+ for (const key of Object.keys(run)) {
31481
+ if (key === "a:rPr") {
31482
+ continue;
31483
+ }
31484
+ rebuilt[key] = run[key];
31485
+ }
31486
+ rebuiltRuns.push(rebuilt);
31487
+ runsChanged = true;
31488
+ }
31489
+ if (runsChanged && rebuiltRuns.length > 0) {
31490
+ paragraph["a:r"] = rebuiltRuns.length === 1 ? rebuiltRuns[0] : rebuiltRuns;
30303
31491
  }
30304
31492
  }
30305
31493
  }
@@ -30321,6 +31509,9 @@ var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30321
31509
  const existingParagraphs = this.ensureArray(txBody["a:p"]);
30322
31510
  const firstRPr = this.ensureArray(existingParagraphs[0]?.["a:r"])[0]?.["a:rPr"];
30323
31511
  const firstPPr = existingParagraphs[0]?.["a:pPr"];
31512
+ const firstEndParaRPr = existingParagraphs[0]?.["a:endParaRPr"];
31513
+ const rPrForRun = firstRPr ? { ...firstRPr } : { "@_lang": "en-US", "@_dirty": "0" };
31514
+ const endParaRPr = firstEndParaRPr ? { ...firstEndParaRPr } : { "@_lang": "en-US", "@_dirty": "0" };
30324
31515
  const lines = text.split("\n");
30325
31516
  const paragraphs = lines.map((line) => {
30326
31517
  const paragraph = {};
@@ -30328,9 +31519,10 @@ var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30328
31519
  paragraph["a:pPr"] = firstPPr;
30329
31520
  }
30330
31521
  paragraph["a:r"] = {
30331
- ...firstRPr ? { "a:rPr": firstRPr } : {},
31522
+ "a:rPr": rPrForRun,
30332
31523
  "a:t": line
30333
31524
  };
31525
+ paragraph["a:endParaRPr"] = endParaRPr;
30334
31526
  return paragraph;
30335
31527
  });
30336
31528
  txBody["a:p"] = paragraphs.length === 1 ? paragraphs[0] : paragraphs;
@@ -30343,7 +31535,7 @@ var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30343
31535
  xmlCell["a:tcPr"] = {};
30344
31536
  }
30345
31537
  const tcPr = xmlCell["a:tcPr"];
30346
- writeCellFill(tcPr, style);
31538
+ writeCellFill(tcPr, style, (colorXml) => this.parseColor(colorXml));
30347
31539
  if (style.vAlign) {
30348
31540
  const vAlignMap = {
30349
31541
  top: "t",
@@ -30425,35 +31617,29 @@ var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30425
31617
  }
30426
31618
  }
30427
31619
  }
30428
- if (style.marginLeft !== void 0 || style.marginRight !== void 0 || style.marginTop !== void 0 || style.marginBottom !== void 0) {
30429
- const emuPerPx = _PptxHandlerRuntime.EMU_PER_PX;
30430
- if (!tcPr["a:tcMar"]) {
30431
- tcPr["a:tcMar"] = {};
30432
- }
30433
- const tcMar = tcPr["a:tcMar"];
30434
- if (style.marginLeft !== void 0) {
30435
- tcMar["a:marL"] = {
30436
- "@_w": String(Math.round(style.marginLeft * emuPerPx))
30437
- };
30438
- }
30439
- if (style.marginRight !== void 0) {
30440
- tcMar["a:marR"] = {
30441
- "@_w": String(Math.round(style.marginRight * emuPerPx))
30442
- };
30443
- }
30444
- if (style.marginTop !== void 0) {
30445
- tcMar["a:marT"] = {
30446
- "@_w": String(Math.round(style.marginTop * emuPerPx))
30447
- };
30448
- }
30449
- if (style.marginBottom !== void 0) {
30450
- tcMar["a:marB"] = {
30451
- "@_w": String(Math.round(style.marginBottom * emuPerPx))
30452
- };
30453
- }
31620
+ const emuPerPx = _PptxHandlerRuntime.EMU_PER_PX;
31621
+ if (style.marginLeft !== void 0) {
31622
+ tcPr["@_marL"] = String(Math.round(style.marginLeft * emuPerPx));
31623
+ }
31624
+ if (style.marginRight !== void 0) {
31625
+ tcPr["@_marR"] = String(Math.round(style.marginRight * emuPerPx));
31626
+ }
31627
+ if (style.marginTop !== void 0) {
31628
+ tcPr["@_marT"] = String(Math.round(style.marginTop * emuPerPx));
30454
31629
  }
31630
+ if (style.marginBottom !== void 0) {
31631
+ tcPr["@_marB"] = String(Math.round(style.marginBottom * emuPerPx));
31632
+ }
31633
+ delete tcPr["a:tcMar"];
30455
31634
  writeDiagonalBorders(tcPr, style, _PptxHandlerRuntime.EMU_PER_PX);
30456
31635
  writeCellTextFormatting(xmlCell, style, this.ensureArray.bind(this));
31636
+ const reordered = reorderObjectKeys(tcPr, TC_PR_BORDERS_ORDER);
31637
+ for (const key of Object.keys(tcPr)) {
31638
+ delete tcPr[key];
31639
+ }
31640
+ for (const key of Object.keys(reordered)) {
31641
+ tcPr[key] = reordered[key];
31642
+ }
30457
31643
  }
30458
31644
  };
30459
31645
 
@@ -30480,14 +31666,27 @@ function serializeCellMergeAttributes(xmlCell, cell) {
30480
31666
  delete xmlCell["@_vMerge"];
30481
31667
  }
30482
31668
  }
31669
+ var DEFAULT_POWERPOINT_TABLE_STYLE_ID = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";
30483
31670
  function serializeTablePropertyFlags(tbl, tableData) {
30484
31671
  const tblPr = tbl["a:tblPr"] ?? {};
30485
- tblPr["@_bandRow"] = tableData.bandedRows ? "1" : "0";
30486
- tblPr["@_bandCol"] = tableData.bandedColumns ? "1" : "0";
30487
- tblPr["@_firstRow"] = tableData.firstRowHeader ? "1" : "0";
30488
- tblPr["@_lastRow"] = tableData.lastRow ? "1" : "0";
30489
- tblPr["@_firstCol"] = tableData.firstCol ? "1" : "0";
30490
- tblPr["@_lastCol"] = tableData.lastCol ? "1" : "0";
31672
+ const setOrDelete = (key, truthy) => {
31673
+ if (truthy) {
31674
+ tblPr[key] = "1";
31675
+ } else {
31676
+ delete tblPr[key];
31677
+ }
31678
+ };
31679
+ setOrDelete("@_bandRow", tableData.bandedRows);
31680
+ setOrDelete("@_bandCol", tableData.bandedColumns);
31681
+ setOrDelete("@_firstRow", tableData.firstRowHeader);
31682
+ setOrDelete("@_lastRow", tableData.lastRow);
31683
+ setOrDelete("@_firstCol", tableData.firstCol);
31684
+ setOrDelete("@_lastCol", tableData.lastCol);
31685
+ if (tableData.tableStyleId) {
31686
+ tblPr["a:tableStyleId"] = tableData.tableStyleId;
31687
+ } else if (!tblPr["a:tableStyleId"]) {
31688
+ tblPr["a:tableStyleId"] = DEFAULT_POWERPOINT_TABLE_STYLE_ID;
31689
+ }
30491
31690
  tbl["a:tblPr"] = tblPr;
30492
31691
  }
30493
31692
  function replaceFirstTextValueInTree(node, localName, newValue, getXmlLocalName) {
@@ -30532,7 +31731,9 @@ function createDefaultXmlCell() {
30532
31731
  "a:bodyPr": {},
30533
31732
  "a:lstStyle": {},
30534
31733
  "a:p": {
30535
- "a:endParaRPr": { "@_lang": "en-US" }
31734
+ // Match PowerPoint's "Insert Table" default: every paragraph-end
31735
+ // run carries `lang="en-US" dirty="0"`.
31736
+ "a:endParaRPr": { "@_lang": "en-US", "@_dirty": "0" }
30536
31737
  }
30537
31738
  },
30538
31739
  "a:tcPr": {}
@@ -30540,6 +31741,54 @@ function createDefaultXmlCell() {
30540
31741
  }
30541
31742
 
30542
31743
  // src/core/core/runtime/table-xml-rebuild.ts
31744
+ var GRID_COL_ID_EXT_URI = "{9D8B030D-6E8A-4147-A177-3AD203B41FA5}";
31745
+ var A16_NAMESPACE = "http://schemas.microsoft.com/office/drawing/2014/main";
31746
+ function ensureA16NamespaceOnSlideRoot(slideRoot) {
31747
+ if (!slideRoot["@_xmlns:a16"]) {
31748
+ slideRoot["@_xmlns:a16"] = A16_NAMESPACE;
31749
+ }
31750
+ if (!slideRoot["@_xmlns:mc"]) {
31751
+ slideRoot["@_xmlns:mc"] = "http://schemas.openxmlformats.org/markup-compatibility/2006";
31752
+ }
31753
+ const existingIgnorable = String(slideRoot["@_mc:Ignorable"] || "").trim();
31754
+ if (existingIgnorable.length === 0) {
31755
+ slideRoot["@_mc:Ignorable"] = "a16";
31756
+ return;
31757
+ }
31758
+ const tokens = existingIgnorable.split(/\s+/).filter((token) => token.length > 0);
31759
+ if (!tokens.includes("a16")) {
31760
+ tokens.push("a16");
31761
+ slideRoot["@_mc:Ignorable"] = tokens.join(" ");
31762
+ }
31763
+ }
31764
+ function slideContainsA16Element(node) {
31765
+ if (node === null || node === void 0) {
31766
+ return false;
31767
+ }
31768
+ if (Array.isArray(node)) {
31769
+ for (const entry of node) {
31770
+ if (slideContainsA16Element(entry)) {
31771
+ return true;
31772
+ }
31773
+ }
31774
+ return false;
31775
+ }
31776
+ if (typeof node !== "object") {
31777
+ return false;
31778
+ }
31779
+ for (const [key, value] of Object.entries(node)) {
31780
+ if (key.startsWith("a16:")) {
31781
+ return true;
31782
+ }
31783
+ if (slideContainsA16Element(value)) {
31784
+ return true;
31785
+ }
31786
+ }
31787
+ return false;
31788
+ }
31789
+ function randomColumnId() {
31790
+ return String(Math.floor(Math.random() * 4294967295));
31791
+ }
30543
31792
  function rebuildTableXmlFromData(tbl, tableData, emuPerPx, ensureArrayFn) {
30544
31793
  const existingXmlRows = ensureArrayFn(tbl["a:tr"]);
30545
31794
  const existingGridCols = ensureArrayFn(
@@ -30548,8 +31797,33 @@ function rebuildTableXmlFromData(tbl, tableData, emuPerPx, ensureArrayFn) {
30548
31797
  const totalWidthEmu = existingGridCols.reduce((sum, col) => {
30549
31798
  return sum + (parseInt(String(col?.["@_w"] || "0"), 10) || 0);
30550
31799
  }, 0) || 9144e3;
30551
- const newGridCols = tableData.columnWidths.map((w) => ({
30552
- "@_w": String(Math.round(w * totalWidthEmu))
31800
+ const existingColIds = existingGridCols.map((col) => {
31801
+ const extList = col?.["a:extLst"];
31802
+ const exts = Array.isArray(extList?.["a:ext"]) ? extList["a:ext"] : extList?.["a:ext"] ? [extList["a:ext"]] : [];
31803
+ for (const ext of exts) {
31804
+ if (ext?.["@_uri"] === GRID_COL_ID_EXT_URI) {
31805
+ const colId = ext["a16:colId"];
31806
+ const val = colId?.["@_val"];
31807
+ if (typeof val === "string" && val.length > 0) {
31808
+ return val;
31809
+ }
31810
+ }
31811
+ }
31812
+ return "";
31813
+ });
31814
+ const newGridCols = tableData.columnWidths.map((w, i) => ({
31815
+ "@_w": String(Math.round(w * totalWidthEmu)),
31816
+ "a:extLst": {
31817
+ "a:ext": {
31818
+ "@_uri": GRID_COL_ID_EXT_URI,
31819
+ // `xmlns:a16` is declared on the slide root by
31820
+ // `ensureA16NamespaceOnSlideRoot`; emitting it here too is
31821
+ // schema-redundant and PowerPoint flags it.
31822
+ "a16:colId": {
31823
+ "@_val": existingColIds[i] || randomColumnId()
31824
+ }
31825
+ }
31826
+ }
30553
31827
  }));
30554
31828
  if (!tbl["a:tblGrid"]) {
30555
31829
  tbl["a:tblGrid"] = {};
@@ -30904,26 +32178,64 @@ var PptxHandlerRuntime23 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30904
32178
  continue;
30905
32179
  }
30906
32180
  const scalingNode = this.xmlLookupService.getChildByLocalName(axisNode, "scaling");
30907
- if (!scalingNode) {
30908
- continue;
32181
+ if (scalingNode) {
32182
+ if (matchingAxis.logBase !== void 0 && matchingAxis.logBase > 0) {
32183
+ const logBaseKey = Object.keys(scalingNode).find(
32184
+ (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32185
+ );
32186
+ if (logBaseKey) {
32187
+ scalingNode[logBaseKey]["@_val"] = String(matchingAxis.logBase);
32188
+ } else {
32189
+ scalingNode["c:logBase"] = {
32190
+ "@_val": String(matchingAxis.logBase)
32191
+ };
32192
+ }
32193
+ } else if (matchingAxis.logScale === false) {
32194
+ const logBaseKey = Object.keys(scalingNode).find(
32195
+ (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32196
+ );
32197
+ if (logBaseKey) {
32198
+ delete scalingNode[logBaseKey];
32199
+ }
32200
+ }
32201
+ this.upsertChartAxisChild(
32202
+ scalingNode,
32203
+ "min",
32204
+ matchingAxis.min !== void 0 ? String(matchingAxis.min) : void 0
32205
+ );
32206
+ this.upsertChartAxisChild(
32207
+ scalingNode,
32208
+ "max",
32209
+ matchingAxis.max !== void 0 ? String(matchingAxis.max) : void 0
32210
+ );
30909
32211
  }
30910
- if (matchingAxis.logBase !== void 0 && matchingAxis.logBase > 0) {
30911
- const logBaseKey = Object.keys(scalingNode).find(
30912
- (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32212
+ if (matchingAxis.numFmt) {
32213
+ const numFmtKey = Object.keys(axisNode).find(
32214
+ (k) => this.compatibilityService.getXmlLocalName(k) === "numFmt"
30913
32215
  );
30914
- if (logBaseKey) {
30915
- scalingNode[logBaseKey]["@_val"] = String(matchingAxis.logBase);
32216
+ const numFmtAttrs = {
32217
+ "@_formatCode": matchingAxis.numFmt.formatCode,
32218
+ "@_sourceLinked": matchingAxis.numFmt.sourceLinked ? "1" : "0"
32219
+ };
32220
+ if (numFmtKey) {
32221
+ axisNode[numFmtKey] = numFmtAttrs;
30916
32222
  } else {
30917
- scalingNode["c:logBase"] = {
30918
- "@_val": String(matchingAxis.logBase)
30919
- };
32223
+ axisNode["c:numFmt"] = numFmtAttrs;
30920
32224
  }
30921
- } else if (matchingAxis.logScale === false) {
30922
- const logBaseKey = Object.keys(scalingNode).find(
30923
- (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32225
+ }
32226
+ this.upsertChartAxisChild(
32227
+ axisNode,
32228
+ "majorUnit",
32229
+ matchingAxis.majorUnit !== void 0 ? String(matchingAxis.majorUnit) : void 0
32230
+ );
32231
+ if (matchingAxis.tickLblPos !== void 0) {
32232
+ const tickLblKey = Object.keys(axisNode).find(
32233
+ (k) => this.compatibilityService.getXmlLocalName(k) === "tickLblPos"
30924
32234
  );
30925
- if (logBaseKey) {
30926
- delete scalingNode[logBaseKey];
32235
+ if (tickLblKey) {
32236
+ axisNode[tickLblKey]["@_val"] = matchingAxis.tickLblPos;
32237
+ } else {
32238
+ axisNode["c:tickLblPos"] = { "@_val": matchingAxis.tickLblPos };
30927
32239
  }
30928
32240
  }
30929
32241
  }
@@ -30936,6 +32248,18 @@ var PptxHandlerRuntime23 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30936
32248
  }
30937
32249
  this.pendingChartUpdates = void 0;
30938
32250
  }
32251
+ /**
32252
+ * Upsert a `c:<localName>` child with `@_val` on an axis or scaling node.
32253
+ * When `value` is undefined, removes any existing child of that local name.
32254
+ */
32255
+ upsertChartAxisChild(parent, localName, value) {
32256
+ upsertChartAxisChild(
32257
+ parent,
32258
+ localName,
32259
+ value,
32260
+ (key) => this.compatibilityService.getXmlLocalName(key)
32261
+ );
32262
+ }
30939
32263
  /**
30940
32264
  * Update the cached point values in a chart reference node
30941
32265
  * (numRef/strRef or numLit/strLit).
@@ -32215,17 +33539,13 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32215
33539
  delete spPr["a:noFill"];
32216
33540
  delete spPr["a:gradFill"];
32217
33541
  delete spPr["a:blipFill"];
32218
- const solidFill = {
32219
- "a:srgbClr": {
32220
- "@_val": fillColor.replace("#", "")
32221
- }
32222
- };
32223
- if (typeof shapeStyle.fillOpacity === "number" && shapeStyle.fillOpacity >= 0 && shapeStyle.fillOpacity < 1) {
32224
- solidFill["a:srgbClr"]["a:alpha"] = {
32225
- "@_val": String(Math.round(this.clampUnitInterval(shapeStyle.fillOpacity) * 1e5))
32226
- };
32227
- }
32228
- spPr["a:solidFill"] = solidFill;
33542
+ const resolvedOriginal = shapeStyle.fillColorXml ? this.parseColor(shapeStyle.fillColorXml) : void 0;
33543
+ spPr["a:solidFill"] = serializeColorChoice(
33544
+ shapeStyle.fillColorXml,
33545
+ resolvedOriginal,
33546
+ fillColor,
33547
+ shapeStyle.fillOpacity
33548
+ );
32229
33549
  }
32230
33550
  }
32231
33551
  if (shapeStyle.strokeColor !== void 0) {
@@ -32240,17 +33560,13 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32240
33560
  delete lineNode["a:solidFill"];
32241
33561
  } else {
32242
33562
  delete lineNode["a:noFill"];
32243
- const lineFill = {
32244
- "a:srgbClr": {
32245
- "@_val": shapeStyle.strokeColor.replace("#", "")
32246
- }
32247
- };
32248
- if (typeof shapeStyle.strokeOpacity === "number" && shapeStyle.strokeOpacity >= 0 && shapeStyle.strokeOpacity < 1) {
32249
- lineFill["a:srgbClr"]["a:alpha"] = {
32250
- "@_val": String(Math.round(this.clampUnitInterval(shapeStyle.strokeOpacity) * 1e5))
32251
- };
32252
- }
32253
- lineNode["a:solidFill"] = lineFill;
33563
+ const resolvedStrokeOriginal = shapeStyle.strokeColorXml ? this.parseColor(shapeStyle.strokeColorXml) : void 0;
33564
+ lineNode["a:solidFill"] = serializeColorChoice(
33565
+ shapeStyle.strokeColorXml,
33566
+ resolvedStrokeOriginal,
33567
+ shapeStyle.strokeColor,
33568
+ shapeStyle.strokeOpacity
33569
+ );
32254
33570
  }
32255
33571
  }
32256
33572
  if (shapeStyle.strokeDash !== void 0) {
@@ -32331,7 +33647,11 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32331
33647
  } else if (shapeStyle.lineJoin === "bevel") {
32332
33648
  lineNode["a:bevel"] = {};
32333
33649
  } else if (shapeStyle.lineJoin === "miter") {
32334
- lineNode["a:miter"] = { "@_lim": "800000" };
33650
+ const miterNode = {};
33651
+ if (typeof shapeStyle.miterLimit === "number" && Number.isFinite(shapeStyle.miterLimit) && shapeStyle.miterLimit !== 8e5) {
33652
+ miterNode["@_lim"] = String(Math.round(shapeStyle.miterLimit));
33653
+ }
33654
+ lineNode["a:miter"] = miterNode;
32335
33655
  }
32336
33656
  }
32337
33657
  if (shapeStyle.lineCap !== void 0) {
@@ -32351,6 +33671,82 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32351
33671
  spPr["a:ln"]["a:effectLst"] = lineEffectListXml;
32352
33672
  }
32353
33673
  }
33674
+ /**
33675
+ * Serialize the shape's `<p:style>` block (CT_ShapeStyle §20.1.2.2.36)
33676
+ * from the persisted ref indices/colour XML. Emits children in spec
33677
+ * order: `lnRef → fillRef → effectRef → fontRef`.
33678
+ *
33679
+ * When the original shape XML already contained a `<p:style>` we mutate
33680
+ * that node in place so any unmodelled attributes/children are preserved.
33681
+ * When it didn't, we create one. When the shape no longer has any ref
33682
+ * data we leave the existing `<p:style>` (if any) untouched — silently
33683
+ * dropping it would break round-tripping.
33684
+ *
33685
+ * Phase 2 Stream B / C-H2.
33686
+ */
33687
+ applyShapeStyleRefs(shape, shapeStyle) {
33688
+ const hasAnyRef = shapeStyle.lnRefIdx !== void 0 || shapeStyle.fillRefIdx !== void 0 || shapeStyle.effectRefIdx !== void 0 || shapeStyle.fontRefIdx !== void 0;
33689
+ if (!hasAnyRef) {
33690
+ return;
33691
+ }
33692
+ const existing = shape["p:style"];
33693
+ const styleNode = existing ?? {};
33694
+ if (shapeStyle.lnRefIdx !== void 0) {
33695
+ const lnRef = styleNode["a:lnRef"] ?? {};
33696
+ lnRef["@_idx"] = String(shapeStyle.lnRefIdx);
33697
+ this.replaceRefColorChoice(lnRef, shapeStyle.lnRefColorXml);
33698
+ styleNode["a:lnRef"] = lnRef;
33699
+ }
33700
+ if (shapeStyle.fillRefIdx !== void 0) {
33701
+ const fillRef = styleNode["a:fillRef"] ?? {};
33702
+ fillRef["@_idx"] = String(shapeStyle.fillRefIdx);
33703
+ this.replaceRefColorChoice(fillRef, shapeStyle.fillRefColorXml);
33704
+ styleNode["a:fillRef"] = fillRef;
33705
+ }
33706
+ if (shapeStyle.effectRefIdx !== void 0) {
33707
+ const effectRef = styleNode["a:effectRef"] ?? {};
33708
+ effectRef["@_idx"] = String(shapeStyle.effectRefIdx);
33709
+ this.replaceRefColorChoice(effectRef, shapeStyle.effectRefColorXml);
33710
+ styleNode["a:effectRef"] = effectRef;
33711
+ }
33712
+ if (shapeStyle.fontRefIdx !== void 0) {
33713
+ const fontRef = styleNode["a:fontRef"] ?? {};
33714
+ fontRef["@_idx"] = shapeStyle.fontRefIdx;
33715
+ this.replaceRefColorChoice(fontRef, shapeStyle.fontRefColorXml);
33716
+ styleNode["a:fontRef"] = fontRef;
33717
+ }
33718
+ const reordered = reorderObjectKeys(styleNode, SHAPE_STYLE_ORDER);
33719
+ for (const key of Object.keys(styleNode)) {
33720
+ delete styleNode[key];
33721
+ }
33722
+ for (const key of Object.keys(reordered)) {
33723
+ styleNode[key] = reordered[key];
33724
+ }
33725
+ shape["p:style"] = styleNode;
33726
+ }
33727
+ /**
33728
+ * Replace any existing colour-choice child on a style-matrix-reference
33729
+ * element with the given preserved XML, or strip all colour children
33730
+ * when the override is undefined.
33731
+ */
33732
+ replaceRefColorChoice(refNode, colorXml) {
33733
+ for (const key of [
33734
+ "a:scrgbClr",
33735
+ "a:srgbClr",
33736
+ "a:hslClr",
33737
+ "a:sysClr",
33738
+ "a:schemeClr",
33739
+ "a:prstClr"
33740
+ ]) {
33741
+ delete refNode[key];
33742
+ }
33743
+ if (!colorXml) {
33744
+ return;
33745
+ }
33746
+ for (const [key, value] of Object.entries(colorXml)) {
33747
+ refNode[key] = value;
33748
+ }
33749
+ }
32354
33750
  };
32355
33751
 
32356
33752
  // src/core/core/runtime/PptxHandlerRuntimeSaveEffectsWriter.ts
@@ -32360,17 +33756,22 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
32360
33756
  * effectDag, 3D scene, and 3D shape properties to the given spPr XML object.
32361
33757
  */
32362
33758
  applyEffectsAndThreeD(spPr, shapeStyle) {
32363
- const outerShadowXml = this.buildOuterShadowXml(shapeStyle);
33759
+ const presetShadowXml = shapeStyle.presetShadowName ? this.buildPresetShadowXml(shapeStyle) : void 0;
33760
+ const outerShadowXml = presetShadowXml ? void 0 : this.buildOuterShadowXml(shapeStyle);
32364
33761
  const innerShadowXml = this.buildInnerShadowXml(shapeStyle);
32365
33762
  const glowXml = this.buildGlowXml(shapeStyle);
32366
33763
  const softEdgeXml = this.buildSoftEdgeXml(shapeStyle);
32367
33764
  const reflectionXml = this.buildReflectionXml(shapeStyle);
32368
33765
  const blurXml = this.buildBlurXml(shapeStyle);
32369
- const hasAnyEffect = outerShadowXml || innerShadowXml || glowXml || softEdgeXml || reflectionXml || blurXml;
33766
+ const hasAnyEffect = outerShadowXml || presetShadowXml || innerShadowXml || glowXml || softEdgeXml || reflectionXml || blurXml;
32370
33767
  if (hasAnyEffect) {
32371
33768
  const effectList = spPr["a:effectLst"] || {};
32372
- if (outerShadowXml) {
33769
+ if (presetShadowXml) {
33770
+ effectList["a:prstShdw"] = presetShadowXml;
33771
+ delete effectList["a:outerShdw"];
33772
+ } else if (outerShadowXml) {
32373
33773
  effectList["a:outerShdw"] = outerShadowXml;
33774
+ delete effectList["a:prstShdw"];
32374
33775
  }
32375
33776
  if (innerShadowXml) {
32376
33777
  effectList["a:innerShdw"] = innerShadowXml;
@@ -32387,12 +33788,13 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
32387
33788
  if (blurXml) {
32388
33789
  effectList["a:blur"] = blurXml;
32389
33790
  }
32390
- spPr["a:effectLst"] = effectList;
33791
+ spPr["a:effectLst"] = reorderObjectKeys(effectList, EFFECT_LST_ORDER);
32391
33792
  } else {
32392
33793
  const effectList = spPr["a:effectLst"];
32393
33794
  if (effectList) {
32394
- if (shapeStyle.shadowColor !== void 0 && !outerShadowXml) {
33795
+ if (shapeStyle.shadowColor !== void 0 && !outerShadowXml && !presetShadowXml) {
32395
33796
  delete effectList["a:outerShdw"];
33797
+ delete effectList["a:prstShdw"];
32396
33798
  }
32397
33799
  if (shapeStyle.innerShadowColor !== void 0 && !innerShadowXml) {
32398
33800
  delete effectList["a:innerShdw"];
@@ -32411,6 +33813,8 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
32411
33813
  }
32412
33814
  if (Object.keys(effectList).length === 0) {
32413
33815
  delete spPr["a:effectLst"];
33816
+ } else {
33817
+ spPr["a:effectLst"] = reorderObjectKeys(effectList, EFFECT_LST_ORDER);
32414
33818
  }
32415
33819
  }
32416
33820
  }
@@ -32571,7 +33975,8 @@ var PptxHandlerRuntime30 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32571
33975
  );
32572
33976
  }
32573
33977
  if (el.textStyle?.hOverflow) {
32574
- bodyPr["@_hOverflow"] = el.textStyle.hOverflow;
33978
+ bodyPr["@_horzOverflow"] = el.textStyle.hOverflow;
33979
+ delete bodyPr["@_hOverflow"];
32575
33980
  }
32576
33981
  if (el.textStyle?.vertOverflow) {
32577
33982
  bodyPr["@_vertOverflow"] = el.textStyle.vertOverflow;
@@ -32802,7 +34207,10 @@ var PptxHandlerRuntime31 = class extends PptxHandlerRuntime30 {
32802
34207
  const elWithPaths = el;
32803
34208
  if (elWithPaths.customGeometryPaths && elWithPaths.customGeometryPaths.length > 0) {
32804
34209
  delete spPr["a:prstGeom"];
32805
- spPr["a:custGeom"] = customGeometryPathsToXml(elWithPaths.customGeometryPaths);
34210
+ spPr["a:custGeom"] = customGeometryPathsToXml(
34211
+ elWithPaths.customGeometryPaths,
34212
+ elWithPaths.customGeometryRawData
34213
+ );
32806
34214
  } else if (spPr["a:prstGeom"]) {
32807
34215
  const presetGeometry = el.type === "connector" ? this.normalizePresetGeometry(el.shapeType || "straightConnector1") : this.normalizePresetGeometry(el.shapeType);
32808
34216
  const prstGeom = spPr["a:prstGeom"];
@@ -32927,6 +34335,42 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
32927
34335
  isGraphicFrameShape(shape) {
32928
34336
  return Boolean(shape["p:nvGraphicFramePr"] || shape["a:graphic"] && shape["p:xfrm"]);
32929
34337
  }
34338
+ /**
34339
+ * Reorder children of `p:spPr` to match CT_ShapeProperties (§20.1.2.2.35).
34340
+ * Also reorders any nested `a:blipFill` per CT_BlipFillProperties.
34341
+ * fast-xml-parser preserves insertion order; PowerPoint validates against
34342
+ * the schema's required order, so save-side mutations must be re-sorted.
34343
+ */
34344
+ finalizeSpPrSchemaOrder(shape) {
34345
+ const spPr = shape["p:spPr"];
34346
+ if (!spPr) {
34347
+ return;
34348
+ }
34349
+ const blipFill = spPr["a:blipFill"];
34350
+ if (blipFill) {
34351
+ this.reorderInPlace(blipFill, BLIP_FILL_ORDER);
34352
+ }
34353
+ this.reorderInPlace(spPr, SP_PR_ORDER);
34354
+ }
34355
+ /**
34356
+ * Reorder children of the picture-level `p:blipFill` (CT_BlipFillProperties).
34357
+ * Picture elements carry their blip data on the `p:pic` root, not under spPr.
34358
+ */
34359
+ finalizePictureBlipFillOrder(shape) {
34360
+ const pBlipFill = shape["p:blipFill"];
34361
+ if (pBlipFill) {
34362
+ this.reorderInPlace(pBlipFill, BLIP_FILL_ORDER);
34363
+ }
34364
+ }
34365
+ reorderInPlace(target, schemaOrder) {
34366
+ const reordered = reorderObjectKeys(target, schemaOrder);
34367
+ for (const key of Object.keys(target)) {
34368
+ delete target[key];
34369
+ }
34370
+ for (const key of Object.keys(reordered)) {
34371
+ target[key] = reordered[key];
34372
+ }
34373
+ }
32930
34374
  /** Whether an element ID indicates a template (layout/master) element. */
32931
34375
  isTemplateElementId(elementId) {
32932
34376
  return elementId.startsWith("layout-") || elementId.startsWith("master-");
@@ -32950,14 +34394,50 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
32950
34394
  }
32951
34395
  return;
32952
34396
  }
34397
+ if (el.type === "contentPart") {
34398
+ if (shape) {
34399
+ this.elementTransformUpdater.applyTransform(shape, el, _PptxHandlerRuntime.EMU_PER_PX);
34400
+ collectors.contentParts.push(shape);
34401
+ } else {
34402
+ this.compatibilityService.reportWarning({
34403
+ code: "SAVE_ELEMENT_SKIPPED",
34404
+ message: `Content part '${el.id}' has no rawXml and was skipped during save.`,
34405
+ scope: "save",
34406
+ slideId: ctx.slide.id,
34407
+ elementId: el.id
34408
+ });
34409
+ }
34410
+ return;
34411
+ }
32953
34412
  if (!shape && (el.type === "text" || el.type === "shape")) {
32954
34413
  shape = this.createElementXml(el);
32955
34414
  }
32956
34415
  if (!shape && el.type === "connector") {
32957
34416
  shape = this.createConnectorXml(el);
32958
34417
  }
32959
- if (!shape && el.type === "ink") {
32960
- shape = this.createInkShapeXml(el);
34418
+ if (el.type === "ink") {
34419
+ if (!shape) {
34420
+ shape = this.createInkShapeXml(el);
34421
+ this.compatibilityService.reportWarning({
34422
+ code: "SAVE_INK_ENCODED_AS_CUSTGEOM",
34423
+ message: "SDK-created ink element serialized as custGeom shape; pressure/tool metadata not represented in OOXML aink format.",
34424
+ scope: "save",
34425
+ slideId: ctx.slide.id,
34426
+ elementId: el.id
34427
+ });
34428
+ }
34429
+ }
34430
+ if (!shape && el.type === "table") {
34431
+ shape = this.createTableGraphicFrameXml(el);
34432
+ }
34433
+ if (el.type === "ole") {
34434
+ const oleEl = el;
34435
+ if (shape) {
34436
+ this.applyOleTypedFieldUpdates(shape, oleEl);
34437
+ } else {
34438
+ const embedRid = this.resolveOleEmbedRelationshipId(ctx.slideRelationships, oleEl.oleTarget) || ctx.slideRelationshipRegistry.nextRelationshipId();
34439
+ shape = this.createOleGraphicFrameXml(oleEl, embedRid);
34440
+ }
32961
34441
  }
32962
34442
  if (!shape) {
32963
34443
  this.compatibilityService.reportWarning({
@@ -32971,11 +34451,14 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
32971
34451
  }
32972
34452
  this.elementTransformUpdater.applyTransform(shape, el, _PptxHandlerRuntime.EMU_PER_PX);
32973
34453
  this.applyImageProperties(shape, el);
34454
+ this.finalizePictureBlipFillOrder(shape);
32974
34455
  this.applyGeometryUpdate(shape, el);
32975
34456
  if (hasShapeProperties(el) && el.shapeStyle && shape["p:spPr"]) {
32976
34457
  const spPr = shape["p:spPr"];
32977
34458
  this.applyFillAndStroke(spPr, el.shapeStyle);
32978
34459
  this.applyEffectsAndThreeD(spPr, el.shapeStyle);
34460
+ this.finalizeSpPrSchemaOrder(shape);
34461
+ this.applyShapeStyleRefs(shape, el.shapeStyle);
32979
34462
  }
32980
34463
  if (hasTextProperties(el)) {
32981
34464
  this.applyTextBodyContent(
@@ -33133,7 +34616,8 @@ var PptxHandlerRuntime33 = class extends PptxHandlerRuntime32 {
33133
34616
  connectors: [],
33134
34617
  graphicFrames: [],
33135
34618
  groups: [],
33136
- model3ds: []
34619
+ model3ds: [],
34620
+ contentParts: []
33137
34621
  };
33138
34622
  const ctx = {
33139
34623
  slide,
@@ -33165,6 +34649,12 @@ var PptxHandlerRuntime33 = class extends PptxHandlerRuntime32 {
33165
34649
  } else {
33166
34650
  delete spTree["p16:model3D"];
33167
34651
  }
34652
+ if (collectors.contentParts.length > 0) {
34653
+ spTree["p:contentPart"] = collectors.contentParts;
34654
+ } else {
34655
+ delete spTree["p:contentPart"];
34656
+ }
34657
+ this.reapplyAlternateContentEnvelopes(spTree, collectors);
33168
34658
  const reassigned = shapeIdValidator.validateAndDeduplicateIds(
33169
34659
  spTree,
33170
34660
  (v) => this.ensureArray(v)
@@ -33182,12 +34672,426 @@ var PptxHandlerRuntime33 = class extends PptxHandlerRuntime32 {
33182
34672
  this.zip.file(slideRelsPath, this.builder.build(slideRelsData));
33183
34673
  this.applySlideDrawingGuides(slideNode, slide);
33184
34674
  this.deduplicateExtensionLists(xmlObj);
34675
+ if (slideContainsA16Element(slideNode)) {
34676
+ ensureA16NamespaceOnSlideRoot(slideNode);
34677
+ }
33185
34678
  this.zip.file(slide.id, this.builder.build(xmlObj));
33186
34679
  }
34680
+ /**
34681
+ * Re-wrap selected children with their original `<mc:AlternateContent>`
34682
+ * envelope (CC-4).
34683
+ *
34684
+ * Parsing merged the selected branch (Choice when supported, otherwise
34685
+ * Fallback) into the spTree's tag arrays. Without re-wrapping, dirty
34686
+ * save would emit flat `<p:sp>`/`<p:pic>` etc. and drop the
34687
+ * `<mc:Fallback>` branch — losing legacy rendering for files originally
34688
+ * authored with newer-namespace features.
34689
+ *
34690
+ * Strategy: for each XmlObject in `collectors.*` that traces back to a
34691
+ * known AC block, group by block and:
34692
+ * 1. Remove the node from its flat collector / spTree array.
34693
+ * 2. Clone the original AC envelope.
34694
+ * 3. Replace the selected branch's `<{tag}>` children with the
34695
+ * live (possibly edited) nodes from the collectors.
34696
+ * 4. Leave the unselected branch verbatim.
34697
+ *
34698
+ * Final envelopes are appended to `spTree['mc:AlternateContent']`.
34699
+ */
34700
+ reapplyAlternateContentEnvelopes(spTree, collectors) {
34701
+ const TAG_TO_COLLECTOR = {
34702
+ "p:sp": collectors.shapes,
34703
+ "p:pic": collectors.pics,
34704
+ "p:cxnSp": collectors.connectors,
34705
+ "p:graphicFrame": collectors.graphicFrames,
34706
+ "p:grpSp": collectors.groups,
34707
+ "p:contentPart": collectors.contentParts,
34708
+ // `model3d` does not flow through SHAPE_TREE_ELEMENT_TAGS, but the
34709
+ // AC pathway in OpenXML decks frequently uses Choice = p16:model3D
34710
+ // + Fallback = p:pic, so map it for completeness.
34711
+ "p16:model3D": collectors.model3ds
34712
+ };
34713
+ const blockGroups = /* @__PURE__ */ new Map();
34714
+ for (const tag of Object.keys(TAG_TO_COLLECTOR)) {
34715
+ const collector = TAG_TO_COLLECTOR[tag];
34716
+ if (!collector) {
34717
+ continue;
34718
+ }
34719
+ for (const node of collector) {
34720
+ const block = this.alternateContentBlockByRawXml.get(node);
34721
+ if (!block) {
34722
+ continue;
34723
+ }
34724
+ let entries = blockGroups.get(block);
34725
+ if (!entries) {
34726
+ entries = [];
34727
+ blockGroups.set(block, entries);
34728
+ }
34729
+ entries.push({ tag, node, collector });
34730
+ }
34731
+ }
34732
+ if (blockGroups.size === 0) {
34733
+ return;
34734
+ }
34735
+ const envelopes = [];
34736
+ for (const [block, entries] of blockGroups) {
34737
+ for (const entry of entries) {
34738
+ const idx = entry.collector.indexOf(entry.node);
34739
+ if (idx !== -1) {
34740
+ entry.collector.splice(idx, 1);
34741
+ }
34742
+ }
34743
+ const clonedAc = { ...block.rawAc };
34744
+ const liveByTag = /* @__PURE__ */ new Map();
34745
+ for (const entry of entries) {
34746
+ let arr = liveByTag.get(entry.tag);
34747
+ if (!arr) {
34748
+ arr = [];
34749
+ liveByTag.set(entry.tag, arr);
34750
+ }
34751
+ arr.push(entry.node);
34752
+ }
34753
+ if (block.selectedBranch === "choice") {
34754
+ const choices = this.ensureArray(clonedAc["mc:Choice"]);
34755
+ const targetIdx = block.choiceIndex ?? 0;
34756
+ const original = choices[targetIdx];
34757
+ if (original) {
34758
+ const rebuilt = { ...original };
34759
+ for (const tag of SHAPE_TREE_ELEMENT_TAGS) {
34760
+ delete rebuilt[tag];
34761
+ }
34762
+ for (const [tag, nodes] of liveByTag) {
34763
+ rebuilt[tag] = nodes.length === 1 ? nodes[0] : nodes;
34764
+ }
34765
+ choices[targetIdx] = rebuilt;
34766
+ clonedAc["mc:Choice"] = choices.length === 1 ? choices[0] : choices;
34767
+ }
34768
+ } else {
34769
+ const fallback = clonedAc["mc:Fallback"];
34770
+ if (fallback) {
34771
+ const rebuilt = { ...fallback };
34772
+ for (const tag of SHAPE_TREE_ELEMENT_TAGS) {
34773
+ delete rebuilt[tag];
34774
+ }
34775
+ for (const [tag, nodes] of liveByTag) {
34776
+ rebuilt[tag] = nodes.length === 1 ? nodes[0] : nodes;
34777
+ }
34778
+ clonedAc["mc:Fallback"] = rebuilt;
34779
+ }
34780
+ }
34781
+ envelopes.push(clonedAc);
34782
+ }
34783
+ spTree["p:sp"] = collectors.shapes;
34784
+ spTree["p:pic"] = collectors.pics;
34785
+ spTree["p:cxnSp"] = collectors.connectors;
34786
+ spTree["p:graphicFrame"] = collectors.graphicFrames;
34787
+ if (collectors.groups.length > 0) {
34788
+ spTree["p:grpSp"] = collectors.groups;
34789
+ } else {
34790
+ delete spTree["p:grpSp"];
34791
+ }
34792
+ if (collectors.contentParts.length > 0) {
34793
+ spTree["p:contentPart"] = collectors.contentParts;
34794
+ } else {
34795
+ delete spTree["p:contentPart"];
34796
+ }
34797
+ if (collectors.model3ds.length > 0) {
34798
+ spTree["p16:model3D"] = collectors.model3ds;
34799
+ } else {
34800
+ delete spTree["p16:model3D"];
34801
+ }
34802
+ spTree["mc:AlternateContent"] = envelopes.length === 1 ? envelopes[0] : envelopes;
34803
+ }
34804
+ };
34805
+
34806
+ // src/core/core/runtime/PptxHandlerRuntimeSaveTheme.ts
34807
+ var PptxHandlerRuntime34 = class extends PptxHandlerRuntime33 {
34808
+ /**
34809
+ * Mark a theme path as dirty so the save pipeline will regenerate
34810
+ * the theme XML from in-memory state. Optional — without this the
34811
+ * original XML is preserved verbatim on save (C-H3).
34812
+ */
34813
+ markThemeDirty(themePath) {
34814
+ this.dirtyThemePaths.add(themePath);
34815
+ }
34816
+ /**
34817
+ * Mark all known theme paths dirty in one call.
34818
+ */
34819
+ markAllThemesDirty() {
34820
+ for (const themePath of this.originalThemeXmlByPath.keys()) {
34821
+ this.dirtyThemePaths.add(themePath);
34822
+ }
34823
+ for (const themePath of this.masterThemePaths.values()) {
34824
+ this.dirtyThemePaths.add(themePath);
34825
+ }
34826
+ }
34827
+ /**
34828
+ * Persist all theme parts during save. Called from the save pipeline
34829
+ * after master / layout XML have been flushed and before
34830
+ * presentation.xml is serialized.
34831
+ *
34832
+ * Order of operations per theme path:
34833
+ *
34834
+ * 1. If the path is *not* in {@link dirtyThemePaths}, the existing
34835
+ * ZIP entry is already correct — no-op. (Original XML was placed
34836
+ * into the ZIP at load time.)
34837
+ * 2. If the path is dirty, build a fresh `<a:theme>` document from
34838
+ * in-memory state and the captured raw subtrees, then overwrite
34839
+ * the ZIP entry.
34840
+ */
34841
+ async persistThemeParts() {
34842
+ const seenThemePaths = /* @__PURE__ */ new Set();
34843
+ for (const [masterPath, themePath] of this.masterThemePaths.entries()) {
34844
+ if (!themePath) {
34845
+ continue;
34846
+ }
34847
+ seenThemePaths.add(themePath);
34848
+ if (!this.dirtyThemePaths.has(themePath)) {
34849
+ continue;
34850
+ }
34851
+ const themeXml2 = this.buildThemeXml(themePath, masterPath);
34852
+ if (themeXml2) {
34853
+ this.zip.file(themePath, themeXml2);
34854
+ }
34855
+ }
34856
+ for (const [themePath] of this.originalThemeXmlByPath.entries()) {
34857
+ if (seenThemePaths.has(themePath)) {
34858
+ continue;
34859
+ }
34860
+ if (!this.dirtyThemePaths.has(themePath)) {
34861
+ continue;
34862
+ }
34863
+ const themeXml2 = this.buildThemeXml(themePath, void 0);
34864
+ if (themeXml2) {
34865
+ this.zip.file(themePath, themeXml2);
34866
+ }
34867
+ }
34868
+ }
34869
+ /**
34870
+ * Build a complete `<a:theme>` XML document from in-memory state.
34871
+ * Returns the serialized XML string (with XML prolog), or `undefined`
34872
+ * if there is no source data to emit.
34873
+ *
34874
+ * - Color scheme: built from per-master color map (or global fallback).
34875
+ * - Font scheme: built from per-master font map + per-script entries.
34876
+ * - Format scheme: re-emit the original XML subtree if available; else
34877
+ * build a minimal scheme from {@link themeFormatScheme}.
34878
+ * - objectDefaults / extraClrSchemeLst / custClrLst / extLst: re-emit
34879
+ * captured raw subtrees.
34880
+ */
34881
+ buildThemeXml(themePath, masterPath) {
34882
+ const colorMap = masterPath && this.masterThemeColorMaps.get(masterPath) || this.globalThemeColorMapSnapshot || this.themeColorMap;
34883
+ const fontMap = masterPath && this.masterThemeFontMaps.get(masterPath) || this.globalThemeFontMapSnapshot || this.themeFontMap;
34884
+ const themeName = this.masterThemeNames.get(themePath) || "Office Theme";
34885
+ const colorSchemeName = this.masterThemeColorSchemeNames.get(themePath) || themeName;
34886
+ const fontSchemeName = this.masterThemeFontSchemeNames.get(themePath) || themeName;
34887
+ const majorScripts = this.masterThemeMajorFontScripts.get(themePath) || {};
34888
+ const minorScripts = this.masterThemeMinorFontScripts.get(themePath) || {};
34889
+ const clrScheme = this.buildClrSchemeObject(colorSchemeName, colorMap);
34890
+ const fontScheme = this.buildFontSchemeObject(
34891
+ fontSchemeName,
34892
+ fontMap,
34893
+ majorScripts,
34894
+ minorScripts
34895
+ );
34896
+ const fmtScheme = this.extractRawSubtreeFromOriginal(themePath, [
34897
+ "a:theme",
34898
+ "a:themeElements",
34899
+ "a:fmtScheme"
34900
+ ]);
34901
+ const themeElements = {
34902
+ "a:clrScheme": clrScheme,
34903
+ "a:fontScheme": fontScheme
34904
+ };
34905
+ if (fmtScheme !== void 0) {
34906
+ themeElements["a:fmtScheme"] = fmtScheme;
34907
+ } else {
34908
+ themeElements["a:fmtScheme"] = this.buildMinimalFmtScheme(themeName);
34909
+ }
34910
+ const themeRoot = {
34911
+ "@_xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
34912
+ "@_name": themeName,
34913
+ "a:themeElements": themeElements
34914
+ };
34915
+ const objectDefaults = this.masterThemeObjectDefaults.get(themePath);
34916
+ if (objectDefaults && (objectDefaults.spDef || objectDefaults.lnDef || objectDefaults.txDef)) {
34917
+ const od = {};
34918
+ if (objectDefaults.spDef !== void 0) {
34919
+ od["a:spDef"] = objectDefaults.spDef;
34920
+ }
34921
+ if (objectDefaults.lnDef !== void 0) {
34922
+ od["a:lnDef"] = objectDefaults.lnDef;
34923
+ }
34924
+ if (objectDefaults.txDef !== void 0) {
34925
+ od["a:txDef"] = objectDefaults.txDef;
34926
+ }
34927
+ themeRoot["a:objectDefaults"] = od;
34928
+ } else {
34929
+ themeRoot["a:objectDefaults"] = {};
34930
+ }
34931
+ const extraClr = this.masterThemeExtraClrSchemeLst.get(themePath);
34932
+ themeRoot["a:extraClrSchemeLst"] = extraClr !== void 0 ? extraClr : {};
34933
+ const custClr = this.masterThemeCustClrLst.get(themePath);
34934
+ if (custClr !== void 0) {
34935
+ themeRoot["a:custClrLst"] = custClr;
34936
+ }
34937
+ const themeExt = this.masterThemeExtLst.get(themePath);
34938
+ if (themeExt !== void 0) {
34939
+ themeRoot["a:extLst"] = themeExt;
34940
+ }
34941
+ const doc = {
34942
+ "?xml": { "@_version": "1.0", "@_encoding": "UTF-8", "@_standalone": "yes" },
34943
+ "a:theme": themeRoot
34944
+ };
34945
+ try {
34946
+ return this.builder.build(doc);
34947
+ } catch (error) {
34948
+ console.warn(`Failed to build theme XML for ${themePath}:`, error);
34949
+ return void 0;
34950
+ }
34951
+ }
34952
+ /**
34953
+ * Build the `a:clrScheme` XmlObject from a colour map. Each slot
34954
+ * value is interpreted as either a `#RRGGBB` srgb hex or a known
34955
+ * sysClr token (currently always emitted as srgbClr — the in-memory
34956
+ * map is hex-typed; sysClr round-trip belongs to the broader C-H3
34957
+ * fix to preserve original color XML and is out of scope here).
34958
+ */
34959
+ buildClrSchemeObject(schemeName, colorMap) {
34960
+ const slot = (key) => {
34961
+ const hex = String(colorMap[key] || "").replace(/^#/, "");
34962
+ const srgb = hex.length === 6 ? hex.toUpperCase() : "000000";
34963
+ return { "a:srgbClr": { "@_val": srgb } };
34964
+ };
34965
+ return {
34966
+ "@_name": schemeName,
34967
+ "a:dk1": slot("dk1"),
34968
+ "a:lt1": slot("lt1"),
34969
+ "a:dk2": slot("dk2"),
34970
+ "a:lt2": slot("lt2"),
34971
+ "a:accent1": slot("accent1"),
34972
+ "a:accent2": slot("accent2"),
34973
+ "a:accent3": slot("accent3"),
34974
+ "a:accent4": slot("accent4"),
34975
+ "a:accent5": slot("accent5"),
34976
+ "a:accent6": slot("accent6"),
34977
+ "a:hlink": slot("hlink"),
34978
+ "a:folHlink": slot("folHlink")
34979
+ };
34980
+ }
34981
+ /**
34982
+ * Build the `a:fontScheme` XmlObject from a font map plus per-script
34983
+ * font tables.
34984
+ *
34985
+ * Phase 4 Stream A / M4.
34986
+ */
34987
+ buildFontSchemeObject(schemeName, fontMap, majorScripts, minorScripts) {
34988
+ const buildFontGroup = (latinKey, eaKey, csKey, scripts) => {
34989
+ const group = {
34990
+ "a:latin": { "@_typeface": fontMap[latinKey] || "Calibri" },
34991
+ "a:ea": { "@_typeface": fontMap[eaKey] || "" },
34992
+ "a:cs": { "@_typeface": fontMap[csKey] || "" }
34993
+ };
34994
+ const scriptKeys = Object.keys(scripts);
34995
+ if (scriptKeys.length > 0) {
34996
+ const fontEntries = scriptKeys.map((script) => ({
34997
+ "@_script": script,
34998
+ "@_typeface": scripts[script]
34999
+ }));
35000
+ group["a:font"] = fontEntries.length === 1 ? fontEntries[0] : fontEntries;
35001
+ }
35002
+ return group;
35003
+ };
35004
+ return {
35005
+ "@_name": schemeName,
35006
+ "a:majorFont": buildFontGroup("mj-lt", "mj-ea", "mj-cs", majorScripts),
35007
+ "a:minorFont": buildFontGroup("mn-lt", "mn-ea", "mn-cs", minorScripts)
35008
+ };
35009
+ }
35010
+ /**
35011
+ * Re-parse the original theme XML and pluck out a subtree by path,
35012
+ * returning the raw parser object. Returns `undefined` when the
35013
+ * original is missing or the path doesn't exist.
35014
+ *
35015
+ * Used to preserve `a:fmtScheme` byte-for-byte through a regenerate
35016
+ * round-trip, since the in-memory PptxThemeFormatScheme is lossy.
35017
+ */
35018
+ extractRawSubtreeFromOriginal(themePath, path) {
35019
+ const original = this.originalThemeXmlByPath.get(themePath);
35020
+ if (!original) {
35021
+ return void 0;
35022
+ }
35023
+ try {
35024
+ const parsed = this.parser.parse(original);
35025
+ let cursor = parsed;
35026
+ for (const segment of path) {
35027
+ if (cursor && typeof cursor === "object" && segment in cursor) {
35028
+ cursor = cursor[segment];
35029
+ } else {
35030
+ return void 0;
35031
+ }
35032
+ }
35033
+ return cursor;
35034
+ } catch {
35035
+ return void 0;
35036
+ }
35037
+ }
35038
+ /**
35039
+ * Last-resort minimal `<a:fmtScheme>` body. Mirrors the SDK new-deck
35040
+ * builder's output for new presentations, scaled down to the smallest
35041
+ * schema-valid form.
35042
+ */
35043
+ buildMinimalFmtScheme(name) {
35044
+ const phClrSolid = { "a:solidFill": { "a:schemeClr": { "@_val": "phClr" } } };
35045
+ return {
35046
+ "@_name": name,
35047
+ "a:fillStyleLst": {
35048
+ "a:solidFill": [{ "a:schemeClr": { "@_val": "phClr" } }],
35049
+ "a:gradFill": []
35050
+ },
35051
+ "a:lnStyleLst": {
35052
+ "a:ln": [
35053
+ {
35054
+ "@_w": "6350",
35055
+ "@_cap": "flat",
35056
+ "@_cmpd": "sng",
35057
+ "@_algn": "ctr",
35058
+ ...phClrSolid,
35059
+ "a:prstDash": { "@_val": "solid" },
35060
+ "a:miter": { "@_lim": "800000" }
35061
+ },
35062
+ {
35063
+ "@_w": "12700",
35064
+ "@_cap": "flat",
35065
+ "@_cmpd": "sng",
35066
+ "@_algn": "ctr",
35067
+ ...phClrSolid,
35068
+ "a:prstDash": { "@_val": "solid" },
35069
+ "a:miter": { "@_lim": "800000" }
35070
+ },
35071
+ {
35072
+ "@_w": "19050",
35073
+ "@_cap": "flat",
35074
+ "@_cmpd": "sng",
35075
+ "@_algn": "ctr",
35076
+ ...phClrSolid,
35077
+ "a:prstDash": { "@_val": "solid" },
35078
+ "a:miter": { "@_lim": "800000" }
35079
+ }
35080
+ ]
35081
+ },
35082
+ "a:effectStyleLst": {
35083
+ "a:effectStyle": [{ "a:effectLst": {} }, { "a:effectLst": {} }, { "a:effectLst": {} }]
35084
+ },
35085
+ "a:bgFillStyleLst": {
35086
+ "a:solidFill": [{ "a:schemeClr": { "@_val": "phClr" } }],
35087
+ "a:gradFill": []
35088
+ }
35089
+ };
35090
+ }
33187
35091
  };
33188
35092
 
33189
35093
  // src/core/core/runtime/PptxHandlerRuntimeSavePipeline.ts
33190
- var PptxHandlerRuntime34 = class _PptxHandlerRuntime extends PptxHandlerRuntime33 {
35094
+ var PptxHandlerRuntime35 = class _PptxHandlerRuntime extends PptxHandlerRuntime34 {
33191
35095
  /**
33192
35096
  * Resolve the effective conformance class for this save operation.
33193
35097
  *
@@ -33274,6 +35178,7 @@ var PptxHandlerRuntime34 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33274
35178
  for (const [masterPath, masterXmlObj] of this.masterXmlMap.entries()) {
33275
35179
  this.zip.file(masterPath, this.builder.build(masterXmlObj));
33276
35180
  }
35181
+ await this.persistThemeParts();
33277
35182
  await this.applyEmbeddedFontPreservation(options?.embeddedFonts);
33278
35183
  if (this.presentationData) {
33279
35184
  this.presentationSaveBuilder.applySaveOptions({
@@ -33363,7 +35268,7 @@ var PptxHandlerRuntime34 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33363
35268
  };
33364
35269
 
33365
35270
  // src/core/core/runtime/PptxHandlerRuntimeElementParsing.ts
33366
- var PptxHandlerRuntime35 = class _PptxHandlerRuntime extends PptxHandlerRuntime34 {
35271
+ var PptxHandlerRuntime36 = class _PptxHandlerRuntime extends PptxHandlerRuntime35 {
33367
35272
  /**
33368
35273
  * Parse media data (video/audio path and MIME type) from graphic frame data.
33369
35274
  */
@@ -33585,7 +35490,7 @@ var PptxHandlerRuntime35 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33585
35490
  };
33586
35491
 
33587
35492
  // src/core/core/runtime/PptxHandlerRuntimePlaceholderLookup.ts
33588
- var PptxHandlerRuntime36 = class extends PptxHandlerRuntime35 {
35493
+ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
33589
35494
  findPlaceholderInShapeTree(spTree, expected) {
33590
35495
  if (!spTree) {
33591
35496
  return void 0;
@@ -33738,7 +35643,7 @@ var PptxHandlerRuntime36 = class extends PptxHandlerRuntime35 {
33738
35643
  };
33739
35644
 
33740
35645
  // src/core/core/runtime/PptxHandlerRuntimeGeometryParsing.ts
33741
- var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
35646
+ var PptxHandlerRuntime38 = class extends PptxHandlerRuntime37 {
33742
35647
  parseGeometryAdjustments(prstGeom) {
33743
35648
  if (!prstGeom) {
33744
35649
  return void 0;
@@ -33847,6 +35752,103 @@ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
33847
35752
  }
33848
35753
  return handles.length > 0 ? handles : void 0;
33849
35754
  }
35755
+ /**
35756
+ * Extract `a:gdLst`/`a:ahLst`/`a:cxnLst`/`a:rect` raw XML from a `a:custGeom`
35757
+ * node so they can be re-emitted on save when the geometry is edited.
35758
+ * Returns `undefined` when none of these auxiliary children carry data.
35759
+ */
35760
+ extractCustomGeometryRawData(custGeom) {
35761
+ if (!custGeom) {
35762
+ return void 0;
35763
+ }
35764
+ const isNonEmpty = (node) => {
35765
+ if (node === void 0 || node === null) {
35766
+ return false;
35767
+ }
35768
+ if (typeof node !== "object") {
35769
+ return true;
35770
+ }
35771
+ return Object.keys(node).length > 0;
35772
+ };
35773
+ const result = {};
35774
+ const gdLst = custGeom["a:gdLst"];
35775
+ if (isNonEmpty(gdLst)) {
35776
+ result.gdLstXml = gdLst;
35777
+ }
35778
+ const ahLst = custGeom["a:ahLst"];
35779
+ if (isNonEmpty(ahLst)) {
35780
+ result.ahLstXml = ahLst;
35781
+ }
35782
+ const cxnLst = custGeom["a:cxnLst"];
35783
+ if (isNonEmpty(cxnLst)) {
35784
+ result.cxnLstXml = cxnLst;
35785
+ }
35786
+ const rect = custGeom["a:rect"];
35787
+ if (isNonEmpty(rect)) {
35788
+ result.rectXml = rect;
35789
+ }
35790
+ return Object.keys(result).length > 0 ? result : void 0;
35791
+ }
35792
+ /**
35793
+ * Build structured `CustomGeometryPath[]` from a parsed `a:custGeom` node,
35794
+ * including per-path `@fill`/`@stroke`/`@extrusionOk` attributes so they
35795
+ * survive a round-trip when the path list is later regenerated.
35796
+ *
35797
+ * Falls back to SVG → structured-path conversion when no structured path
35798
+ * info is otherwise available.
35799
+ */
35800
+ buildStructuredCustomGeometryPaths(custGeom, pathData, pathWidth, pathHeight) {
35801
+ if (!custGeom) {
35802
+ return void 0;
35803
+ }
35804
+ const pathLst = custGeom["a:pathLst"];
35805
+ if (!pathLst) {
35806
+ return void 0;
35807
+ }
35808
+ const pathNodes = this.ensureArray(pathLst["a:path"]);
35809
+ if (pathNodes.length === 0) {
35810
+ return void 0;
35811
+ }
35812
+ const segments = svgToCustomGeometryPaths(pathData, pathWidth, pathHeight);
35813
+ if (segments.length === 0) {
35814
+ return void 0;
35815
+ }
35816
+ const validFillModes = /* @__PURE__ */ new Set([
35817
+ "norm",
35818
+ "lighten",
35819
+ "lightenLess",
35820
+ "darken",
35821
+ "darkenLess",
35822
+ "none"
35823
+ ]);
35824
+ const parseBoolAttr2 = (value) => {
35825
+ if (value === void 0 || value === null || value === "") {
35826
+ return void 0;
35827
+ }
35828
+ if (value === "1" || value === "true" || value === true) {
35829
+ return true;
35830
+ }
35831
+ if (value === "0" || value === "false" || value === false) {
35832
+ return false;
35833
+ }
35834
+ return void 0;
35835
+ };
35836
+ const target = segments[0];
35837
+ const firstNode = pathNodes[0];
35838
+ const fillAttr = String(firstNode["@_fill"] ?? "").trim();
35839
+ if (validFillModes.has(fillAttr)) {
35840
+ target.fillMode = fillAttr;
35841
+ }
35842
+ const strokeAttr = parseBoolAttr2(firstNode["@_stroke"]);
35843
+ if (strokeAttr !== void 0) {
35844
+ target.stroke = strokeAttr;
35845
+ }
35846
+ const extrusionAttr = parseBoolAttr2(firstNode["@_extrusionOk"]);
35847
+ if (extrusionAttr !== void 0) {
35848
+ target.extrusionOk = extrusionAttr;
35849
+ }
35850
+ return segments;
35851
+ }
33850
35852
  parseCustomGeometry(custGeom, shapeWidth, shapeHeight) {
33851
35853
  if (!custGeom || !custGeom["a:pathLst"] || !custGeom["a:pathLst"]?.["a:path"]) {
33852
35854
  return null;
@@ -33915,7 +35917,7 @@ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
33915
35917
  };
33916
35918
 
33917
35919
  // src/core/core/runtime/PptxHandlerRuntimeShapeImageFill.ts
33918
- var PptxHandlerRuntime38 = class _PptxHandlerRuntime extends PptxHandlerRuntime37 {
35920
+ var PptxHandlerRuntime39 = class _PptxHandlerRuntime extends PptxHandlerRuntime38 {
33919
35921
  /**
33920
35922
  * Parse a shape that has an image fill (a:blipFill inside spPr)
33921
35923
  * This handles shapes like rectangles filled with images (e.g., wood texture backgrounds)
@@ -34115,7 +36117,7 @@ var PptxHandlerRuntime38 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
34115
36117
  };
34116
36118
 
34117
36119
  // src/core/core/runtime/PptxHandlerRuntimeTextDefaults.ts
34118
- var PptxHandlerRuntime39 = class extends PptxHandlerRuntime38 {
36120
+ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34119
36121
  /**
34120
36122
  * Apply {@link PlaceholderDefaults} body-level properties to a
34121
36123
  * {@link TextStyle} as fallback values (only sets fields that are
@@ -34239,7 +36241,7 @@ var PptxHandlerRuntime39 = class extends PptxHandlerRuntime38 {
34239
36241
  };
34240
36242
 
34241
36243
  // src/core/core/runtime/PptxHandlerRuntimeBulletParsing.ts
34242
- var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
36244
+ var PptxHandlerRuntime41 = class extends PptxHandlerRuntime40 {
34243
36245
  resolveParagraphBulletInfo(paragraph, paragraphIndex, txBody, inheritedTxBody, isBodyPlaceholder = false, slidePath) {
34244
36246
  if (!paragraph) {
34245
36247
  return null;
@@ -34270,7 +36272,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34270
36272
  if (candidate["a:buNone"]) {
34271
36273
  return { none: true };
34272
36274
  }
34273
- if (candidate["a:buChar"] || candidate["a:buAutoNum"] || candidate["a:buBlip"]) {
36275
+ if (candidate["a:buChar"] || candidate["a:buAutoNum"] || candidate["a:buBlip"] || candidate["a:buFontTx"] !== void 0 || candidate["a:buClrTx"] !== void 0 || candidate["a:buSzTx"] !== void 0) {
34274
36276
  resolvedBulletProps = candidate;
34275
36277
  break;
34276
36278
  }
@@ -34284,6 +36286,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34284
36286
  }
34285
36287
  const buFont = resolvedBulletProps["a:buFont"];
34286
36288
  const fontFamily = buFont?.["@_typeface"] ? String(buFont["@_typeface"]) : void 0;
36289
+ const fontInherit = resolvedBulletProps["a:buFontTx"] !== void 0;
34287
36290
  const buSzPct = resolvedBulletProps["a:buSzPct"];
34288
36291
  let sizePercent;
34289
36292
  if (buSzPct?.["@_val"] !== void 0) {
@@ -34300,6 +36303,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34300
36303
  sizePts = ptsRaw / 100;
34301
36304
  }
34302
36305
  }
36306
+ const sizeInherit = resolvedBulletProps["a:buSzTx"] !== void 0;
34303
36307
  const buClr = resolvedBulletProps["a:buClr"];
34304
36308
  let color;
34305
36309
  if (buClr) {
@@ -34308,6 +36312,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34308
36312
  color = String(srgb["@_val"]);
34309
36313
  }
34310
36314
  }
36315
+ const colorInherit = resolvedBulletProps["a:buClrTx"] !== void 0;
34311
36316
  const bulletChar = String(
34312
36317
  resolvedBulletProps["a:buChar"]?.["@_char"] || ""
34313
36318
  );
@@ -34317,7 +36322,10 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34317
36322
  fontFamily,
34318
36323
  sizePercent,
34319
36324
  sizePts,
34320
- color
36325
+ color,
36326
+ ...fontInherit ? { fontInherit: true } : {},
36327
+ ...colorInherit ? { colorInherit: true } : {},
36328
+ ...sizeInherit ? { sizeInherit: true } : {}
34321
36329
  };
34322
36330
  }
34323
36331
  const autoNum = resolvedBulletProps["a:buAutoNum"];
@@ -34332,7 +36340,10 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34332
36340
  fontFamily,
34333
36341
  sizePercent,
34334
36342
  sizePts,
34335
- color
36343
+ color,
36344
+ ...fontInherit ? { fontInherit: true } : {},
36345
+ ...colorInherit ? { colorInherit: true } : {},
36346
+ ...sizeInherit ? { sizeInherit: true } : {}
34336
36347
  };
34337
36348
  }
34338
36349
  const buBlip = resolvedBulletProps["a:buBlip"];
@@ -34444,7 +36455,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34444
36455
  };
34445
36456
 
34446
36457
  // src/core/core/runtime/PptxHandlerRuntimeShapeBodyParsing.ts
34447
- var PptxHandlerRuntime41 = class _PptxHandlerRuntime extends PptxHandlerRuntime40 {
36458
+ var PptxHandlerRuntime42 = class _PptxHandlerRuntime extends PptxHandlerRuntime41 {
34448
36459
  /**
34449
36460
  * Parse `a:spLocks` attributes into a structured {@link PptxShapeLocks} object.
34450
36461
  * Returns `undefined` when the node is absent or contains no lock attributes.
@@ -34539,7 +36550,8 @@ var PptxHandlerRuntime41 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
34539
36550
  if (Number.isFinite(spcColRaw) && spcColRaw > 0) {
34540
36551
  textStyle.columnSpacing = spcColRaw / _PptxHandlerRuntime.EMU_PER_PX;
34541
36552
  }
34542
- const hOverflow = String(bodyPr["@_hOverflow"] || "").trim();
36553
+ const hOverflowRaw = bodyPr["@_horzOverflow"] ?? bodyPr["@_hOverflow"];
36554
+ const hOverflow = String(hOverflowRaw || "").trim();
34543
36555
  if (hOverflow === "overflow" || hOverflow === "clip") {
34544
36556
  textStyle.hOverflow = hOverflow;
34545
36557
  }
@@ -34722,7 +36734,7 @@ var PptxHandlerRuntime41 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
34722
36734
  };
34723
36735
 
34724
36736
  // src/core/core/runtime/PptxHandlerRuntimeShapeTextParsing.ts
34725
- var PptxHandlerRuntime42 = class _PptxHandlerRuntime extends PptxHandlerRuntime41 {
36737
+ var PptxHandlerRuntime43 = class _PptxHandlerRuntime extends PptxHandlerRuntime42 {
34726
36738
  /**
34727
36739
  * Resolve paragraph-level styles (alignment, spacing, margins, tabs,
34728
36740
  * level styles) for a single paragraph. Modifies `textStyle` in place
@@ -34904,7 +36916,7 @@ var PptxHandlerRuntime42 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
34904
36916
  };
34905
36917
 
34906
36918
  // src/core/core/runtime/PptxHandlerRuntimeShapeParagraphContentParsing.ts
34907
- var PptxHandlerRuntime43 = class extends PptxHandlerRuntime42 {
36919
+ var PptxHandlerRuntime44 = class extends PptxHandlerRuntime43 {
34908
36920
  /**
34909
36921
  * Collect text content (runs, fields, equations, bullets) for a single
34910
36922
  * paragraph and return text parts + segments. The returned `seedStyle`
@@ -35087,6 +37099,23 @@ var PptxHandlerRuntime43 = class extends PptxHandlerRuntime42 {
35087
37099
  parts.push("\n");
35088
37100
  segments.push({ text: "\n", style: { ...mergedDefaultRunStyle } });
35089
37101
  }
37102
+ const firstSegmentIndex = segments.length === 0 ? -1 : 0;
37103
+ if (firstSegmentIndex >= 0) {
37104
+ const pPrRaw = p["a:pPr"];
37105
+ const lvlRaw = pPrRaw?.["@_lvl"];
37106
+ if (lvlRaw !== void 0) {
37107
+ const lvlParsed = Number.parseInt(String(lvlRaw), 10);
37108
+ if (Number.isFinite(lvlParsed) && lvlParsed > 0) {
37109
+ segments[firstSegmentIndex].paragraphLevel = Math.min(Math.max(lvlParsed, 0), 8);
37110
+ }
37111
+ }
37112
+ const endParaRPrRaw = p["a:endParaRPr"];
37113
+ if (endParaRPrRaw && typeof endParaRPrRaw === "object") {
37114
+ segments[firstSegmentIndex].endParaRunProperties = {
37115
+ ...endParaRPrRaw
37116
+ };
37117
+ }
37118
+ }
35090
37119
  return { parts, segments, seedStyle };
35091
37120
  }
35092
37121
  /**
@@ -35196,7 +37225,7 @@ var PptxHandlerRuntime43 = class extends PptxHandlerRuntime42 {
35196
37225
  };
35197
37226
 
35198
37227
  // src/core/core/runtime/PptxHandlerRuntimeShapeParsing.ts
35199
- var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime43 {
37228
+ var PptxHandlerRuntime45 = class _PptxHandlerRuntime extends PptxHandlerRuntime44 {
35200
37229
  parseShape(shape, id, slidePath) {
35201
37230
  try {
35202
37231
  const spPr = shape["p:spPr"];
@@ -35232,6 +37261,7 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35232
37261
  let pathData;
35233
37262
  let pathWidth;
35234
37263
  let pathHeight;
37264
+ let customGeometryRawData;
35235
37265
  const custGeom = effectiveSpPr?.["a:custGeom"];
35236
37266
  if (custGeom) {
35237
37267
  const customPath = this.parseCustomGeometry(
@@ -35244,6 +37274,7 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35244
37274
  pathData = customPath.pathData;
35245
37275
  pathWidth = customPath.pathWidth;
35246
37276
  pathHeight = customPath.pathHeight;
37277
+ customGeometryRawData = this.extractCustomGeometryRawData(custGeom);
35247
37278
  }
35248
37279
  }
35249
37280
  const geomNode = custGeom ?? effectiveSpPr?.["a:prstGeom"];
@@ -35401,7 +37432,8 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35401
37432
  type: "shape",
35402
37433
  pathData,
35403
37434
  pathWidth,
35404
- pathHeight
37435
+ pathHeight,
37436
+ customGeometryRawData
35405
37437
  };
35406
37438
  } catch (e) {
35407
37439
  console.warn(`[pptx] Skipping shape element (${id}):`, e);
@@ -35411,7 +37443,7 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35411
37443
  };
35412
37444
 
35413
37445
  // src/core/core/runtime/PptxHandlerRuntimePictureParsing.ts
35414
- var PptxHandlerRuntime45 = class _PptxHandlerRuntime extends PptxHandlerRuntime44 {
37446
+ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime45 {
35415
37447
  async parsePicture(pic, id, slidePath) {
35416
37448
  try {
35417
37449
  const spPr = pic["p:spPr"];
@@ -35650,7 +37682,7 @@ var PptxHandlerRuntime45 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35650
37682
  };
35651
37683
 
35652
37684
  // src/core/core/runtime/PptxHandlerRuntimeSpTreeParsing.ts
35653
- var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime45 {
37685
+ var PptxHandlerRuntime47 = class _PptxHandlerRuntime extends PptxHandlerRuntime46 {
35654
37686
  /**
35655
37687
  * Known element tag names that appear as direct children of `p:spTree`
35656
37688
  * (or `p:grpSp`) and represent renderable shapes/objects.
@@ -35995,9 +38027,18 @@ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35995
38027
  * Unwrap mc:AlternateContent elements within a shape tree (or group),
35996
38028
  * merging selected branch children into the parent element arrays.
35997
38029
  * Delegates to the standalone alternate-content utility.
38030
+ *
38031
+ * Records each consumed AC envelope in {@link alternateContentBlockByRawXml}
38032
+ * so the save layer can re-emit the original `<mc:Choice>` /
38033
+ * `<mc:Fallback>` shape on dirty save (CC-4).
35998
38034
  */
35999
38035
  unwrapAlternateContent(container) {
36000
- unwrapAlternateContent(container);
38036
+ const blocks = unwrapAlternateContent(container);
38037
+ for (const block of blocks) {
38038
+ for (const ref of block.childRefs) {
38039
+ this.alternateContentBlockByRawXml.set(ref.node, block);
38040
+ }
38041
+ }
36001
38042
  }
36002
38043
  /**
36003
38044
  * Forward declaration – implemented in PptxHandlerRuntimeGroupParsing.
@@ -36008,7 +38049,7 @@ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
36008
38049
  };
36009
38050
 
36010
38051
  // src/core/core/runtime/PptxHandlerRuntimeGroupParsing.ts
36011
- var PptxHandlerRuntime47 = class _PptxHandlerRuntime extends PptxHandlerRuntime46 {
38052
+ var PptxHandlerRuntime48 = class _PptxHandlerRuntime extends PptxHandlerRuntime47 {
36012
38053
  async parseGroupShape(group, baseId, slidePath, rawXmlStr) {
36013
38054
  const grpSpPr = group["p:grpSpPr"];
36014
38055
  const xfrm = grpSpPr?.["a:xfrm"];
@@ -36181,7 +38222,7 @@ var PptxHandlerRuntime47 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
36181
38222
  };
36182
38223
 
36183
38224
  // src/core/core/runtime/PptxHandlerRuntimeSlideParsing.ts
36184
- var PptxHandlerRuntime48 = class extends PptxHandlerRuntime47 {
38225
+ var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
36185
38226
  /**
36186
38227
  * Parse text body from a connector shape (p:cxnSp > p:txBody).
36187
38228
  * Uses the same text run extraction logic as regular shapes but
@@ -36293,7 +38334,7 @@ var PptxHandlerRuntime48 = class extends PptxHandlerRuntime47 {
36293
38334
  };
36294
38335
 
36295
38336
  // src/core/core/runtime/PptxHandlerRuntimeColorAndEffects.ts
36296
- var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
38337
+ var PptxHandlerRuntime50 = class extends PptxHandlerRuntime49 {
36297
38338
  /**
36298
38339
  * Forward declaration – implemented in PptxHandlerRuntimeThemeProcessing.
36299
38340
  * Re-resolves gradient stops by substituting `phClr` with the given colour.
@@ -36334,8 +38375,9 @@ var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
36334
38375
  return void 0;
36335
38376
  }
36336
38377
  const resolvedKey = normalized === "phclr" ? "accent1" : normalized;
36337
- if (this.currentSlideClrMapOverride) {
36338
- const remapped = this.currentSlideClrMapOverride[resolvedKey];
38378
+ const overrideMap = this.currentSlideClrMapOverride ?? this.currentMasterClrMap;
38379
+ if (overrideMap) {
38380
+ const remapped = overrideMap[resolvedKey];
36339
38381
  if (remapped) {
36340
38382
  return this.themeColorMap[remapped] || this.getDefaultSchemeColorMap()[remapped];
36341
38383
  }
@@ -36418,7 +38460,7 @@ var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
36418
38460
  };
36419
38461
 
36420
38462
  // src/core/core/runtime/PptxHandlerRuntimeBackgroundParsing.ts
36421
- var PptxHandlerRuntime50 = class extends PptxHandlerRuntime49 {
38463
+ var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
36422
38464
  async extractBackgroundImage(slideXml2, slidePath, rootElement = "p:sld") {
36423
38465
  try {
36424
38466
  const bg = slideXml2[rootElement]?.["p:cSld"]?.["p:bg"];
@@ -36629,7 +38671,7 @@ var PptxHandlerRuntime50 = class extends PptxHandlerRuntime49 {
36629
38671
  };
36630
38672
 
36631
38673
  // src/core/core/runtime/PptxHandlerRuntimeSlideUtils.ts
36632
- var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
38674
+ var PptxHandlerRuntime52 = class extends PptxHandlerRuntime51 {
36633
38675
  /**
36634
38676
  * Retrieve the background gradient from a layout, falling back to master.
36635
38677
  */
@@ -36700,6 +38742,64 @@ var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
36700
38742
  }
36701
38743
  return void 0;
36702
38744
  }
38745
+ /**
38746
+ * Find the master file path referenced by a layout via its relationships.
38747
+ */
38748
+ findMasterPathForLayoutBase(layoutPath) {
38749
+ const layoutRels = this.slideRelsMap.get(layoutPath);
38750
+ if (!layoutRels) {
38751
+ return void 0;
38752
+ }
38753
+ for (const [, target] of layoutRels.entries()) {
38754
+ if (target.includes("slideMaster")) {
38755
+ const layoutDir = layoutPath.substring(0, layoutPath.lastIndexOf("/") + 1);
38756
+ return target.startsWith("..") ? this.resolvePath(layoutDir, target) : `ppt/${target.replace("../", "")}`;
38757
+ }
38758
+ }
38759
+ return void 0;
38760
+ }
38761
+ /**
38762
+ * Switch the active master state (clrMap + theme color/font/format
38763
+ * scheme) so that scheme-colour resolution for the slide currently
38764
+ * being parsed walks through the correct master.
38765
+ *
38766
+ * Multi-master decks must resolve scheme colours against each slide's
38767
+ * own master rather than always against `masterFiles[0]`.
38768
+ *
38769
+ * Phase 2 Stream B / C-H4.
38770
+ */
38771
+ async setActiveMasterForSlide(slidePath) {
38772
+ const layoutPath = this.findLayoutPathForSlide(slidePath);
38773
+ if (!layoutPath) {
38774
+ this.currentMasterClrMap = null;
38775
+ this.themeColorMap = { ...this.globalThemeColorMapSnapshot };
38776
+ this.themeFontMap = { ...this.globalThemeFontMapSnapshot };
38777
+ this.themeFormatScheme = this.globalThemeFormatSchemeSnapshot;
38778
+ return;
38779
+ }
38780
+ if (!this.slideRelsMap.has(layoutPath)) {
38781
+ const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
38782
+ try {
38783
+ await this.loadSlideRelationships(layoutPath, layoutRelsPath);
38784
+ } catch {
38785
+ }
38786
+ }
38787
+ const masterPath = this.findMasterPathForLayoutBase(layoutPath);
38788
+ if (!masterPath) {
38789
+ this.currentMasterClrMap = null;
38790
+ this.themeColorMap = { ...this.globalThemeColorMapSnapshot };
38791
+ this.themeFontMap = { ...this.globalThemeFontMapSnapshot };
38792
+ this.themeFormatScheme = this.globalThemeFormatSchemeSnapshot;
38793
+ return;
38794
+ }
38795
+ this.currentMasterClrMap = this.masterClrMaps.get(masterPath) ?? null;
38796
+ const masterColorMap = this.masterThemeColorMaps.get(masterPath);
38797
+ this.themeColorMap = masterColorMap ? { ...masterColorMap } : { ...this.globalThemeColorMapSnapshot };
38798
+ const masterFontMap = this.masterThemeFontMaps.get(masterPath);
38799
+ this.themeFontMap = masterFontMap ? { ...masterFontMap } : { ...this.globalThemeFontMapSnapshot };
38800
+ const masterFormatScheme = this.masterThemeFormatSchemes.get(masterPath);
38801
+ this.themeFormatScheme = masterFormatScheme ?? this.globalThemeFormatSchemeSnapshot;
38802
+ }
36703
38803
  /**
36704
38804
  * Extract the `p:bg/@showAnimation` flag from a slide's XML.
36705
38805
  * Returns `true` when the background should animate, `false` when
@@ -36840,7 +38940,7 @@ var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
36840
38940
  };
36841
38941
 
36842
38942
  // src/core/core/runtime/PptxHandlerRuntimePlaceholderStyles.ts
36843
- var PptxHandlerRuntime52 = class _PptxHandlerRuntime extends PptxHandlerRuntime51 {
38943
+ var PptxHandlerRuntime53 = class _PptxHandlerRuntime extends PptxHandlerRuntime52 {
36844
38944
  /**
36845
38945
  * Parse a single `a:lvlXpPr` node into a structured
36846
38946
  * {@link PlaceholderTextLevelStyle}.
@@ -36961,7 +39061,7 @@ var PptxHandlerRuntime52 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
36961
39061
  };
36962
39062
 
36963
39063
  // src/core/core/runtime/PptxHandlerRuntimePlaceholderDefaults.ts
36964
- var PptxHandlerRuntime53 = class _PptxHandlerRuntime extends PptxHandlerRuntime52 {
39064
+ var PptxHandlerRuntime54 = class _PptxHandlerRuntime extends PptxHandlerRuntime53 {
36965
39065
  /**
36966
39066
  * Extract structured {@link PlaceholderDefaults} from a layout or master
36967
39067
  * shape that carries a `p:ph` element.
@@ -37104,7 +39204,118 @@ var PptxHandlerRuntime53 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
37104
39204
  };
37105
39205
 
37106
39206
  // src/core/core/runtime/PptxHandlerRuntimeMasterElements.ts
37107
- var PptxHandlerRuntime54 = class extends PptxHandlerRuntime53 {
39207
+ function parseHeaderFooterFlags(hf) {
39208
+ if (!hf) {
39209
+ return void 0;
39210
+ }
39211
+ const result = {};
39212
+ if (hf["@_hdr"] !== void 0) {
39213
+ result.hasHeader = String(hf["@_hdr"]) !== "0";
39214
+ }
39215
+ if (hf["@_ftr"] !== void 0) {
39216
+ result.hasFooter = String(hf["@_ftr"]) !== "0";
39217
+ }
39218
+ if (hf["@_dt"] !== void 0) {
39219
+ result.hasDateTime = String(hf["@_dt"]) !== "0";
39220
+ }
39221
+ if (hf["@_sldNum"] !== void 0) {
39222
+ result.hasSlideNumber = String(hf["@_sldNum"]) !== "0";
39223
+ }
39224
+ return Object.keys(result).length > 0 ? result : void 0;
39225
+ }
39226
+ var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
39227
+ /**
39228
+ * Parse a `CT_TextListStyle` node (`a:defPPr` + `a:lvl1pPr` … `a:lvl9pPr`)
39229
+ * into a level-keyed style map. Used for `<p:txStyles>` children
39230
+ * (`p:titleStyle`, `p:bodyStyle`, `p:otherStyle`) — see ECMA-376 §19.3.1.52.
39231
+ */
39232
+ parseTextListStyle(node) {
39233
+ if (!node) {
39234
+ return void 0;
39235
+ }
39236
+ const levels = {};
39237
+ const defParsed = this.parsePlaceholderLevelStyle(node["a:defPPr"]);
39238
+ if (defParsed) {
39239
+ levels[-1] = defParsed;
39240
+ }
39241
+ for (let lvl = 1; lvl <= 9; lvl++) {
39242
+ const parsed = this.parsePlaceholderLevelStyle(
39243
+ node[`a:lvl${lvl}pPr`]
39244
+ );
39245
+ if (parsed) {
39246
+ levels[lvl - 1] = parsed;
39247
+ }
39248
+ }
39249
+ return Object.keys(levels).length > 0 ? levels : void 0;
39250
+ }
39251
+ /**
39252
+ * Parse `<p:txStyles>` from a slide-master XML object into a structured
39253
+ * {@link PptxMasterTextStyles}. Used to populate `PptxSlideMaster.txStyles`
39254
+ * so the title/body/other text-style cascade (P-H1) is visible on the
39255
+ * typed model.
39256
+ */
39257
+ parseMasterTxStyles(masterXml) {
39258
+ const txStyles = masterXml?.["p:txStyles"];
39259
+ if (!txStyles) {
39260
+ return void 0;
39261
+ }
39262
+ const titleStyle = this.parseTextListStyle(txStyles["p:titleStyle"]);
39263
+ const bodyStyle = this.parseTextListStyle(txStyles["p:bodyStyle"]);
39264
+ const otherStyle = this.parseTextListStyle(txStyles["p:otherStyle"]);
39265
+ if (!titleStyle && !bodyStyle && !otherStyle) {
39266
+ return void 0;
39267
+ }
39268
+ const result = {};
39269
+ if (titleStyle) {
39270
+ result.titleStyle = titleStyle;
39271
+ }
39272
+ if (bodyStyle) {
39273
+ result.bodyStyle = bodyStyle;
39274
+ }
39275
+ if (otherStyle) {
39276
+ result.otherStyle = otherStyle;
39277
+ }
39278
+ return result;
39279
+ }
39280
+ /**
39281
+ * Enrich an array of {@link PptxSlideMaster} entries (already produced by
39282
+ * `parseSlideMasters`) with parsed `<p:txStyles>`. Loads each master's XML
39283
+ * once, parses, and caches it in `masterXmlMap` for downstream consumers.
39284
+ *
39285
+ * Also stores the parsed result on the per-master cache so that the
39286
+ * inheritance chain in `applyMasterTextStyleCascade` can find it without
39287
+ * re-parsing.
39288
+ */
39289
+ async enrichSlideMastersWithTxStyles(slideMasters) {
39290
+ for (const master of slideMasters) {
39291
+ try {
39292
+ let masterXmlObj = this.masterXmlMap.get(master.path);
39293
+ if (!masterXmlObj) {
39294
+ const xmlStr = await this.zip.file(master.path)?.async("string");
39295
+ if (!xmlStr) {
39296
+ continue;
39297
+ }
39298
+ masterXmlObj = this.parser.parse(xmlStr);
39299
+ this.masterXmlMap.set(master.path, masterXmlObj);
39300
+ }
39301
+ const sldMaster = masterXmlObj["p:sldMaster"];
39302
+ if (!sldMaster) {
39303
+ continue;
39304
+ }
39305
+ const parsed = this.parseMasterTxStyles(sldMaster);
39306
+ if (parsed) {
39307
+ master.txStyles = parsed;
39308
+ this.masterTxStylesCache.set(master.path, parsed);
39309
+ }
39310
+ const hf = parseHeaderFooterFlags(sldMaster["p:hf"]);
39311
+ if (hf) {
39312
+ master.headerFooter = hf;
39313
+ }
39314
+ } catch (e) {
39315
+ console.warn("Failed to parse master txStyles:", e);
39316
+ }
39317
+ }
39318
+ }
37108
39319
  parsePresentationDefaultTextStyle() {
37109
39320
  const presentation = this.presentationData?.["p:presentation"];
37110
39321
  const defaultTextStyle = presentation?.["p:defaultTextStyle"];
@@ -37260,7 +39471,7 @@ var PptxHandlerRuntime54 = class extends PptxHandlerRuntime53 {
37260
39471
  };
37261
39472
 
37262
39473
  // src/core/core/runtime/PptxHandlerRuntimeLayoutElements.ts
37263
- var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
39474
+ var PptxHandlerRuntime56 = class extends PptxHandlerRuntime55 {
37264
39475
  async getLayoutElements(slidePath) {
37265
39476
  const slideRels = this.slideRelsMap.get(slidePath);
37266
39477
  if (!slideRels) {
@@ -37384,10 +39595,10 @@ var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
37384
39595
  }
37385
39596
  }
37386
39597
  }
37387
- this.currentSlideClrMapOverride = prevClrMapOverride;
37388
39598
  const layoutShowMasterSp = layoutXmlObj["p:sldLayout"]?.["@_showMasterSp"];
37389
39599
  const showMasterSp = layoutShowMasterSp === void 0 || String(layoutShowMasterSp).trim().toLowerCase() !== "0" && String(layoutShowMasterSp).trim().toLowerCase() !== "false";
37390
39600
  const masterElements = showMasterSp ? await this.getMasterElements(layoutPath) : [];
39601
+ this.currentSlideClrMapOverride = prevClrMapOverride;
37391
39602
  const allElements = [...masterElements, ...elements];
37392
39603
  this.layoutCache.set(layoutPath, allElements);
37393
39604
  return allElements;
@@ -37399,7 +39610,7 @@ var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
37399
39610
  };
37400
39611
 
37401
39612
  // src/core/core/runtime/PptxHandlerRuntimeThemeFormatScheme.ts
37402
- var PptxHandlerRuntime56 = class _PptxHandlerRuntime extends PptxHandlerRuntime55 {
39613
+ var PptxHandlerRuntime57 = class _PptxHandlerRuntime extends PptxHandlerRuntime56 {
37403
39614
  /**
37404
39615
  * Collect fill-style children from a style list node, preserving
37405
39616
  * document order. Handles `a:solidFill`, `a:gradFill`, `a:pattFill`,
@@ -37641,7 +39852,7 @@ var PptxHandlerRuntime56 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
37641
39852
  };
37642
39853
 
37643
39854
  // src/core/core/runtime/PptxHandlerRuntimeThemeOverrides.ts
37644
- var PptxHandlerRuntime57 = class extends PptxHandlerRuntime56 {
39855
+ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
37645
39856
  /**
37646
39857
  * Parse the `a:fmtScheme` element from the theme into a structured
37647
39858
  * {@link PptxThemeFormatScheme}. Each sub-list (fillStyleLst, lnStyleLst,
@@ -37838,8 +40049,10 @@ var PptxHandlerRuntime57 = class extends PptxHandlerRuntime56 {
37838
40049
  }
37839
40050
  const fontScheme = root["a:fontScheme"];
37840
40051
  if (fontScheme) {
37841
- const majorLatin = fontScheme["a:majorFont"]?.["a:latin"];
37842
- const minorLatin = fontScheme["a:minorFont"]?.["a:latin"];
40052
+ const majorFontNode = fontScheme["a:majorFont"];
40053
+ const minorFontNode = fontScheme["a:minorFont"];
40054
+ const majorLatin = majorFontNode?.["a:latin"];
40055
+ const minorLatin = minorFontNode?.["a:latin"];
37843
40056
  const majorFont = this.normalizeTypefaceToken(String(majorLatin?.["@_typeface"] || ""));
37844
40057
  const minorFont = this.normalizeTypefaceToken(String(minorLatin?.["@_typeface"] || ""));
37845
40058
  if (!result.colorOverrides) {
@@ -37862,13 +40075,46 @@ var PptxHandlerRuntime57 = class extends PptxHandlerRuntime56 {
37862
40075
  };
37863
40076
 
37864
40077
  // src/core/core/runtime/PptxHandlerRuntimeThemeRefResolution.ts
37865
- var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
40078
+ var COLOR_CHOICE_KEYS2 = [
40079
+ "a:scrgbClr",
40080
+ "a:srgbClr",
40081
+ "a:hslClr",
40082
+ "a:sysClr",
40083
+ "a:schemeClr",
40084
+ "a:prstClr"
40085
+ ];
40086
+ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
40087
+ /**
40088
+ * Pull the verbatim colour-choice child out of a style-matrix-reference
40089
+ * element (`a:lnRef`/`a:fillRef`/`a:effectRef`/`a:fontRef`). Returns the
40090
+ * full child object so it can be round-tripped at save time, preserving
40091
+ * any contained colour transforms (`a:lumMod`, `a:tint`, etc.).
40092
+ */
40093
+ extractRefColorXml(refNode) {
40094
+ if (!refNode) {
40095
+ return void 0;
40096
+ }
40097
+ for (const key of COLOR_CHOICE_KEYS2) {
40098
+ const child = refNode[key];
40099
+ if (child !== void 0) {
40100
+ return { [key]: child };
40101
+ }
40102
+ }
40103
+ return void 0;
40104
+ }
37866
40105
  /**
37867
40106
  * Resolve a `a:effectRef` element into concrete effect properties
37868
40107
  * by looking up `@_idx` in the theme format scheme's effect style list.
37869
40108
  */
37870
40109
  resolveThemeEffectRef(refNode, style) {
37871
40110
  const idx = parseInt(String(refNode["@_idx"] || "0"), 10);
40111
+ if (Number.isFinite(idx) && idx > 0) {
40112
+ style.effectRefIdx = idx;
40113
+ }
40114
+ const overrideColorXml = this.extractRefColorXml(refNode);
40115
+ if (overrideColorXml) {
40116
+ style.effectRefColorXml = overrideColorXml;
40117
+ }
37872
40118
  if (!Number.isFinite(idx) || idx <= 0 || !this.themeFormatScheme || idx > this.themeFormatScheme.effectStyles.length) {
37873
40119
  return;
37874
40120
  }
@@ -37921,6 +40167,13 @@ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
37921
40167
  resolveThemeLineRef(refNode, style) {
37922
40168
  const idx = parseInt(String(refNode["@_idx"] || "0"), 10);
37923
40169
  const overrideColor = this.parseColor(refNode);
40170
+ if (Number.isFinite(idx) && idx > 0) {
40171
+ style.lnRefIdx = idx;
40172
+ }
40173
+ const overrideColorXml = this.extractRefColorXml(refNode);
40174
+ if (overrideColorXml) {
40175
+ style.lnRefColorXml = overrideColorXml;
40176
+ }
37924
40177
  if (!Number.isFinite(idx) || idx <= 0 || !this.themeFormatScheme || idx > this.themeFormatScheme.lineStyles.length) {
37925
40178
  style.strokeColor = overrideColor;
37926
40179
  if (overrideColor) {
@@ -37992,6 +40245,13 @@ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
37992
40245
  */
37993
40246
  resolveThemeFillRef(refNode, style) {
37994
40247
  const idx = parseInt(String(refNode["@_idx"] || "0"), 10);
40248
+ if (Number.isFinite(idx) && idx > 0) {
40249
+ style.fillRefIdx = idx;
40250
+ }
40251
+ const overrideColorXml = this.extractRefColorXml(refNode);
40252
+ if (overrideColorXml) {
40253
+ style.fillRefColorXml = overrideColorXml;
40254
+ }
37995
40255
  if (!Number.isFinite(idx) || idx <= 0 || !this.themeFormatScheme) {
37996
40256
  style.fillMode = "theme";
37997
40257
  style.fillColor = this.parseColor(refNode);
@@ -38057,7 +40317,7 @@ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
38057
40317
  };
38058
40318
 
38059
40319
  // src/core/core/runtime/PptxHandlerRuntimeThemeLoading.ts
38060
- var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
40320
+ var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
38061
40321
  async resolvePrimaryThemePath() {
38062
40322
  const masterFiles = this.zip.file(/^ppt\/slideMasters\/slideMaster\d+\.xml$/);
38063
40323
  if (!masterFiles || masterFiles.length === 0) {
@@ -38167,62 +40427,97 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
38167
40427
  formatScheme: this.themeFormatScheme
38168
40428
  };
38169
40429
  }
38170
- async applySlideMasterColorMap(defaultMap) {
40430
+ /**
40431
+ * Parse every slide master's `<p:clrMap>` element and store the alias
40432
+ * dictionaries on {@link masterClrMaps}. Do *not* mutate
40433
+ * {@link themeColorMap} — alias resolution happens at colour-lookup
40434
+ * time so that:
40435
+ *
40436
+ * 1. The raw theme scheme stays the source of truth (clrMap is a
40437
+ * routing layer, not a colour table).
40438
+ * 2. Multi-master decks resolve each slide against its own master's
40439
+ * clrMap rather than always against `masterFiles[0]`.
40440
+ * 3. Layout `clrMapOvr` semantics work correctly when a slide's master
40441
+ * differs from the deck's first master.
40442
+ *
40443
+ * Phase 2 Stream B / C-H4.
40444
+ */
40445
+ async applySlideMasterColorMap(_defaultMap) {
38171
40446
  const masterFiles = this.zip.file(/^ppt\/slideMasters\/slideMaster\d+\.xml$/);
38172
40447
  if (!masterFiles || masterFiles.length === 0) {
38173
40448
  return;
38174
40449
  }
38175
- try {
38176
- const masterXml = await masterFiles[0].async("string");
38177
- const masterData = this.parser.parse(masterXml);
38178
- const clrMap = masterData?.["p:sldMaster"]?.["p:clrMap"];
38179
- if (!clrMap) {
38180
- return;
38181
- }
38182
- const aliasKeys = [
38183
- "bg1",
38184
- "tx1",
38185
- "bg2",
38186
- "tx2",
38187
- "accent1",
38188
- "accent2",
38189
- "accent3",
38190
- "accent4",
38191
- "accent5",
38192
- "accent6",
38193
- "hlink",
38194
- "folHlink"
38195
- ];
38196
- for (const aliasKey of aliasKeys) {
38197
- const mappedKey = String(clrMap[`@_${aliasKey}`] || "").trim().toLowerCase();
38198
- if (!mappedKey) {
40450
+ const aliasKeys = [
40451
+ "bg1",
40452
+ "tx1",
40453
+ "bg2",
40454
+ "tx2",
40455
+ "accent1",
40456
+ "accent2",
40457
+ "accent3",
40458
+ "accent4",
40459
+ "accent5",
40460
+ "accent6",
40461
+ "hlink",
40462
+ "folHlink"
40463
+ ];
40464
+ for (const file of masterFiles) {
40465
+ try {
40466
+ const masterXml = await file.async("string");
40467
+ const masterData = this.parser.parse(masterXml);
40468
+ const clrMap = masterData?.["p:sldMaster"]?.["p:clrMap"];
40469
+ if (!clrMap) {
38199
40470
  continue;
38200
40471
  }
38201
- const mappedColor = this.themeColorMap[mappedKey] || defaultMap[mappedKey];
38202
- if (mappedColor) {
38203
- this.themeColorMap[aliasKey] = mappedColor;
40472
+ const aliasMap = {};
40473
+ for (const aliasKey of aliasKeys) {
40474
+ const mappedKey = String(clrMap[`@_${aliasKey}`] || "").trim().toLowerCase();
40475
+ if (mappedKey) {
40476
+ aliasMap[aliasKey] = mappedKey;
40477
+ }
40478
+ }
40479
+ if (Object.keys(aliasMap).length > 0) {
40480
+ this.masterClrMaps.set(file.name, aliasMap);
38204
40481
  }
40482
+ } catch (error) {
40483
+ console.warn(`Failed to parse slide master color map for ${file.name}:`, error);
38205
40484
  }
38206
- } catch (error) {
38207
- console.warn("Failed to parse slide master color map:", error);
38208
40485
  }
38209
40486
  }
38210
- async loadThemeData() {
38211
- const themeFiles = this.zip.file(/^ppt\/theme\/theme\d+\.xml$/);
38212
- if (!themeFiles || themeFiles.length === 0) {
38213
- return;
40487
+ /**
40488
+ * Parse a single theme part into structured colour, font, and format
40489
+ * scheme dictionaries. Used both for the global default theme and for
40490
+ * each master's per-master theme (multi-master support).
40491
+ *
40492
+ * Phase 2 Stream B / C-H4.
40493
+ */
40494
+ async parseThemePart(themePath) {
40495
+ const themeFile = this.zip.file(themePath);
40496
+ if (!themeFile) {
40497
+ return null;
38214
40498
  }
38215
- const preferredThemePath = await this.resolvePrimaryThemePath();
38216
- const preferredThemeFile = preferredThemePath ? themeFiles.find((file) => file.name === preferredThemePath) : void 0;
38217
- const themeFile = preferredThemeFile ?? themeFiles[0];
38218
40499
  const themeXml2 = await themeFile.async("string");
40500
+ this.originalThemeXmlByPath.set(themePath, themeXml2);
38219
40501
  const themeData = this.parser.parse(themeXml2);
38220
40502
  const themeRoot = themeData["a:theme"];
38221
40503
  const themeElements = themeRoot?.["a:themeElements"];
38222
40504
  const colorScheme = themeElements?.["a:clrScheme"];
38223
40505
  const fontScheme = themeElements?.["a:fontScheme"];
40506
+ const fmtScheme = themeElements?.["a:fmtScheme"];
40507
+ const themeName = String(themeRoot?.["@_name"] || "").trim();
40508
+ if (themeName) {
40509
+ this.masterThemeNames.set(themePath, themeName);
40510
+ }
40511
+ const colorSchemeName = String(colorScheme?.["@_name"] || "").trim();
40512
+ if (colorSchemeName) {
40513
+ this.masterThemeColorSchemeNames.set(themePath, colorSchemeName);
40514
+ }
40515
+ const fontSchemeName = String(fontScheme?.["@_name"] || "").trim();
40516
+ if (fontSchemeName) {
40517
+ this.masterThemeFontSchemeNames.set(themePath, fontSchemeName);
40518
+ }
38224
40519
  const defaultMap = this.getDefaultSchemeColorMap();
38225
- this.themeColorMap = { ...defaultMap };
40520
+ const colorMap = { ...defaultMap };
38226
40521
  if (colorScheme) {
38227
40522
  const schemeKeys = [
38228
40523
  "dk1",
@@ -38242,39 +40537,196 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
38242
40537
  const colorNode = colorScheme[`a:${key}`];
38243
40538
  const parsed = this.parseColorChoice(colorNode);
38244
40539
  if (parsed) {
38245
- this.themeColorMap[key] = parsed;
40540
+ colorMap[key] = parsed;
38246
40541
  }
38247
40542
  }
38248
40543
  }
38249
- this.themeColorMap["tx1"] = this.themeColorMap["dk1"] || defaultMap["dk1"];
38250
- this.themeColorMap["bg1"] = this.themeColorMap["lt1"] || defaultMap["lt1"];
38251
- this.themeColorMap["tx2"] = this.themeColorMap["dk2"] || defaultMap["dk2"];
38252
- this.themeColorMap["bg2"] = this.themeColorMap["lt2"] || defaultMap["lt2"];
38253
- await this.applySlideMasterColorMap(defaultMap);
38254
- const majorLatin = fontScheme?.["a:majorFont"]?.["a:latin"];
38255
- const minorLatin = fontScheme?.["a:minorFont"]?.["a:latin"];
40544
+ colorMap["tx1"] = colorMap["dk1"] || defaultMap["dk1"];
40545
+ colorMap["bg1"] = colorMap["lt1"] || defaultMap["lt1"];
40546
+ colorMap["tx2"] = colorMap["dk2"] || defaultMap["dk2"];
40547
+ colorMap["bg2"] = colorMap["lt2"] || defaultMap["lt2"];
40548
+ const majorFontNode = fontScheme?.["a:majorFont"];
40549
+ const minorFontNode = fontScheme?.["a:minorFont"];
40550
+ const majorLatin = majorFontNode?.["a:latin"];
40551
+ const minorLatin = minorFontNode?.["a:latin"];
38256
40552
  const majorFont = this.normalizeTypefaceToken(String(majorLatin?.["@_typeface"] || ""));
38257
40553
  const minorFont = this.normalizeTypefaceToken(String(minorLatin?.["@_typeface"] || ""));
38258
- this.themeFontMap = {};
40554
+ const fontMap = {};
38259
40555
  if (majorFont) {
38260
- this.themeFontMap["mj-lt"] = majorFont;
38261
- this.themeFontMap["mj-ea"] = majorFont;
38262
- this.themeFontMap["mj-cs"] = majorFont;
40556
+ fontMap["mj-lt"] = majorFont;
40557
+ fontMap["mj-ea"] = majorFont;
40558
+ fontMap["mj-cs"] = majorFont;
38263
40559
  }
38264
40560
  if (minorFont) {
38265
- this.themeFontMap["mn-lt"] = minorFont;
38266
- this.themeFontMap["mn-ea"] = minorFont;
38267
- this.themeFontMap["mn-cs"] = minorFont;
40561
+ fontMap["mn-lt"] = minorFont;
40562
+ fontMap["mn-ea"] = minorFont;
40563
+ fontMap["mn-cs"] = minorFont;
38268
40564
  }
38269
- const fmtScheme = themeElements?.["a:fmtScheme"];
38270
- if (fmtScheme) {
38271
- this.themeFormatScheme = this.parseFormatScheme(fmtScheme);
40565
+ const majorEa = this.normalizeTypefaceToken(
40566
+ String(majorFontNode?.["a:ea"]?.["@_typeface"] || "")
40567
+ );
40568
+ if (majorEa) {
40569
+ fontMap["mj-ea"] = majorEa;
40570
+ }
40571
+ const majorCs = this.normalizeTypefaceToken(
40572
+ String(majorFontNode?.["a:cs"]?.["@_typeface"] || "")
40573
+ );
40574
+ if (majorCs) {
40575
+ fontMap["mj-cs"] = majorCs;
40576
+ }
40577
+ const minorEa = this.normalizeTypefaceToken(
40578
+ String(minorFontNode?.["a:ea"]?.["@_typeface"] || "")
40579
+ );
40580
+ if (minorEa) {
40581
+ fontMap["mn-ea"] = minorEa;
40582
+ }
40583
+ const minorCs = this.normalizeTypefaceToken(
40584
+ String(minorFontNode?.["a:cs"]?.["@_typeface"] || "")
40585
+ );
40586
+ if (minorCs) {
40587
+ fontMap["mn-cs"] = minorCs;
40588
+ }
40589
+ const majorScripts = this.collectFontScriptOverrides(majorFontNode);
40590
+ if (Object.keys(majorScripts).length > 0) {
40591
+ this.masterThemeMajorFontScripts.set(themePath, majorScripts);
40592
+ }
40593
+ const minorScripts = this.collectFontScriptOverrides(minorFontNode);
40594
+ if (Object.keys(minorScripts).length > 0) {
40595
+ this.masterThemeMinorFontScripts.set(themePath, minorScripts);
40596
+ }
40597
+ const objectDefaultsNode = themeRoot?.["a:objectDefaults"];
40598
+ if (objectDefaultsNode) {
40599
+ const od = {
40600
+ spDef: objectDefaultsNode["a:spDef"],
40601
+ lnDef: objectDefaultsNode["a:lnDef"],
40602
+ txDef: objectDefaultsNode["a:txDef"]
40603
+ };
40604
+ if (od.spDef !== void 0 || od.lnDef !== void 0 || od.txDef !== void 0) {
40605
+ this.masterThemeObjectDefaults.set(themePath, od);
40606
+ }
40607
+ }
40608
+ const extraClrSchemeLst = themeRoot?.["a:extraClrSchemeLst"];
40609
+ if (extraClrSchemeLst !== void 0) {
40610
+ this.masterThemeExtraClrSchemeLst.set(themePath, extraClrSchemeLst);
40611
+ }
40612
+ const custClrLst = themeRoot?.["a:custClrLst"];
40613
+ if (custClrLst !== void 0) {
40614
+ this.masterThemeCustClrLst.set(themePath, custClrLst);
40615
+ }
40616
+ const themeExtLst = themeRoot?.["a:extLst"];
40617
+ if (themeExtLst !== void 0) {
40618
+ this.masterThemeExtLst.set(themePath, themeExtLst);
40619
+ }
40620
+ const formatScheme = fmtScheme ? this.parseFormatScheme(fmtScheme) : void 0;
40621
+ return { colorMap, fontMap, formatScheme };
40622
+ }
40623
+ /**
40624
+ * Parse `<a:font script="…" typeface="…"/>` children of a major or
40625
+ * minor font node into a `script -> typeface` dictionary.
40626
+ *
40627
+ * fast-xml-parser collapses repeated tags into arrays, so iterate
40628
+ * over the array form regardless of how many siblings are present.
40629
+ *
40630
+ * Phase 4 Stream A / M4.
40631
+ */
40632
+ collectFontScriptOverrides(fontNode) {
40633
+ const overrides = {};
40634
+ if (!fontNode) {
40635
+ return overrides;
40636
+ }
40637
+ const fontEntries = this.ensureArray(fontNode["a:font"]);
40638
+ for (const entry of fontEntries) {
40639
+ const script = String(entry?.["@_script"] || "").trim();
40640
+ const typeface = this.normalizeTypefaceToken(String(entry?.["@_typeface"] || ""));
40641
+ if (script && typeface) {
40642
+ overrides[script] = typeface;
40643
+ }
40644
+ }
40645
+ return overrides;
40646
+ }
40647
+ /**
40648
+ * Resolve the theme file path referenced by a given master's `.rels`.
40649
+ * Returns `undefined` when the master has no theme relationship.
40650
+ */
40651
+ async resolveThemePathForMaster(masterPath) {
40652
+ const relsPath = masterPath.replace(
40653
+ /ppt\/slideMasters\/(slideMaster\d+)\.xml/,
40654
+ "ppt/slideMasters/_rels/$1.xml.rels"
40655
+ );
40656
+ const relsXml = this.zip.file(relsPath);
40657
+ if (!relsXml) {
40658
+ return void 0;
40659
+ }
40660
+ const relsData = this.parser.parse(await relsXml.async("string"));
40661
+ const relNodes = this.ensureArray(relsData?.Relationships?.Relationship);
40662
+ for (const rel of relNodes) {
40663
+ const target = String(rel["@_Target"] || "");
40664
+ if (!target.includes("theme")) {
40665
+ continue;
40666
+ }
40667
+ const themePath = target.startsWith("..") ? this.resolvePath(masterPath.substring(0, masterPath.lastIndexOf("/") + 1), target) : target.startsWith("/") ? target.slice(1) : `ppt/${target.replace(/^\.?\//, "")}`;
40668
+ if (themePath.startsWith("ppt/theme/")) {
40669
+ return themePath;
40670
+ }
40671
+ }
40672
+ return void 0;
40673
+ }
40674
+ /**
40675
+ * Populate {@link masterThemeColorMaps}, {@link masterThemeFontMaps},
40676
+ * and {@link masterThemeFormatSchemes} for every slide master in the
40677
+ * deck. Multi-master support — Phase 2 Stream B / C-H4.
40678
+ */
40679
+ async loadPerMasterThemes() {
40680
+ const masterFiles = this.zip.file(/^ppt\/slideMasters\/slideMaster\d+\.xml$/);
40681
+ if (!masterFiles || masterFiles.length === 0) {
40682
+ return;
40683
+ }
40684
+ for (const file of masterFiles) {
40685
+ try {
40686
+ const themePath = await this.resolveThemePathForMaster(file.name);
40687
+ if (!themePath) {
40688
+ continue;
40689
+ }
40690
+ this.masterThemePaths.set(file.name, themePath);
40691
+ const parsed = await this.parseThemePart(themePath);
40692
+ if (!parsed) {
40693
+ continue;
40694
+ }
40695
+ this.masterThemeColorMaps.set(file.name, parsed.colorMap);
40696
+ this.masterThemeFontMaps.set(file.name, parsed.fontMap);
40697
+ if (parsed.formatScheme) {
40698
+ this.masterThemeFormatSchemes.set(file.name, parsed.formatScheme);
40699
+ }
40700
+ } catch (error) {
40701
+ console.warn(`Failed to load per-master theme for ${file.name}:`, error);
40702
+ }
40703
+ }
40704
+ }
40705
+ async loadThemeData() {
40706
+ const themeFiles = this.zip.file(/^ppt\/theme\/theme\d+\.xml$/);
40707
+ if (!themeFiles || themeFiles.length === 0) {
40708
+ return;
38272
40709
  }
40710
+ const preferredThemePath = await this.resolvePrimaryThemePath();
40711
+ const themeFile = preferredThemePath ? themeFiles.find((file) => file.name === preferredThemePath) ?? themeFiles[0] : themeFiles[0];
40712
+ const parsed = await this.parseThemePart(themeFile.name);
40713
+ if (parsed) {
40714
+ this.themeColorMap = parsed.colorMap;
40715
+ this.themeFontMap = parsed.fontMap;
40716
+ if (parsed.formatScheme) {
40717
+ this.themeFormatScheme = parsed.formatScheme;
40718
+ }
40719
+ }
40720
+ await this.applySlideMasterColorMap(this.getDefaultSchemeColorMap());
40721
+ await this.loadPerMasterThemes();
40722
+ this.globalThemeColorMapSnapshot = { ...this.themeColorMap };
40723
+ this.globalThemeFontMapSnapshot = { ...this.themeFontMap };
40724
+ this.globalThemeFormatSchemeSnapshot = this.themeFormatScheme;
38273
40725
  }
38274
40726
  };
38275
40727
 
38276
40728
  // src/core/core/runtime/PptxHandlerRuntimeThemeProcessing.ts
38277
- var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
40729
+ var PptxHandlerRuntime61 = class extends PptxHandlerRuntime60 {
38278
40730
  // ---------------------------------------------------------------------------
38279
40731
  // Theme editing — update colour scheme, font scheme, and name in the zip
38280
40732
  // ---------------------------------------------------------------------------
@@ -38424,7 +40876,7 @@ var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
38424
40876
  };
38425
40877
 
38426
40878
  // src/core/core/runtime/PptxHandlerRuntimeComments.ts
38427
- var PptxHandlerRuntime61 = class _PptxHandlerRuntime extends PptxHandlerRuntime60 {
40879
+ var PptxHandlerRuntime62 = class _PptxHandlerRuntime extends PptxHandlerRuntime61 {
38428
40880
  /**
38429
40881
  * Parse modern threaded comments (PowerPoint 2019+ / Office 365).
38430
40882
  * Modern comments use `p188:cmLst`/`p15:cmLst` roots within
@@ -38657,7 +41109,7 @@ var PptxHandlerRuntime61 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
38657
41109
  };
38658
41110
 
38659
41111
  // src/core/core/runtime/PptxHandlerRuntimeSmartArtXmlUtils.ts
38660
- var PptxHandlerRuntime62 = class extends PptxHandlerRuntime61 {
41112
+ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
38661
41113
  async readXmlPartByRelationshipId(slidePath, relationshipId) {
38662
41114
  const normalizedRelationshipId = String(relationshipId || "").trim();
38663
41115
  if (normalizedRelationshipId.length === 0) {
@@ -38812,7 +41264,7 @@ var PptxHandlerRuntime62 = class extends PptxHandlerRuntime61 {
38812
41264
  };
38813
41265
 
38814
41266
  // src/core/core/runtime/PptxHandlerRuntimeSmartArtParsing.ts
38815
- var PptxHandlerRuntime63 = class _PptxHandlerRuntime extends PptxHandlerRuntime62 {
41267
+ var PptxHandlerRuntime64 = class _PptxHandlerRuntime extends PptxHandlerRuntime63 {
38816
41268
  /**
38817
41269
  * Parse quick style from `ppt/diagrams/quickStyles*.xml`.
38818
41270
  */
@@ -38971,7 +41423,7 @@ var PptxHandlerRuntime63 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
38971
41423
  };
38972
41424
 
38973
41425
  // src/core/core/runtime/PptxHandlerRuntimeSmartArt.ts
38974
- var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
41426
+ var PptxHandlerRuntime65 = class _PptxHandlerRuntime extends PptxHandlerRuntime64 {
38975
41427
  async getSmartArtDataForGraphicFrame(slidePath, graphicFrame) {
38976
41428
  const graphicData = this.xmlLookupService.getChildByLocalName(
38977
41429
  this.xmlLookupService.getChildByLocalName(graphicFrame, "graphic"),
@@ -39022,10 +41474,14 @@ var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
39022
41474
  const layoutPart = layoutRelationshipId.length > 0 ? await this.readXmlPartByRelationshipId(slidePath, layoutRelationshipId) : void 0;
39023
41475
  const layoutType = layoutPart?.partPath?.split("/").pop()?.replace(/\.[^.]+$/, "") || void 0;
39024
41476
  const chrome = this.parseSmartArtChrome(dataModel);
39025
- const drawingRelationshipId = String(relationshipIds["@_r:cs"] || "").trim();
39026
- const drawingShapes = await this.parseSmartArtDrawingShapes(slidePath, drawingRelationshipId);
39027
41477
  const colorsRelationshipId = String(relationshipIds["@_r:cs"] || "").trim();
39028
41478
  const colorTransform = await this.parseSmartArtColorTransform(slidePath, colorsRelationshipId);
41479
+ const drawingResolution = await this.resolveSmartArtDrawingPart(
41480
+ slidePath,
41481
+ diagramDataRelationshipId
41482
+ );
41483
+ const drawingShapes = drawingResolution ? await this.parseSmartArtDrawingShapesFromPath(drawingResolution.path) : [];
41484
+ const drawingRelationshipId = drawingResolution?.relId;
39029
41485
  const styleRelationshipId = String(relationshipIds["@_r:qs"] || "").trim();
39030
41486
  const quickStyle = await this.parseSmartArtQuickStyle(slidePath, styleRelationshipId);
39031
41487
  return {
@@ -39037,11 +41493,87 @@ var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
39037
41493
  colorTransform,
39038
41494
  quickStyle,
39039
41495
  dataRelId: diagramDataRelationshipId,
39040
- drawingRelId: drawingRelationshipId.length > 0 ? drawingRelationshipId : void 0,
41496
+ drawingRelId: drawingRelationshipId && drawingRelationshipId.length > 0 ? drawingRelationshipId : void 0,
39041
41497
  colorsRelId: colorsRelationshipId.length > 0 ? colorsRelationshipId : void 0,
39042
41498
  styleRelId: styleRelationshipId.length > 0 ? styleRelationshipId : void 0
39043
41499
  };
39044
41500
  }
41501
+ /**
41502
+ * Resolve the SmartArt drawing-shapes part path + relationship id.
41503
+ *
41504
+ * Strategy:
41505
+ * 1. Locate the data-model part's rels file
41506
+ * (`ppt/diagrams/_rels/data*.xml.rels`) via `slideRelsMap`.
41507
+ * 2. Find a relationship whose `Type` matches the `…/diagramDrawing`
41508
+ * URI. PowerPoint emits this for any deck that has had its
41509
+ * SmartArt rendered to drawing shapes.
41510
+ * 3. Return the matched part path (so the caller can load it
41511
+ * directly) and the relationship id (for round-trip preservation).
41512
+ */
41513
+ async resolveSmartArtDrawingPart(slidePath, diagramDataRelationshipId) {
41514
+ if (diagramDataRelationshipId.length === 0) {
41515
+ return void 0;
41516
+ }
41517
+ const slideRels = this.slideRelsMap.get(slidePath);
41518
+ const dataTarget = slideRels?.get(diagramDataRelationshipId);
41519
+ if (!dataTarget) {
41520
+ return void 0;
41521
+ }
41522
+ const dataPath = this.resolveImagePath(slidePath, dataTarget);
41523
+ const dataDir = dataPath.replace(/\/[^/]+$/, "");
41524
+ const dataFile = dataPath.split("/").pop() ?? "";
41525
+ const dataRelsPath = `${dataDir}/_rels/${dataFile}.rels`;
41526
+ const relsXml = await this.zip.file(dataRelsPath)?.async("string");
41527
+ if (!relsXml) {
41528
+ return void 0;
41529
+ }
41530
+ try {
41531
+ const parsed = this.parser.parse(relsXml);
41532
+ const relsRoot = parsed["Relationships"];
41533
+ if (!relsRoot) {
41534
+ return void 0;
41535
+ }
41536
+ const rels = this.ensureArray(relsRoot["Relationship"]);
41537
+ const drawingRel = rels.find(
41538
+ (rel) => String(rel?.["@_Type"] || "").endsWith("/diagramDrawing")
41539
+ );
41540
+ const id = String(drawingRel?.["@_Id"] || "").trim();
41541
+ const target = String(drawingRel?.["@_Target"] || "").trim();
41542
+ if (id.length === 0 || target.length === 0) {
41543
+ return void 0;
41544
+ }
41545
+ const drawingPath = this.resolveImagePath(dataPath, target);
41546
+ return { relId: id, path: drawingPath };
41547
+ } catch {
41548
+ return void 0;
41549
+ }
41550
+ }
41551
+ /**
41552
+ * Parse SmartArt drawing shapes given an absolute part path.
41553
+ *
41554
+ * Wraps `parseSmartArtDrawingShapes` (which expects a slide-relative
41555
+ * relationship id) with a path-based lookup so the resolution layer
41556
+ * can pull the part from anywhere in the package.
41557
+ */
41558
+ async parseSmartArtDrawingShapesFromPath(drawingPath) {
41559
+ const xmlString = await this.zip.file(drawingPath)?.async("string");
41560
+ if (!xmlString) {
41561
+ return [];
41562
+ }
41563
+ try {
41564
+ const xml = this.parser.parse(xmlString);
41565
+ const drawing = this.xmlLookupService.getChildByLocalName(xml, "drawing");
41566
+ const spTree = this.xmlLookupService.getChildByLocalName(drawing || xml, "spTree");
41567
+ if (!spTree) {
41568
+ return [];
41569
+ }
41570
+ const shapes = this.xmlLookupService.getChildrenArrayByLocalName(spTree, "sp");
41571
+ const emuPerPx = _PptxHandlerRuntime.EMU_PER_PX;
41572
+ return shapes.map((sp, index) => this.parseDrawingShape(sp, index, emuPerPx)).filter((entry) => entry !== null);
41573
+ } catch {
41574
+ return [];
41575
+ }
41576
+ }
39045
41577
  parseSmartArtConnections(dataModel) {
39046
41578
  const connectionList = this.xmlLookupService.getChildByLocalName(dataModel, "cxnLst");
39047
41579
  const rawConnections = this.xmlLookupService.getChildrenArrayByLocalName(connectionList, "cxn");
@@ -39072,7 +41604,7 @@ var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
39072
41604
  };
39073
41605
 
39074
41606
  // src/core/core/runtime/PptxHandlerRuntimeChartDetection.ts
39075
- var PptxHandlerRuntime65 = class extends PptxHandlerRuntime64 {
41607
+ var PptxHandlerRuntime66 = class extends PptxHandlerRuntime65 {
39076
41608
  detectChartType(plotArea) {
39077
41609
  if (!plotArea) {
39078
41610
  return "unknown";
@@ -39181,7 +41713,7 @@ var PptxHandlerRuntime65 = class extends PptxHandlerRuntime64 {
39181
41713
  };
39182
41714
 
39183
41715
  // src/core/core/runtime/PptxHandlerRuntimeChartParsingHelpers.ts
39184
- var PptxHandlerRuntime66 = class extends PptxHandlerRuntime65 {
41716
+ var PptxHandlerRuntime67 = class extends PptxHandlerRuntime66 {
39185
41717
  /**
39186
41718
  * Parse `c:plotVisOnly` from the chart root element.
39187
41719
  *
@@ -39242,7 +41774,7 @@ var PptxHandlerRuntime66 = class extends PptxHandlerRuntime65 {
39242
41774
  };
39243
41775
 
39244
41776
  // src/core/core/runtime/PptxHandlerRuntimeChartExternalData.ts
39245
- var PptxHandlerRuntime67 = class extends PptxHandlerRuntime66 {
41777
+ var PptxHandlerRuntime68 = class extends PptxHandlerRuntime67 {
39246
41778
  /**
39247
41779
  * Parse `c:externalData` from the chart's `c:chartSpace` and resolve
39248
41780
  * the external relationship target from the chart part's .rels file.
@@ -39358,7 +41890,7 @@ var PptxHandlerRuntime67 = class extends PptxHandlerRuntime66 {
39358
41890
  };
39359
41891
 
39360
41892
  // src/core/core/runtime/PptxHandlerRuntimeChartColorStyle.ts
39361
- var PptxHandlerRuntime68 = class extends PptxHandlerRuntime67 {
41893
+ var PptxHandlerRuntime69 = class extends PptxHandlerRuntime68 {
39362
41894
  /**
39363
41895
  * Parse the Office 2013+ chart color style part (`chartColorStyle*.xml`)
39364
41896
  * referenced from the chart's relationships.
@@ -39465,7 +41997,7 @@ var PptxHandlerRuntime68 = class extends PptxHandlerRuntime67 {
39465
41997
  };
39466
41998
 
39467
41999
  // src/core/core/runtime/PptxHandlerRuntimeChartParsing.ts
39468
- var PptxHandlerRuntime69 = class extends PptxHandlerRuntime68 {
42000
+ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
39469
42001
  /**
39470
42002
  * Parse chart data from a graphic frame element on a slide.
39471
42003
  *
@@ -39712,7 +42244,7 @@ var PptxHandlerRuntime69 = class extends PptxHandlerRuntime68 {
39712
42244
  };
39713
42245
 
39714
42246
  // src/core/core/runtime/PptxHandlerRuntimePresentationStructure.ts
39715
- var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
42247
+ var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
39716
42248
  parseEditorAnimations(slideXml2) {
39717
42249
  return this.editorAnimationService.parseEditorAnimations(slideXml2);
39718
42250
  }
@@ -39957,7 +42489,7 @@ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
39957
42489
  };
39958
42490
 
39959
42491
  // src/core/core/runtime/PptxHandlerRuntimeEmbeddedFonts.ts
39960
- var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
42492
+ var PptxHandlerRuntime72 = class extends PptxHandlerRuntime71 {
39961
42493
  async getEmbeddedFonts() {
39962
42494
  const embeddedFontEntries = this.ensureArray(
39963
42495
  this.presentationData?.["p:presentation"]?.["p:embeddedFontLst"]?.["p:embeddedFont"]
@@ -40129,7 +42661,7 @@ var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
40129
42661
  };
40130
42662
 
40131
42663
  // src/core/core/runtime/PptxHandlerRuntimeLoadSession.ts
40132
- var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime71 {
42664
+ var PptxHandlerRuntime73 = class _PptxHandlerRuntime extends PptxHandlerRuntime72 {
40133
42665
  isZipContainer(data) {
40134
42666
  const bytes = new Uint8Array(data);
40135
42667
  if (bytes.byteLength < 4) {
@@ -40172,6 +42704,23 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40172
42704
  this.imageDataCache.clear();
40173
42705
  this.themeColorMap = {};
40174
42706
  this.themeFontMap = {};
42707
+ this.masterClrMaps.clear();
42708
+ this.masterThemeColorMaps.clear();
42709
+ this.masterThemeFontMaps.clear();
42710
+ this.masterThemeFormatSchemes.clear();
42711
+ this.masterThemePaths.clear();
42712
+ this.masterThemeMajorFontScripts.clear();
42713
+ this.masterThemeMinorFontScripts.clear();
42714
+ this.masterThemeNames.clear();
42715
+ this.masterThemeFontSchemeNames.clear();
42716
+ this.masterThemeColorSchemeNames.clear();
42717
+ this.originalThemeXmlByPath.clear();
42718
+ this.dirtyThemePaths.clear();
42719
+ this.masterThemeObjectDefaults.clear();
42720
+ this.masterThemeExtraClrSchemeLst.clear();
42721
+ this.masterThemeCustClrLst.clear();
42722
+ this.masterThemeExtLst.clear();
42723
+ this.currentMasterClrMap = null;
40175
42724
  this.presentationDefaultTextStyle = void 0;
40176
42725
  this.commentAuthorMap.clear();
40177
42726
  this.commentAuthorDetails.clear();
@@ -40326,6 +42875,7 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40326
42875
  setCurrentSlideClrMapOverride: (override) => {
40327
42876
  this.currentSlideClrMapOverride = override;
40328
42877
  },
42878
+ setActiveMasterForSlide: (slidePath) => this.setActiveMasterForSlide(slidePath),
40329
42879
  findLayoutPathForSlide: (slidePath) => this.findLayoutPathForSlide(slidePath),
40330
42880
  loadThemeOverride: (partBasePath) => this.loadThemeOverride(partBasePath),
40331
42881
  applyThemeOverrideState: (override) => this.applyThemeOverrideState(override),
@@ -40356,7 +42906,7 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40356
42906
  };
40357
42907
 
40358
42908
  // src/core/core/runtime/PptxHandlerRuntimeLoadPipeline.ts
40359
- var PptxHandlerRuntime73 = class extends PptxHandlerRuntime72 {
42909
+ var PptxHandlerRuntime74 = class extends PptxHandlerRuntime73 {
40360
42910
  async buildLoadData(presentationState, slidesWithWarnings) {
40361
42911
  const headerFooter = this.extractHeaderFooter();
40362
42912
  const presentationProperties = await this.parsePresentationProperties();
@@ -40368,6 +42918,7 @@ var PptxHandlerRuntime73 = class extends PptxHandlerRuntime72 {
40368
42918
  const notesMaster = await this.parseNotesMaster();
40369
42919
  const handoutMaster = await this.parseHandoutMaster();
40370
42920
  const slideMasters = await this.parseSlideMasters();
42921
+ await this.enrichSlideMastersWithTxStyles(slideMasters);
40371
42922
  const tags = await this.parseTags();
40372
42923
  const customProperties = await this.parseCustomProperties();
40373
42924
  const coreProperties = await this.parseCoreProperties();
@@ -40702,7 +43253,7 @@ var PptxHandlerRuntime73 = class extends PptxHandlerRuntime72 {
40702
43253
  };
40703
43254
 
40704
43255
  // src/core/core/runtime/PptxHandlerRuntimeImplementation.ts
40705
- var PptxHandlerRuntime74 = class _PptxHandlerRuntime extends PptxHandlerRuntime73 {
43256
+ var PptxHandlerRuntime75 = class _PptxHandlerRuntime extends PptxHandlerRuntime74 {
40706
43257
  constructor(dependencyFactory = new PptxRuntimeDependencyFactory()) {
40707
43258
  super();
40708
43259
  this.dependencyFactory = dependencyFactory;
@@ -40750,6 +43301,9 @@ var PptxHandlerRuntime74 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40750
43301
  extractGradientPathType: (gradFill) => this.colorStyleCodec.extractGradientPathType(gradFill),
40751
43302
  extractGradientFocalPoint: (gradFill) => this.colorStyleCodec.extractGradientFocalPoint(gradFill),
40752
43303
  extractGradientFillToRect: (gradFill) => this.colorStyleCodec.extractGradientFillToRect(gradFill),
43304
+ extractGradientFlip: (gradFill) => this.colorStyleCodec.extractGradientFlip(gradFill),
43305
+ extractGradientRotWithShape: (gradFill) => this.colorStyleCodec.extractGradientRotWithShape(gradFill),
43306
+ extractGradientScaled: (gradFill) => this.colorStyleCodec.extractGradientScaled(gradFill),
40753
43307
  normalizeStrokeDashType: (value) => this.normalizeStrokeDashType(value),
40754
43308
  normalizeConnectorArrowType: (value) => this.normalizeConnectorArrowType(value),
40755
43309
  ensureArray: (value) => this.ensureArray(value),
@@ -40823,7 +43377,7 @@ var PptxHandlerRuntime74 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40823
43377
  };
40824
43378
 
40825
43379
  // src/core/core/PptxHandlerRuntime.ts
40826
- var PptxHandlerRuntime75 = class extends PptxHandlerRuntime74 {
43380
+ var PptxHandlerRuntime76 = class extends PptxHandlerRuntime75 {
40827
43381
  };
40828
43382
 
40829
43383
  // src/core/core/PptxHandlerRuntimeFactory.ts
@@ -40834,10 +43388,10 @@ var PptxHandlerRuntimeFactory = class {
40834
43388
  * @returns A freshly constructed runtime ready for loading a PPTX file.
40835
43389
  */
40836
43390
  createRuntime() {
40837
- return new PptxHandlerRuntime75();
43391
+ return new PptxHandlerRuntime76();
40838
43392
  }
40839
43393
  };
40840
- var createDefaultPptxHandlerRuntime = () => new PptxHandlerRuntime75();
43394
+ var createDefaultPptxHandlerRuntime = () => new PptxHandlerRuntime76();
40841
43395
 
40842
43396
  // src/core/PptxHandlerCore.ts
40843
43397
  var PptxHandlerCore = class {
@@ -42207,10 +44761,12 @@ function getConnectorPathGeometry(element) {
42207
44761
  const height = Math.max(element.height, 1);
42208
44762
  const normalizedType = (element.shapeType || "").toLowerCase();
42209
44763
  const point = (x, y) => `${Math.round(x)} ${Math.round(y)}`;
42210
- const startX = 0;
42211
- const startY = 0;
42212
- const endX = width;
42213
- const endY = height;
44764
+ const flipH = Boolean(element.flipHorizontal);
44765
+ const flipV = Boolean(element.flipVertical);
44766
+ const startX = flipH ? width : 0;
44767
+ const startY = flipV ? height : 0;
44768
+ const endX = flipH ? 0 : width;
44769
+ const endY = flipV ? 0 : height;
42214
44770
  if (normalizedType.includes("bentconnector5")) {
42215
44771
  const adj1 = getConnectorAdjustment(element, "adj1", 0.5);
42216
44772
  const adj2 = getConnectorAdjustment(element, "adj2", 0.5);
@@ -42223,7 +44779,7 @@ function getConnectorPathGeometry(element) {
42223
44779
  startY,
42224
44780
  endX,
42225
44781
  endY,
42226
- pathData: `M ${point(0, 0)} L ${point(x1, 0)} L ${point(x1, yMid)} L ${point(x2, yMid)} L ${point(x2, height)} L ${point(width, height)}`
44782
+ pathData: `M ${point(startX, startY)} L ${point(x1, startY)} L ${point(x1, yMid)} L ${point(x2, yMid)} L ${point(x2, endY)} L ${point(endX, endY)}`
42227
44783
  };
42228
44784
  }
42229
44785
  if (normalizedType.includes("bentconnector4")) {
@@ -42236,7 +44792,7 @@ function getConnectorPathGeometry(element) {
42236
44792
  startY,
42237
44793
  endX,
42238
44794
  endY,
42239
- pathData: `M ${point(0, 0)} L ${point(midX, 0)} L ${point(midX, midY)} L ${point(width, midY)} L ${point(width, height)}`
44795
+ pathData: `M ${point(startX, startY)} L ${point(midX, startY)} L ${point(midX, midY)} L ${point(endX, midY)} L ${point(endX, endY)}`
42240
44796
  };
42241
44797
  }
42242
44798
  if (normalizedType.includes("bentconnector3")) {
@@ -42247,7 +44803,7 @@ function getConnectorPathGeometry(element) {
42247
44803
  startY,
42248
44804
  endX,
42249
44805
  endY,
42250
- pathData: `M ${point(0, 0)} L ${point(midX, 0)} L ${point(midX, height)} L ${point(width, height)}`
44806
+ pathData: `M ${point(startX, startY)} L ${point(midX, startY)} L ${point(midX, endY)} L ${point(endX, endY)}`
42251
44807
  };
42252
44808
  }
42253
44809
  if (normalizedType.includes("bentconnector2")) {
@@ -42256,7 +44812,7 @@ function getConnectorPathGeometry(element) {
42256
44812
  startY,
42257
44813
  endX,
42258
44814
  endY,
42259
- pathData: `M ${point(0, 0)} L ${point(width, 0)} L ${point(width, height)}`
44815
+ pathData: `M ${point(startX, startY)} L ${point(endX, startY)} L ${point(endX, endY)}`
42260
44816
  };
42261
44817
  }
42262
44818
  if (normalizedType.includes("curvedconnector5")) {
@@ -42266,12 +44822,14 @@ function getConnectorPathGeometry(element) {
42266
44822
  const x1 = width * adj1;
42267
44823
  const yMid = height * adj2;
42268
44824
  const x2 = width * adj3;
44825
+ const yQuarter = startY + (yMid - startY) * 0.5;
44826
+ const yThreeQ = yMid + (endY - yMid) * 0.5;
42269
44827
  return {
42270
44828
  startX,
42271
44829
  startY,
42272
44830
  endX,
42273
44831
  endY,
42274
- pathData: `M ${point(0, 0)} C ${point(x1, 0)} ${point(x1, 0)} ${point(x1, yMid * 0.5)} C ${point(x1, yMid)} ${point(x1, yMid)} ${point((x1 + x2) / 2, yMid)} C ${point(x2, yMid)} ${point(x2, yMid)} ${point(x2, (yMid + height) / 2)} C ${point(x2, height)} ${point(x2, height)} ${point(width, height)}`
44832
+ pathData: `M ${point(startX, startY)} C ${point(x1, startY)} ${point(x1, startY)} ${point(x1, yQuarter)} C ${point(x1, yMid)} ${point(x1, yMid)} ${point((x1 + x2) / 2, yMid)} C ${point(x2, yMid)} ${point(x2, yMid)} ${point(x2, yThreeQ)} C ${point(x2, endY)} ${point(x2, endY)} ${point(endX, endY)}`
42275
44833
  };
42276
44834
  }
42277
44835
  if (normalizedType.includes("curvedconnector4")) {
@@ -42279,12 +44837,13 @@ function getConnectorPathGeometry(element) {
42279
44837
  const adj2 = getConnectorAdjustment(element, "adj2", 0.5);
42280
44838
  const midX = width * adj1;
42281
44839
  const midY = height * adj2;
44840
+ const yQuarter = startY + (midY - startY) * 0.5;
42282
44841
  return {
42283
44842
  startX,
42284
44843
  startY,
42285
44844
  endX,
42286
44845
  endY,
42287
- pathData: `M ${point(0, 0)} C ${point(midX, 0)} ${point(midX, 0)} ${point(midX, midY * 0.5)} C ${point(midX, midY)} ${point(midX, midY)} ${point((midX + width) / 2, midY)} C ${point(width, midY)} ${point(width, midY)} ${point(width, height)}`
44846
+ pathData: `M ${point(startX, startY)} C ${point(midX, startY)} ${point(midX, startY)} ${point(midX, yQuarter)} C ${point(midX, midY)} ${point(midX, midY)} ${point((midX + endX) / 2, midY)} C ${point(endX, midY)} ${point(endX, midY)} ${point(endX, endY)}`
42288
44847
  };
42289
44848
  }
42290
44849
  if (normalizedType.includes("curvedconnector3")) {
@@ -42296,7 +44855,7 @@ function getConnectorPathGeometry(element) {
42296
44855
  startY,
42297
44856
  endX,
42298
44857
  endY,
42299
- pathData: `M ${point(0, 0)} C ${point(midX, 0)} ${point(midX, 0)} ${point(midX, midY)} C ${point(midX, height)} ${point(midX, height)} ${point(width, height)}`
44858
+ pathData: `M ${point(startX, startY)} C ${point(midX, startY)} ${point(midX, startY)} ${point(midX, midY)} C ${point(midX, endY)} ${point(midX, endY)} ${point(endX, endY)}`
42300
44859
  };
42301
44860
  }
42302
44861
  if (normalizedType.includes("curvedconnector2")) {
@@ -42305,7 +44864,7 @@ function getConnectorPathGeometry(element) {
42305
44864
  startY,
42306
44865
  endX,
42307
44866
  endY,
42308
- pathData: `M ${point(0, 0)} Q ${point(width, 0)} ${point(width, height)}`
44867
+ pathData: `M ${point(startX, startY)} Q ${point(endX, startY)} ${point(endX, endY)}`
42309
44868
  };
42310
44869
  }
42311
44870
  return {
@@ -42313,7 +44872,7 @@ function getConnectorPathGeometry(element) {
42313
44872
  startY,
42314
44873
  endX,
42315
44874
  endY,
42316
- pathData: `M ${point(0, 0)} L ${point(width, height)}`
44875
+ pathData: `M ${point(startX, startY)} L ${point(endX, endY)}`
42317
44876
  };
42318
44877
  }
42319
44878
 
@@ -50474,4 +53033,4 @@ var SvgExporter = class _SvgExporter {
50474
53033
  }
50475
53034
  };
50476
53035
 
50477
- export { ALL_ANIMATION_PRESETS, COLOR_MAP_ALIAS_KEYS, CONNECTOR_ARROW_OPTIONS, CONNECTOR_GEOMETRY_OPTIONS, ChartBuilder, ConnectorBuilder, ConnectorXmlFactory, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_COLOR_MAP, DEFAULT_FILL_COLOR, DEFAULT_FONT_FAMILY, DEFAULT_SCHEME_COLOR_MAP, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, DEFAULT_TEXT_FONT_SIZE, DIGEST_ALGORITHM_TO_HASH, DIGEST_ALGORITHM_TO_WEB_CRYPTO, DIGITAL_SIGNATURE_ORIGIN_REL_TYPE, DIGITAL_SIGNATURE_REL_TYPE, DataIntegrityError, DocumentConverter, EMPHASIS_PRESETS, EMU_PER_INCH, EMU_PER_PIXEL2 as EMU_PER_PIXEL, EMU_PER_POINT, EMU_PER_PX, ENTERPRISE_FAIL_ON_REVOCATION_UNKNOWN_ENV, ENTERPRISE_REQUIRE_REVOCATION_ENV, ENTERPRISE_REQUIRE_TIMESTAMP_ENV, ENTERPRISE_TRUST_ROOTS_FILE_ENV, ENTERPRISE_TRUST_ROOTS_PEM_ENV, ENTRANCE_PRESETS, EXIT_PRESETS, EncryptedFileError, FONT_SUBSTITUTION_MAP, FreeformPathBuilder, GroupBuilder, ImageBuilder, IncorrectPasswordError, MIN_ELEMENT_SIZE, MOTION_PATH_PRESETS, MediaBuilder, MediaContext, MediaGraphicFrameXmlFactory, OPC_RELATIONSHIP_TRANSFORM, Ole2ParseError, P14_GUIDE_URI, P15_GUIDE_URI, PANOSE_FAMILY_MAP, PANOSE_MONOSPACE_PROPORTION, PANOSE_SANS_SERIF_STYLES, PANOSE_WEIGHT_MAP, POWERPOINT_PRESENCE_KEY, PPTX_VIEWER_MANIFEST_NS, PRESET_COLOR_MAP, PRESET_SHAPE_CATEGORY_LABELS, PRESET_SHAPE_CLIP_PATHS, PRESET_SHAPE_DEFINITIONS, PRESET_TO_OOXML, PictureXmlFactory, PptxAnimationWriteService, PptxColorStyleCodec, PptxCommentAuthorsXmlFactory, PptxCommentXmlFactoryProvider, PptxCompatibilityService, PptxConnectorParser, PptxContentTypesBuilder, PptxDocumentPropertiesUpdater, PptxEditorAnimationService, PptxElementTransformUpdater, PptxElementXmlBuilder, PptxGraphicFrameParser, PptxHandler, PptxHandlerRuntime75 as PptxHandlerRuntime, PptxHandlerRuntimeFactory, PptxLoadDataBuilder, PptxMarkdownConverter, PptxMediaDataParser, PptxNativeAnimationService, PptxPresentationSaveBuilder, PptxPresentationSlidesReconciler, PptxRuntimeDependencyFactory, PptxSaveConstantsFactory, PptxSaveState as PptxSaveSession, PptxSaveStateBuilder as PptxSaveSessionBuilder, PptxSaveState, PptxSaveStateBuilder, PptxShapeIdValidator, PptxShapeStyleExtractor, PptxSlideBackgroundBuilder, PptxSlideBuilder, PptxSlideCommentPartWriter, PptxSlideCommentsXmlFactory, PptxSlideElementsBuilder, PptxSlideLoaderService, PptxSlideMediaRelationshipBuilder, PptxSlideNotesBuilder, PptxSlideNotesPartUpdater, PptxSlideRelationshipRegistry, PptxSlideTransitionService, PptxTableDataParser, PptxTemplateBackgroundService, PptxXmlBuilder, PptxXmlFactoryProvider, PptxXmlLookupService, Presentation, PresentationBuilder, SHAPE_TREE_ELEMENT_TAGS, STROKE_DASH_OPTIONS, SUPPORTED_XML_CANON_TRANSFORMS, SWITCHABLE_LAYOUT_TYPES, SYSTEM_COLOR_MAP, ShapeBuilder, SlideBuilder, SlideProcessor, SlideSizes, SvgExporter, THEME_COLOR_SCHEME_KEYS, THEME_PRESETS, TRANSITION_VALID_DIRECTIONS, TableBuilder, TextBuilder, TextShapeXmlFactory, ThemePresets, VML_SHAPE_TAGS, XMLDSIG_NS, XML_TRANSFORM_ENVELOPED_SIGNATURE, addChartCategory, addChartSeries, addSection, addSmartArtNode, addSmartArtNodeAsChild, applyDrawingColorTransforms, applyKinsokuToXml, applyTemplate, applyThemeToData, areNamespacesSupported, buildCalloutLeaderLineSvgPath, buildClrMapOverrideXml, buildFontFamilyString, buildGuideListExtension, buildLinkedTextBoxChains, buildOle2, buildSingleEffectNode, buildThemeColorMap, catmullRomToBezier, chartDataAddCategory, chartDataAddSeries, chartDataChangeType, chartDataRemoveCategory, chartDataRemoveSeries, chartDataUpdatePoint, checkBlankSlide, checkComplexTables, checkDuplicateTitles, checkLowContrast, checkMissingAltText, checkMissingSlideTitle, checkPresentation, clampUnitInterval, classifyPanose, cloneElement, cloneShapeStyle, cloneSlide, cloneTemplateElementsBySlideId, cloneTextStyle, cloneXmlObject, cm, cmToEmu, colorWithOpacity, combineShapes, computeContrastRatio, computeCycleLayout, computeDetailStatus, computeDigestBase64 as computeDigestBase64WebCrypto, computeHierarchyLayout, computeLinearLayout, computeMatrixLayout, computePyramidLayout, computeSmartArtLayout, computeSnakeLayout, computeVerificationStatus, convertEmfToDataUrl, convertWmfToDataUrl, convertXmlToStrict, createArrayBufferCopy, createBuiltinVariables, createChartElement, createConnectorElement, createDefaultPptxHandlerRuntime, createEditorId, createFreeformElement, createGroupElement, createImageElement, createLayout, createLayouts, createMediaElement, createModifyVerifier, createPptxSaveConstants, createShapeElement, createTableElement, createTemplateConnectorRawXml, createTemplateShapeRawXml, createTextElement, createUniformTextSegments, dataUrlToMediaBytes, decomposeSmartArt, decryptPptx, demoteSmartArtNode, deobfuscateFont, deriveOutputPath, detectDigitalSignatures, detectFileFormat, detectFontFormat, detectOleObjectType, detectStrictConformance, diffPresentations, diffSlides, distributeSegmentsAcrossChain, douglasPeucker, duplicateElement, duplicateSlide, elementActionToPptxAction, elementHasAction, emuToPixels, encryptPptx, ensureArrayValue, escapeXmlAttr, estimateTextBoxCapacity, evaluateGeometryPaths, evaluateGuides, extractAllTagText, extractFirstTagText, extractGuidFromPartName, extractModel3DTransform, extractTagAttribute, fetchUrlToBytes, findCustomShow, findLayoutByName, findLayoutByType, findPlaceholders, findText, formatCommentTimestamp, fragmentShapes, generateFontGuid, generateLayoutXml, generateMediaFilename, getAnimationPresetInfo, getCalloutLeaderLineGeometry, getCalloutTier, getCalloutViewBoxBounds, getCommentMarkerPosition, getConnectorAdjustment, getConnectorPathGeometry, getCssBorderDashStyle, getCustomShowNames, getCustomShowPositionLabel, getDirectory, getElementLabel, getElementTextContent, getElementTransform, getImageMaskStyle, getLinkedTextBoxSegments, getOleObjectTypeLabel, getPanoseWeight, getPresetShapeClipPath, getPresetsByCategory, getRoundRectRadiusPx, getSectionForSlide, getSectionSlideRange, getShapeClipPath, getShapeType, getSignaturePathsToStrip, getSubstituteFontFamily, getSubstituteFonts, getSupportedNamespaces, getSvgStrokeDasharray, getTextCompensationTransform, getThemePreset, getZoomElements, getZoomTargetSlideIndexes, guidToKey, guideEmuToPx, guidePxToEmu, hasDirectSubstitution, hasNonTrivialOverride, hasShapeProperties, hasTextProperties, hexToRgbChannels, hslToRgb, inches, inchesToEmu, inferOleExtensionFromTarget, interpolateShapeGeometry, intersectPolygons, intersectShapes, intersectSvgPaths, isCalloutShape, isConnectorElement, isEditableTextElement, isImageLikeElement, isInkElement, isNamespaceSupported, isShapeElement, isStrictNamespaceUri, isSummaryZoomSlide, isSwitchableLayoutType, isTemplateElement, isTextElement, isTransitionalNamespaceUri, isZoomElement, isZoomElement2 as isZoomElementUtil, layoutEngineShapesToDrawingShapes, mailMerge, mergePresentation, mergeShapes, mergeStyleParts, mergeThemeColorOverride, mm, moveSlidesToSection, navigateCustomShow, normalizeHexColor, normalizeNamespaceUri, normalizePartPath, normalizePath, normalizeStrictXml, normalizeStrokeDashType, obfuscateFont, ooxmlArcToSvg, parseActiveXControlsFromSlide, parseAdjustmentValues, parseBodyPrBooleanAttrs, parseChart3DSurfaces, parseChartAxes, parseCondition, parseConditionList, parseCxChartSeries, parseDataTable, parseDataUrlToBytes, parseDrawingColor, parseDrawingColorChoice, parseDrawingColorOpacity, parseDrawingFraction, parseDrawingHueDegrees, parseDrawingPercent, parseEmbeddedXlsx, parseGuideDefinitions, parseHexColor, parseKinsoku, parseLayoutDefinition, parseLineStyle, parseMarker, parseOle2, parsePanoseBytes, parsePanoseString, parsePresentationDrawingGuides, parseSeriesDataLabels, parseSeriesDataPoints, parseSeriesErrBars, parseSeriesExplosion, parseSeriesTrendlines, parseShapeProps, parseSignatureXml, parseSlideDrawingGuides, parseSvgPath, parseVmlElement, parseVmlElements, pixelsToEmu, polygonsToSvgPath, pptxActionToElementAction, promoteSmartArtNode, pt, reResolveSlideColors, readFileAsDataUrl, reflowSmartArtLayout, relativeLuminance, relayoutSmartArt, removeChartCategory, removeChartSeries, removeSection, removeSmartArtNode, reorderSections, reorderSmartArtNode, reorderSmartArtNodeToIndex, repairPptx, replaceShapeGeometry, replaceText, replaceTextInSlide, replaceWithCustomGeometry, resetCloneIdCounter, resetDecomposeCounter, resetIdCounter, resetSectionIdCounter, resetSmartArtEditCounter, resolveCoordinate, resolveCustomShowSlideIndices, resolveModel3DMimeType, resolveReferenceUriToPart, resolveTableCellStyle, rgbToHsl, selectAlternateContentBranch, serializeCondition, serializeConditionList, serializeSvgPath, setChartCategories, setChartGrouping, setChartTitle, setChartType, shouldRenderFallbackLabel, shouldReturnToZoomSlide, subtractPolygons, subtractShapes, subtractSvgPaths, svgPathToPolygons, switchSmartArtLayout, toHex, toStrictNamespaceUri, unionPolygons, unionShapes, unionSvgPaths, unwrapAlternateContent, updateChartDataPoint, updateChartSeriesValues, updateSmartArtNodeText, validatePptx, verifyModifyPassword, verifyPassword, verifySignatureDigests, writeBodyPrBooleanAttrs };
53036
+ export { ALL_ANIMATION_PRESETS, BLIP_FILL_ORDER, COLOR_MAP_ALIAS_KEYS, CONNECTOR_ARROW_OPTIONS, CONNECTOR_GEOMETRY_OPTIONS, ChartBuilder, ConnectorBuilder, ConnectorXmlFactory, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_COLOR_MAP, DEFAULT_FILL_COLOR, DEFAULT_FONT_FAMILY, DEFAULT_SCHEME_COLOR_MAP, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, DEFAULT_TEXT_FONT_SIZE, DIGEST_ALGORITHM_TO_HASH, DIGEST_ALGORITHM_TO_WEB_CRYPTO, DIGITAL_SIGNATURE_ORIGIN_REL_TYPE, DIGITAL_SIGNATURE_REL_TYPE, DataIntegrityError, DocumentConverter, EFFECT_LST_ORDER, EMPHASIS_PRESETS, EMU_PER_INCH, EMU_PER_PIXEL2 as EMU_PER_PIXEL, EMU_PER_POINT, EMU_PER_PX, ENTERPRISE_FAIL_ON_REVOCATION_UNKNOWN_ENV, ENTERPRISE_REQUIRE_REVOCATION_ENV, ENTERPRISE_REQUIRE_TIMESTAMP_ENV, ENTERPRISE_TRUST_ROOTS_FILE_ENV, ENTERPRISE_TRUST_ROOTS_PEM_ENV, ENTRANCE_PRESETS, EXIT_PRESETS, EncryptedFileError, FONT_SUBSTITUTION_MAP, FreeformPathBuilder, GroupBuilder, ImageBuilder, IncorrectPasswordError, MIN_ELEMENT_SIZE, MOTION_PATH_PRESETS, MediaBuilder, MediaContext, MediaGraphicFrameXmlFactory, OPC_RELATIONSHIP_TRANSFORM, Ole2ParseError, P14_GUIDE_URI, P15_GUIDE_URI, PANOSE_FAMILY_MAP, PANOSE_MONOSPACE_PROPORTION, PANOSE_SANS_SERIF_STYLES, PANOSE_WEIGHT_MAP, POWERPOINT_PRESENCE_KEY, PPTX_VIEWER_MANIFEST_NS, PRESET_COLOR_MAP, PRESET_SHAPE_CATEGORY_LABELS, PRESET_SHAPE_CLIP_PATHS, PRESET_SHAPE_DEFINITIONS, PRESET_TO_OOXML, PictureXmlFactory, PptxAnimationWriteService, PptxColorStyleCodec, PptxCommentAuthorsXmlFactory, PptxCommentXmlFactoryProvider, PptxCompatibilityService, PptxConnectorParser, PptxContentTypesBuilder, PptxDocumentPropertiesUpdater, PptxEditorAnimationService, PptxElementTransformUpdater, PptxElementXmlBuilder, PptxGraphicFrameParser, PptxHandler, PptxHandlerRuntime76 as PptxHandlerRuntime, PptxHandlerRuntimeFactory, PptxLoadDataBuilder, PptxMarkdownConverter, PptxMediaDataParser, PptxNativeAnimationService, PptxPresentationSaveBuilder, PptxPresentationSlidesReconciler, PptxRuntimeDependencyFactory, PptxSaveConstantsFactory, PptxSaveState as PptxSaveSession, PptxSaveStateBuilder as PptxSaveSessionBuilder, PptxSaveState, PptxSaveStateBuilder, PptxShapeIdValidator, PptxShapeStyleExtractor, PptxSlideBackgroundBuilder, PptxSlideBuilder, PptxSlideCommentPartWriter, PptxSlideCommentsXmlFactory, PptxSlideElementsBuilder, PptxSlideLoaderService, PptxSlideMediaRelationshipBuilder, PptxSlideNotesBuilder, PptxSlideNotesPartUpdater, PptxSlideRelationshipRegistry, PptxSlideTransitionService, PptxTableDataParser, PptxTemplateBackgroundService, PptxXmlBuilder, PptxXmlFactoryProvider, PptxXmlLookupService, Presentation, PresentationBuilder, SHAPE_TREE_ELEMENT_TAGS, SP_PR_ORDER, STROKE_DASH_OPTIONS, SUPPORTED_XML_CANON_TRANSFORMS, SWITCHABLE_LAYOUT_TYPES, SYSTEM_COLOR_MAP, ShapeBuilder, SlideBuilder, SlideProcessor, SlideSizes, SvgExporter, TC_PR_BORDERS_ORDER, THEME_COLOR_SCHEME_KEYS, THEME_PRESETS, TRANSITION_VALID_DIRECTIONS, TableBuilder, TextBuilder, TextShapeXmlFactory, ThemePresets, VML_SHAPE_TAGS, XMLDSIG_NS, XML_TRANSFORM_ENVELOPED_SIGNATURE, addChartCategory, addChartSeries, addSection, addSmartArtNode, addSmartArtNodeAsChild, applyDrawingColorTransforms, applyKinsokuToXml, applyTemplate, applyThemeToData, areNamespacesSupported, buildCalloutLeaderLineSvgPath, buildClrMapOverrideXml, buildFontFamilyString, buildGuideListExtension, buildLinkedTextBoxChains, buildOle2, buildSingleEffectNode, buildSrgbColorChoice, buildThemeColorMap, catmullRomToBezier, chartDataAddCategory, chartDataAddSeries, chartDataChangeType, chartDataRemoveCategory, chartDataRemoveSeries, chartDataUpdatePoint, checkBlankSlide, checkComplexTables, checkDuplicateTitles, checkLowContrast, checkMissingAltText, checkMissingSlideTitle, checkPresentation, clampUnitInterval, classifyPanose, cloneElement, cloneShapeStyle, cloneSlide, cloneTemplateElementsBySlideId, cloneTextStyle, cloneXmlObject, cm, cmToEmu, colorWithOpacity, colorsEqual, combineShapes, computeContrastRatio, computeCycleLayout, computeDetailStatus, computeDigestBase64 as computeDigestBase64WebCrypto, computeHierarchyLayout, computeLinearLayout, computeMatrixLayout, computePyramidLayout, computeSmartArtLayout, computeSnakeLayout, computeVerificationStatus, convertEmfToDataUrl, convertWmfToDataUrl, convertXmlToStrict, createArrayBufferCopy, createBuiltinVariables, createChartElement, createConnectorElement, createDefaultPptxHandlerRuntime, createEditorId, createFreeformElement, createGroupElement, createImageElement, createLayout, createLayouts, createMediaElement, createModifyVerifier, createPptxSaveConstants, createShapeElement, createTableElement, createTemplateConnectorRawXml, createTemplateShapeRawXml, createTextElement, createUniformTextSegments, dataUrlToMediaBytes, decomposeSmartArt, decryptPptx, demoteSmartArtNode, deobfuscateFont, deriveOutputPath, detectDigitalSignatures, detectFileFormat, detectFontFormat, detectOleObjectType, detectStrictConformance, diffPresentations, diffSlides, distributeSegmentsAcrossChain, douglasPeucker, duplicateElement, duplicateSlide, elementActionToPptxAction, elementHasAction, emuToPixels, encryptPptx, ensureArrayValue, escapeXmlAttr, estimateTextBoxCapacity, evaluateGeometryPaths, evaluateGuides, extractAllTagText, extractColorChoiceXml, extractFirstTagText, extractGuidFromPartName, extractModel3DTransform, extractTagAttribute, fetchUrlToBytes, findCustomShow, findLayoutByName, findLayoutByType, findPlaceholders, findText, formatCommentTimestamp, fragmentShapes, generateFontGuid, generateLayoutXml, generateMediaFilename, getAnimationPresetInfo, getCalloutLeaderLineGeometry, getCalloutTier, getCalloutViewBoxBounds, getCommentMarkerPosition, getConnectorAdjustment, getConnectorPathGeometry, getCssBorderDashStyle, getCustomShowNames, getCustomShowPositionLabel, getDirectory, getElementLabel, getElementTextContent, getElementTransform, getImageMaskStyle, getLinkedTextBoxSegments, getOleObjectTypeLabel, getPanoseWeight, getPresetShapeClipPath, getPresetsByCategory, getRoundRectRadiusPx, getSectionForSlide, getSectionSlideRange, getShapeClipPath, getShapeType, getSignaturePathsToStrip, getSubstituteFontFamily, getSubstituteFonts, getSupportedNamespaces, getSvgStrokeDasharray, getTextCompensationTransform, getThemePreset, getZoomElements, getZoomTargetSlideIndexes, guidToKey, guideEmuToPx, guidePxToEmu, hasDirectSubstitution, hasNonTrivialOverride, hasShapeProperties, hasTextProperties, hexToRgbChannels, hslToRgb, inches, inchesToEmu, inferOleExtensionFromTarget, interpolateShapeGeometry, intersectPolygons, intersectShapes, intersectSvgPaths, isCalloutShape, isConnectorElement, isEditableTextElement, isImageLikeElement, isInkElement, isNamespaceSupported, isShapeElement, isStrictNamespaceUri, isSummaryZoomSlide, isSwitchableLayoutType, isTemplateElement, isTextElement, isTransitionalNamespaceUri, isZoomElement, isZoomElement2 as isZoomElementUtil, layoutEngineShapesToDrawingShapes, mailMerge, mergePresentation, mergeShapes, mergeStyleParts, mergeThemeColorOverride, mm, moveSlidesToSection, navigateCustomShow, normalizeHexColor, normalizeNamespaceUri, normalizePartPath, normalizePath, normalizeStrictXml, normalizeStrokeDashType, obfuscateFont, ooxmlArcToSvg, parseActiveXControlsFromSlide, parseAdjustmentValues, parseBodyPrBooleanAttrs, parseChart3DSurfaces, parseChartAxes, parseCondition, parseConditionList, parseCxChartSeries, parseDataTable, parseDataUrlToBytes, parseDrawingColor, parseDrawingColorChoice, parseDrawingColorOpacity, parseDrawingFraction, parseDrawingHueDegrees, parseDrawingPercent, parseEmbeddedXlsx, parseGuideDefinitions, parseHexColor, parseKinsoku, parseLayoutDefinition, parseLineStyle, parseMarker, parseOle2, parsePanoseBytes, parsePanoseString, parsePresentationDrawingGuides, parseSeriesDataLabels, parseSeriesDataPoints, parseSeriesErrBars, parseSeriesExplosion, parseSeriesTrendlines, parseShapeProps, parseSignatureXml, parseSlideDrawingGuides, parseSvgPath, parseVmlElement, parseVmlElements, pixelsToEmu, polygonsToSvgPath, pptxActionToElementAction, promoteSmartArtNode, pt, reResolveSlideColors, readFileAsDataUrl, reflowSmartArtLayout, relativeLuminance, relayoutSmartArt, removeChartCategory, removeChartSeries, removeSection, removeSmartArtNode, reorderObjectKeys, reorderSections, reorderSmartArtNode, reorderSmartArtNodeToIndex, repairPptx, replaceShapeGeometry, replaceText, replaceTextInSlide, replaceWithCustomGeometry, resetCloneIdCounter, resetDecomposeCounter, resetIdCounter, resetSectionIdCounter, resetSmartArtEditCounter, resolveCoordinate, resolveCustomShowSlideIndices, resolveModel3DMimeType, resolveReferenceUriToPart, resolveTableCellStyle, rgbToHsl, selectAlternateContentBranch, serializeColorChoice, serializeCondition, serializeConditionList, serializeSvgPath, setChartCategories, setChartGrouping, setChartTitle, setChartType, shouldRenderFallbackLabel, shouldReturnToZoomSlide, subtractPolygons, subtractShapes, subtractSvgPaths, svgPathToPolygons, switchSmartArtLayout, toHex, toStrictNamespaceUri, unionPolygons, unionShapes, unionSvgPaths, unwrapAlternateContent, updateChartDataPoint, updateChartSeriesValues, updateSmartArtNodeText, validatePptx, verifyModifyPassword, verifyPassword, verifySignatureDigests, writeBodyPrBooleanAttrs };