pptx-react-viewer 1.1.3 → 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-BMjoxMDV.d.ts → SvgExporter-0TxiiorD.d.ts} +1 -1
  9. package/node_modules/pptx-viewer-core/dist/{SvgExporter-z6AbXRQg.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 +2711 -304
  13. package/node_modules/pptx-viewer-core/dist/cli/index.mjs +2711 -304
  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 +692 -44
  17. package/node_modules/pptx-viewer-core/dist/index.d.ts +692 -44
  18. package/node_modules/pptx-viewer-core/dist/index.js +2794 -373
  19. package/node_modules/pptx-viewer-core/dist/index.mjs +2785 -373
  20. package/node_modules/pptx-viewer-core/dist/{presentation-CchuDGfU.d.mts → presentation-ArhfImJ5.d.mts} +225 -8
  21. package/node_modules/pptx-viewer-core/dist/{presentation-CchuDGfU.d.ts → presentation-ArhfImJ5.d.ts} +225 -8
  22. package/node_modules/pptx-viewer-core/dist/{text-operations-CeukUztU.d.mts → text-operations-CLj-sJyk.d.mts} +1 -1
  23. package/node_modules/pptx-viewer-core/dist/{text-operations-e7JxgI5l.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
@@ -682,12 +682,25 @@ function svgToCustomGeometryPaths(pathData, width, height) {
682
682
  function pointToXml(pt2) {
683
683
  return { "@_x": String(Math.round(pt2.x)), "@_y": String(Math.round(pt2.y)) };
684
684
  }
685
- function customGeometryPathsToXml(paths) {
685
+ function customGeometryPathsToXml(paths, rawData) {
686
686
  const xmlPaths = paths.map((path) => {
687
687
  const pathXml = {
688
688
  "@_w": String(Math.round(path.width)),
689
689
  "@_h": String(Math.round(path.height))
690
690
  };
691
+ if (path.fillMode) {
692
+ pathXml["@_fill"] = path.fillMode;
693
+ }
694
+ if (path.stroke === false) {
695
+ pathXml["@_stroke"] = "0";
696
+ } else if (path.stroke === true) {
697
+ pathXml["@_stroke"] = "1";
698
+ }
699
+ if (path.extrusionOk === true) {
700
+ pathXml["@_extrusionOk"] = "1";
701
+ } else if (path.extrusionOk === false) {
702
+ pathXml["@_extrusionOk"] = "0";
703
+ }
691
704
  const moveToList = [];
692
705
  const lnToList = [];
693
706
  const cubicBezToList = [];
@@ -745,12 +758,12 @@ function customGeometryPathsToXml(paths) {
745
758
  }
746
759
  return pathXml;
747
760
  });
748
- return {
761
+ const result = {
749
762
  "a:avLst": {},
750
- "a:gdLst": {},
751
- "a:ahLst": {},
752
- "a:cxnLst": {},
753
- "a:rect": {
763
+ "a:gdLst": rawData?.gdLstXml ?? {},
764
+ "a:ahLst": rawData?.ahLstXml ?? {},
765
+ "a:cxnLst": rawData?.cxnLstXml ?? {},
766
+ "a:rect": rawData?.rectXml ?? {
754
767
  "@_l": "l",
755
768
  "@_t": "t",
756
769
  "@_r": "r",
@@ -760,6 +773,7 @@ function customGeometryPathsToXml(paths) {
760
773
  "a:path": xmlPaths.length === 1 ? xmlPaths[0] : xmlPaths
761
774
  }
762
775
  };
776
+ return result;
763
777
  }
764
778
 
765
779
  // src/core/builders/sdk/ElementFactory.ts
@@ -1509,6 +1523,9 @@ ${Array.from(
1509
1523
  <p:presentation xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
1510
1524
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
1511
1525
  xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
1526
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
1527
+ xmlns:p14="http://schemas.microsoft.com/office/powerpoint/2010/main"
1528
+ xmlns:p15="http://schemas.microsoft.com/office/powerpoint/2012/main"
1512
1529
  saveSubsetFonts="1">
1513
1530
  <p:sldMasterIdLst>
1514
1531
  <p:sldMasterId id="2147483648" r:id="rId1"/>
@@ -2930,6 +2947,22 @@ var PptxPresentationSlidesReconciler = class {
2930
2947
  };
2931
2948
 
2932
2949
  // src/core/core/builders/PptxSlideRelationshipRegistry.ts
2950
+ function isExternalTarget(target) {
2951
+ const normalized = target.trim();
2952
+ if (normalized.length === 0) {
2953
+ return false;
2954
+ }
2955
+ const colonIdx = normalized.indexOf(":");
2956
+ if (colonIdx <= 0) {
2957
+ return false;
2958
+ }
2959
+ const slashIdx = normalized.indexOf("/");
2960
+ if (slashIdx !== -1 && slashIdx < colonIdx) {
2961
+ return false;
2962
+ }
2963
+ const scheme = normalized.slice(0, colonIdx);
2964
+ return /^[A-Za-z][A-Za-z0-9+\-.]*$/.test(scheme);
2965
+ }
2933
2966
  var PptxSlideRelationshipRegistry = class {
2934
2967
  relationships;
2935
2968
  usedRelationshipIds = /* @__PURE__ */ new Set();
@@ -3000,7 +3033,7 @@ var PptxSlideRelationshipRegistry = class {
3000
3033
  return existingRelationshipId;
3001
3034
  }
3002
3035
  const relationshipId = this.nextRelationshipId();
3003
- const targetMode = /^(https?:|mailto:|ftp:|file:)/i.test(normalizedTarget) ? "External" : void 0;
3036
+ const targetMode = isExternalTarget(normalizedTarget) ? "External" : void 0;
3004
3037
  this.upsertRelationship(
3005
3038
  relationshipId,
3006
3039
  this.hyperlinkRelationshipType,
@@ -3250,6 +3283,82 @@ var PptxSlideNotesPartUpdater = class {
3250
3283
  }
3251
3284
  };
3252
3285
 
3286
+ // src/core/utils/xml-reorder.ts
3287
+ function reorderObjectKeys(obj, schemaOrder) {
3288
+ const result = {};
3289
+ const consumed = /* @__PURE__ */ new Set();
3290
+ for (const key of schemaOrder) {
3291
+ if (Object.hasOwn(obj, key)) {
3292
+ const value = obj[key];
3293
+ if (value !== void 0) {
3294
+ result[key] = value;
3295
+ }
3296
+ consumed.add(key);
3297
+ }
3298
+ }
3299
+ for (const key of Object.keys(obj)) {
3300
+ if (consumed.has(key)) {
3301
+ continue;
3302
+ }
3303
+ const value = obj[key];
3304
+ if (value !== void 0) {
3305
+ result[key] = value;
3306
+ }
3307
+ }
3308
+ return result;
3309
+ }
3310
+ var EFFECT_LST_ORDER = [
3311
+ "a:blur",
3312
+ "a:fillOverlay",
3313
+ "a:glow",
3314
+ "a:innerShdw",
3315
+ "a:outerShdw",
3316
+ "a:prstShdw",
3317
+ "a:reflection",
3318
+ "a:softEdge"
3319
+ ];
3320
+ var SP_PR_ORDER = [
3321
+ "a:xfrm",
3322
+ "a:custGeom",
3323
+ "a:prstGeom",
3324
+ "a:noFill",
3325
+ "a:solidFill",
3326
+ "a:gradFill",
3327
+ "a:blipFill",
3328
+ "a:pattFill",
3329
+ "a:grpFill",
3330
+ "a:ln",
3331
+ "a:effectLst",
3332
+ "a:effectDag",
3333
+ "a:scene3d",
3334
+ "a:sp3d",
3335
+ "a:extLst"
3336
+ ];
3337
+ var TC_PR_BORDERS_ORDER = [
3338
+ "a:lnL",
3339
+ "a:lnR",
3340
+ "a:lnT",
3341
+ "a:lnB",
3342
+ "a:lnTlToBr",
3343
+ "a:lnBlToTr",
3344
+ "a:cell3D",
3345
+ "a:noFill",
3346
+ "a:solidFill",
3347
+ "a:gradFill",
3348
+ "a:blipFill",
3349
+ "a:pattFill",
3350
+ "a:grpFill",
3351
+ "a:headers",
3352
+ "a:extLst"
3353
+ ];
3354
+ var BLIP_FILL_ORDER = ["a:blip", "a:srcRect", "a:tile", "a:stretch"];
3355
+ var SHAPE_STYLE_ORDER = [
3356
+ "a:lnRef",
3357
+ "a:fillRef",
3358
+ "a:effectRef",
3359
+ "a:fontRef"
3360
+ ];
3361
+
3253
3362
  // src/core/core/builders/PptxSlideBackgroundBuilder.ts
3254
3363
  var PptxSlideBackgroundBuilder = class {
3255
3364
  applyBackground(init) {
@@ -3285,10 +3394,13 @@ var PptxSlideBackgroundBuilder = class {
3285
3394
  init.slideImageRelationshipType,
3286
3395
  relativeBackgroundImagePath
3287
3396
  );
3288
- backgroundProperties["a:blipFill"] = {
3289
- "a:blip": { "@_r:embed": backgroundRelationshipId },
3290
- "a:stretch": { "a:fillRect": {} }
3291
- };
3397
+ backgroundProperties["a:blipFill"] = reorderObjectKeys(
3398
+ {
3399
+ "a:blip": { "@_r:embed": backgroundRelationshipId },
3400
+ "a:stretch": { "a:fillRect": {} }
3401
+ },
3402
+ BLIP_FILL_ORDER
3403
+ );
3292
3404
  }
3293
3405
  } else if (hasBackgroundColor && init.slide.backgroundColor) {
3294
3406
  backgroundProperties["a:solidFill"] = {
@@ -4110,6 +4222,45 @@ var PptxGradientStyleCodec = class {
4110
4222
  b: Number.isFinite(b) ? this.context.clampUnitInterval(b / 1e5) : 0
4111
4223
  };
4112
4224
  }
4225
+ extractGradientFlip(gradFill) {
4226
+ const flipRaw = String(gradFill["@_flip"] || "").trim().toLowerCase();
4227
+ if (flipRaw === "x" || flipRaw === "y" || flipRaw === "xy" || flipRaw === "none") {
4228
+ return flipRaw;
4229
+ }
4230
+ return void 0;
4231
+ }
4232
+ extractGradientRotWithShape(gradFill) {
4233
+ const rot = gradFill["@_rotWithShape"];
4234
+ if (rot === void 0 || rot === null) {
4235
+ return void 0;
4236
+ }
4237
+ const token = String(rot).trim().toLowerCase();
4238
+ if (token === "1" || token === "true") {
4239
+ return true;
4240
+ }
4241
+ if (token === "0" || token === "false") {
4242
+ return false;
4243
+ }
4244
+ return void 0;
4245
+ }
4246
+ extractGradientScaled(gradFill) {
4247
+ const lin = gradFill["a:lin"];
4248
+ if (!lin) {
4249
+ return void 0;
4250
+ }
4251
+ const scaled = lin["@_scaled"];
4252
+ if (scaled === void 0 || scaled === null) {
4253
+ return void 0;
4254
+ }
4255
+ const token = String(scaled).trim().toLowerCase();
4256
+ if (token === "1" || token === "true") {
4257
+ return true;
4258
+ }
4259
+ if (token === "0" || token === "false") {
4260
+ return false;
4261
+ }
4262
+ return void 0;
4263
+ }
4113
4264
  extractGradientAngle(gradFill) {
4114
4265
  const angleRaw = Number.parseInt(
4115
4266
  String(gradFill["a:lin"]?.["@_ang"] || ""),
@@ -4196,11 +4347,14 @@ var PptxGradientStyleCodec = class {
4196
4347
  return void 0;
4197
4348
  }
4198
4349
  const gradientType = shapeStyle.fillGradientType || "linear";
4199
- const gradientXml = {
4200
- "a:gsLst": {
4201
- "a:gs": stops
4202
- }
4203
- };
4350
+ const gradientXml = {};
4351
+ if (shapeStyle.fillGradientFlip && shapeStyle.fillGradientFlip !== "none") {
4352
+ gradientXml["@_flip"] = shapeStyle.fillGradientFlip;
4353
+ }
4354
+ if (shapeStyle.fillGradientRotWithShape !== void 0) {
4355
+ gradientXml["@_rotWithShape"] = shapeStyle.fillGradientRotWithShape ? "1" : "0";
4356
+ }
4357
+ gradientXml["a:gsLst"] = { "a:gs": stops };
4204
4358
  if (gradientType === "radial") {
4205
4359
  const pathType = shapeStyle.fillGradientPathType || "circle";
4206
4360
  const pathXml = {
@@ -4230,10 +4384,15 @@ var PptxGradientStyleCodec = class {
4230
4384
  gradientXml["a:path"] = pathXml;
4231
4385
  } else {
4232
4386
  const normalizedAngle = typeof shapeStyle.fillGradientAngle === "number" && Number.isFinite(shapeStyle.fillGradientAngle) ? shapeStyle.fillGradientAngle : 90;
4233
- gradientXml["a:lin"] = {
4234
- "@_ang": String(Math.round(normalizedAngle * 6e4)),
4235
- "@_scaled": "1"
4387
+ const linNode = {
4388
+ "@_ang": String(Math.round(normalizedAngle * 6e4))
4236
4389
  };
4390
+ if (shapeStyle.fillGradientScaled !== void 0) {
4391
+ linNode["@_scaled"] = shapeStyle.fillGradientScaled ? "1" : "0";
4392
+ } else {
4393
+ linNode["@_scaled"] = "1";
4394
+ }
4395
+ gradientXml["a:lin"] = linNode;
4237
4396
  }
4238
4397
  return gradientXml;
4239
4398
  }
@@ -4630,6 +4789,30 @@ var PRESET_SHADOW_OPACITY_MAP = {
4630
4789
  };
4631
4790
 
4632
4791
  // src/core/core/builders/PptxShapeEffectStyleExtractor.ts
4792
+ var VALID_ALIGNMENTS = /* @__PURE__ */ new Set(["tl", "t", "tr", "l", "ctr", "r", "bl", "b", "br"]);
4793
+ function parseIntAttr(value) {
4794
+ if (value === void 0 || value === null || value === "") {
4795
+ return void 0;
4796
+ }
4797
+ const parsed = Number.parseInt(String(value), 10);
4798
+ return Number.isFinite(parsed) ? parsed : void 0;
4799
+ }
4800
+ function parseAlignmentAttr(value) {
4801
+ const v = String(value ?? "").trim();
4802
+ return VALID_ALIGNMENTS.has(v) ? v : void 0;
4803
+ }
4804
+ function parseBoolAttr(value) {
4805
+ if (typeof value === "boolean") {
4806
+ return value;
4807
+ }
4808
+ if (value === "1" || value === "true") {
4809
+ return true;
4810
+ }
4811
+ if (value === "0" || value === "false") {
4812
+ return false;
4813
+ }
4814
+ return void 0;
4815
+ }
4633
4816
  var PptxShapeEffectStyleExtractor = class {
4634
4817
  context;
4635
4818
  constructor(context) {
@@ -4653,7 +4836,12 @@ var PptxShapeEffectStyleExtractor = class {
4653
4836
  const shadowOffsetX = distance !== void 0 ? Math.round(Math.cos(directionRadians) * distance * 100) / 100 : void 0;
4654
4837
  const shadowOffsetY = distance !== void 0 ? Math.round(Math.sin(directionRadians) * distance * 100) / 100 : void 0;
4655
4838
  const rotateWithShape = outerShadow["@_rotWithShape"];
4656
- const shadowRotateWithShape = typeof rotateWithShape === "boolean" ? rotateWithShape : rotateWithShape === "1" || rotateWithShape === "true" ? true : void 0;
4839
+ const shadowRotateWithShape = typeof rotateWithShape === "boolean" ? rotateWithShape : rotateWithShape === "1" || rotateWithShape === "true" ? true : rotateWithShape === "0" || rotateWithShape === "false" ? false : void 0;
4840
+ const shadowScaleX = parseIntAttr(outerShadow["@_sx"]);
4841
+ const shadowScaleY = parseIntAttr(outerShadow["@_sy"]);
4842
+ const shadowSkewX = parseIntAttr(outerShadow["@_kx"]);
4843
+ const shadowSkewY = parseIntAttr(outerShadow["@_ky"]);
4844
+ const shadowAlignment = parseAlignmentAttr(outerShadow["@_algn"]);
4657
4845
  return {
4658
4846
  shadowColor,
4659
4847
  shadowOpacity,
@@ -4662,7 +4850,12 @@ var PptxShapeEffectStyleExtractor = class {
4662
4850
  shadowOffsetY,
4663
4851
  shadowAngle: directionDegrees,
4664
4852
  shadowDistance: distance,
4665
- shadowRotateWithShape
4853
+ shadowRotateWithShape,
4854
+ shadowScaleX,
4855
+ shadowScaleY,
4856
+ shadowSkewX,
4857
+ shadowSkewY,
4858
+ shadowAlignment
4666
4859
  };
4667
4860
  }
4668
4861
  extractPresetShadowStyle(effectLstParent) {
@@ -4708,12 +4901,14 @@ var PptxShapeEffectStyleExtractor = class {
4708
4901
  const directionRadians = directionDegrees * Math.PI / 180;
4709
4902
  const innerShadowOffsetX = distance !== void 0 ? Math.round(Math.cos(directionRadians) * distance * 100) / 100 : void 0;
4710
4903
  const innerShadowOffsetY = distance !== void 0 ? Math.round(Math.sin(directionRadians) * distance * 100) / 100 : void 0;
4904
+ const innerShadowRotateWithShape = parseBoolAttr(innerShadow["@_rotWithShape"]);
4711
4905
  return {
4712
4906
  innerShadowColor,
4713
4907
  innerShadowOpacity,
4714
4908
  innerShadowBlur,
4715
4909
  innerShadowOffsetX,
4716
- innerShadowOffsetY
4910
+ innerShadowOffsetY,
4911
+ innerShadowRotateWithShape
4717
4912
  };
4718
4913
  }
4719
4914
  extractGlowStyle(shapeProps) {
@@ -4762,6 +4957,16 @@ var PptxShapeEffectStyleExtractor = class {
4762
4957
  const reflectionRotation = Number.isFinite(rotationRaw) ? rotationRaw / 6e4 : void 0;
4763
4958
  const distanceRaw = Number.parseInt(String(reflectionNode["@_dist"] || ""), 10);
4764
4959
  const reflectionDistance = Number.isFinite(distanceRaw) && distanceRaw >= 0 ? distanceRaw / this.context.emuPerPx : void 0;
4960
+ const fadeDirRaw = parseIntAttr(reflectionNode["@_fadeDir"]);
4961
+ const reflectionFadeDirection = fadeDirRaw !== void 0 ? fadeDirRaw / 6e4 : void 0;
4962
+ const reflectionScaleX = parseIntAttr(reflectionNode["@_sx"]);
4963
+ const reflectionScaleY = parseIntAttr(reflectionNode["@_sy"]);
4964
+ const reflectionSkewX = parseIntAttr(reflectionNode["@_kx"]);
4965
+ const reflectionSkewY = parseIntAttr(reflectionNode["@_ky"]);
4966
+ const reflectionAlignment = parseAlignmentAttr(reflectionNode["@_algn"]);
4967
+ const reflectionRotateWithShape = parseBoolAttr(reflectionNode["@_rotWithShape"]);
4968
+ const stPosRaw = parseIntAttr(reflectionNode["@_stPos"]);
4969
+ const reflectionStartPosition = stPosRaw !== void 0 ? stPosRaw / 1e5 : void 0;
4765
4970
  return {
4766
4971
  reflectionBlurRadius,
4767
4972
  reflectionStartOpacity,
@@ -4769,7 +4974,15 @@ var PptxShapeEffectStyleExtractor = class {
4769
4974
  reflectionEndPosition,
4770
4975
  reflectionDirection,
4771
4976
  reflectionRotation,
4772
- reflectionDistance
4977
+ reflectionDistance,
4978
+ reflectionFadeDirection,
4979
+ reflectionScaleX,
4980
+ reflectionScaleY,
4981
+ reflectionSkewX,
4982
+ reflectionSkewY,
4983
+ reflectionAlignment,
4984
+ reflectionRotateWithShape,
4985
+ reflectionStartPosition
4773
4986
  };
4774
4987
  }
4775
4988
  extractBlurStyle(shapeProps) {
@@ -4821,11 +5034,56 @@ var PptxShapeEffectXmlBuilder = class {
4821
5034
  }
4822
5035
  }
4823
5036
  };
5037
+ if (typeof shapeStyle.shadowScaleX === "number") {
5038
+ xmlObj["@_sx"] = String(Math.round(shapeStyle.shadowScaleX));
5039
+ }
5040
+ if (typeof shapeStyle.shadowScaleY === "number") {
5041
+ xmlObj["@_sy"] = String(Math.round(shapeStyle.shadowScaleY));
5042
+ }
5043
+ if (typeof shapeStyle.shadowSkewX === "number") {
5044
+ xmlObj["@_kx"] = String(Math.round(shapeStyle.shadowSkewX));
5045
+ }
5046
+ if (typeof shapeStyle.shadowSkewY === "number") {
5047
+ xmlObj["@_ky"] = String(Math.round(shapeStyle.shadowSkewY));
5048
+ }
5049
+ if (shapeStyle.shadowAlignment) {
5050
+ xmlObj["@_algn"] = shapeStyle.shadowAlignment;
5051
+ }
4824
5052
  if (typeof shapeStyle.shadowRotateWithShape === "boolean") {
4825
5053
  xmlObj["@_rotWithShape"] = shapeStyle.shadowRotateWithShape ? "1" : "0";
4826
5054
  }
4827
5055
  return xmlObj;
4828
5056
  }
5057
+ buildPresetShadowXml(shapeStyle) {
5058
+ const preset = shapeStyle.presetShadowName;
5059
+ if (!preset || preset.length === 0) {
5060
+ return void 0;
5061
+ }
5062
+ const shadowColor = String(shapeStyle.shadowColor || "#000000").trim();
5063
+ const shadowOpacity = typeof shapeStyle.shadowOpacity === "number" && Number.isFinite(shapeStyle.shadowOpacity) ? this.context.clampUnitInterval(shapeStyle.shadowOpacity) : 0.5;
5064
+ let distance;
5065
+ let directionDegrees;
5066
+ if (typeof shapeStyle.shadowAngle === "number" && typeof shapeStyle.shadowDistance === "number") {
5067
+ directionDegrees = shapeStyle.shadowAngle;
5068
+ distance = shapeStyle.shadowDistance;
5069
+ } else {
5070
+ const ox = typeof shapeStyle.shadowOffsetX === "number" ? shapeStyle.shadowOffsetX : 0;
5071
+ const oy = typeof shapeStyle.shadowOffsetY === "number" ? shapeStyle.shadowOffsetY : 0;
5072
+ distance = Math.sqrt(ox * ox + oy * oy);
5073
+ directionDegrees = (Math.atan2(oy, ox) * 180 / Math.PI + 360) % 360;
5074
+ }
5075
+ return {
5076
+ "@_prst": preset,
5077
+ "@_dist": String(Math.round(distance * this.context.emuPerPx)),
5078
+ "@_dir": String(Math.round(directionDegrees * 6e4)),
5079
+ "a:srgbClr": {
5080
+ "@_val": shadowColor.replace("#", ""),
5081
+ "a:alpha": {
5082
+ "@_val": String(Math.round(shadowOpacity * 1e5))
5083
+ }
5084
+ }
5085
+ };
5086
+ }
4829
5087
  buildInnerShadowXml(shapeStyle) {
4830
5088
  const innerColor = String(shapeStyle.innerShadowColor || "").trim();
4831
5089
  if (innerColor.length === 0 || innerColor === "transparent") {
@@ -4837,7 +5095,7 @@ var PptxShapeEffectXmlBuilder = class {
4837
5095
  const opacity = typeof shapeStyle.innerShadowOpacity === "number" && Number.isFinite(shapeStyle.innerShadowOpacity) ? this.context.clampUnitInterval(shapeStyle.innerShadowOpacity) : 0.5;
4838
5096
  const distance = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
4839
5097
  const directionDegrees = (Math.atan2(offsetY, offsetX) * 180 / Math.PI + 360) % 360;
4840
- return {
5098
+ const xmlObj = {
4841
5099
  "@_blurRad": String(Math.round(blurValue * this.context.emuPerPx)),
4842
5100
  "@_dist": String(Math.round(distance * this.context.emuPerPx)),
4843
5101
  "@_dir": String(Math.round(directionDegrees * 6e4)),
@@ -4848,6 +5106,10 @@ var PptxShapeEffectXmlBuilder = class {
4848
5106
  }
4849
5107
  }
4850
5108
  };
5109
+ if (typeof shapeStyle.innerShadowRotateWithShape === "boolean") {
5110
+ xmlObj["@_rotWithShape"] = shapeStyle.innerShadowRotateWithShape ? "1" : "0";
5111
+ }
5112
+ return xmlObj;
4851
5113
  }
4852
5114
  buildGlowXml(shapeStyle) {
4853
5115
  const glowColor = String(shapeStyle.glowColor || "").trim();
@@ -4909,6 +5171,30 @@ var PptxShapeEffectXmlBuilder = class {
4909
5171
  Math.round(shapeStyle.reflectionDistance * this.context.emuPerPx)
4910
5172
  );
4911
5173
  }
5174
+ if (typeof shapeStyle.reflectionFadeDirection === "number") {
5175
+ reflectionXml["@_fadeDir"] = String(Math.round(shapeStyle.reflectionFadeDirection * 6e4));
5176
+ }
5177
+ if (typeof shapeStyle.reflectionScaleX === "number") {
5178
+ reflectionXml["@_sx"] = String(Math.round(shapeStyle.reflectionScaleX));
5179
+ }
5180
+ if (typeof shapeStyle.reflectionScaleY === "number") {
5181
+ reflectionXml["@_sy"] = String(Math.round(shapeStyle.reflectionScaleY));
5182
+ }
5183
+ if (typeof shapeStyle.reflectionSkewX === "number") {
5184
+ reflectionXml["@_kx"] = String(Math.round(shapeStyle.reflectionSkewX));
5185
+ }
5186
+ if (typeof shapeStyle.reflectionSkewY === "number") {
5187
+ reflectionXml["@_ky"] = String(Math.round(shapeStyle.reflectionSkewY));
5188
+ }
5189
+ if (shapeStyle.reflectionAlignment) {
5190
+ reflectionXml["@_algn"] = shapeStyle.reflectionAlignment;
5191
+ }
5192
+ if (typeof shapeStyle.reflectionRotateWithShape === "boolean") {
5193
+ reflectionXml["@_rotWithShape"] = shapeStyle.reflectionRotateWithShape ? "1" : "0";
5194
+ }
5195
+ if (typeof shapeStyle.reflectionStartPosition === "number") {
5196
+ reflectionXml["@_stPos"] = String(Math.round(shapeStyle.reflectionStartPosition * 1e5));
5197
+ }
4912
5198
  return reflectionXml;
4913
5199
  }
4914
5200
  buildBlurXml(shapeStyle) {
@@ -5016,6 +5302,9 @@ var PptxShapeEffectXmlCodec = class {
5016
5302
  buildOuterShadowXml(shapeStyle) {
5017
5303
  return this.builder.buildOuterShadowXml(shapeStyle);
5018
5304
  }
5305
+ buildPresetShadowXml(shapeStyle) {
5306
+ return this.builder.buildPresetShadowXml(shapeStyle);
5307
+ }
5019
5308
  buildInnerShadowXml(shapeStyle) {
5020
5309
  return this.builder.buildInnerShadowXml(shapeStyle);
5021
5310
  }
@@ -5176,6 +5465,9 @@ var PptxColorStyleCodec = class {
5176
5465
  buildOuterShadowXml(shapeStyle) {
5177
5466
  return this.shapeEffectXmlCodec.buildOuterShadowXml(shapeStyle);
5178
5467
  }
5468
+ buildPresetShadowXml(shapeStyle) {
5469
+ return this.shapeEffectXmlCodec.buildPresetShadowXml(shapeStyle);
5470
+ }
5179
5471
  buildInnerShadowXml(shapeStyle) {
5180
5472
  return this.shapeEffectXmlCodec.buildInnerShadowXml(shapeStyle);
5181
5473
  }
@@ -5197,6 +5489,15 @@ var PptxColorStyleCodec = class {
5197
5489
  extractGradientFillColor(gradFill) {
5198
5490
  return this.gradientStyleCodec.extractGradientFillColor(gradFill);
5199
5491
  }
5492
+ extractGradientFlip(gradFill) {
5493
+ return this.gradientStyleCodec.extractGradientFlip(gradFill);
5494
+ }
5495
+ extractGradientRotWithShape(gradFill) {
5496
+ return this.gradientStyleCodec.extractGradientRotWithShape(gradFill);
5497
+ }
5498
+ extractGradientScaled(gradFill) {
5499
+ return this.gradientStyleCodec.extractGradientScaled(gradFill);
5500
+ }
5200
5501
  extractGradientPathType(gradFill) {
5201
5502
  return this.gradientStyleCodec.extractGradientPathType(gradFill);
5202
5503
  }
@@ -5208,6 +5509,61 @@ var PptxColorStyleCodec = class {
5208
5509
  }
5209
5510
  };
5210
5511
 
5512
+ // src/core/utils/color-xml-preservation.ts
5513
+ var COLOR_CHOICE_KEYS = [
5514
+ "a:srgbClr",
5515
+ "a:schemeClr",
5516
+ "a:sysClr",
5517
+ "a:prstClr",
5518
+ "a:scrgbClr",
5519
+ "a:hslClr"
5520
+ ];
5521
+ function extractColorChoiceXml(parent) {
5522
+ if (!parent) {
5523
+ return void 0;
5524
+ }
5525
+ for (const key of COLOR_CHOICE_KEYS) {
5526
+ if (parent[key] !== void 0) {
5527
+ return { [key]: parent[key] };
5528
+ }
5529
+ }
5530
+ return void 0;
5531
+ }
5532
+ function normalizeHex(value) {
5533
+ const raw = String(value ?? "").trim();
5534
+ if (raw.length === 0) {
5535
+ return "";
5536
+ }
5537
+ const hex = raw.replace(/^#/, "");
5538
+ if (/^[0-9a-fA-F]{6}$/.test(hex)) {
5539
+ return hex.toUpperCase();
5540
+ }
5541
+ return raw.toLowerCase();
5542
+ }
5543
+ function colorsEqual(left, right) {
5544
+ if (left === void 0 || right === void 0) {
5545
+ return false;
5546
+ }
5547
+ return normalizeHex(left) === normalizeHex(right);
5548
+ }
5549
+ function buildSrgbColorChoice(hex, opacity) {
5550
+ const normalized = String(hex || "").replace(/^#/, "");
5551
+ const srgb = { "@_val": normalized };
5552
+ if (typeof opacity === "number" && Number.isFinite(opacity) && opacity >= 0 && opacity < 1) {
5553
+ const alphaPct = Math.round(Math.max(0, Math.min(1, opacity)) * 1e5);
5554
+ srgb["a:alpha"] = { "@_val": String(alphaPct) };
5555
+ }
5556
+ return { "a:srgbClr": srgb };
5557
+ }
5558
+ function serializeColorChoice(originalColorXml, currentResolvedHex, fallbackHex, opacity, options = {}) {
5559
+ if (originalColorXml && colorsEqual(currentResolvedHex, fallbackHex)) {
5560
+ if (options.preserveAlphaFromOriginal !== false) {
5561
+ return originalColorXml;
5562
+ }
5563
+ }
5564
+ return buildSrgbColorChoice(fallbackHex, opacity);
5565
+ }
5566
+
5211
5567
  // src/core/core/builders/shape-style-3d-helpers.ts
5212
5568
  function applyScene3dStyle(shapeProps, style) {
5213
5569
  const scene3dNode = shapeProps["a:scene3d"];
@@ -5293,6 +5649,10 @@ function applyStrokeColor(lineNode, style, context) {
5293
5649
  const lineFill = lineNode["a:solidFill"];
5294
5650
  style.strokeColor = context.parseColor(lineFill);
5295
5651
  style.strokeOpacity = context.extractColorOpacity(lineFill);
5652
+ const strokeColorXml = extractColorChoiceXml(lineFill);
5653
+ if (strokeColorXml) {
5654
+ style.strokeColorXml = strokeColorXml;
5655
+ }
5296
5656
  } else if (lineNode["a:gradFill"]) {
5297
5657
  style.strokeColor = context.extractGradientFillColor(lineNode["a:gradFill"]);
5298
5658
  style.strokeOpacity = context.extractGradientOpacity(lineNode["a:gradFill"]);
@@ -5360,6 +5720,14 @@ function applyJoinCapCompound(lineNode, style) {
5360
5720
  style.lineJoin = "bevel";
5361
5721
  } else if ("a:miter" in lineNode) {
5362
5722
  style.lineJoin = "miter";
5723
+ const miterNode = lineNode["a:miter"];
5724
+ const limRaw = miterNode?.["@_lim"];
5725
+ if (limRaw !== void 0 && limRaw !== "") {
5726
+ const parsed = parseInt(String(limRaw), 10);
5727
+ if (Number.isFinite(parsed)) {
5728
+ style.miterLimit = parsed;
5729
+ }
5730
+ }
5363
5731
  }
5364
5732
  const capValue = String(lineNode["@_cap"] || "").trim().toLowerCase();
5365
5733
  if (capValue === "rnd" || capValue === "sq" || capValue === "flat") {
@@ -5416,6 +5784,10 @@ var PptxShapeStyleExtractor = class {
5416
5784
  style.fillMode = "solid";
5417
5785
  style.fillColor = this.context.parseColor(solidFill);
5418
5786
  style.fillOpacity = this.context.extractColorOpacity(solidFill);
5787
+ const solidFillColorXml = extractColorChoiceXml(solidFill);
5788
+ if (solidFillColorXml) {
5789
+ style.fillColorXml = solidFillColorXml;
5790
+ }
5419
5791
  } else if (gradFill) {
5420
5792
  style.fillMode = "gradient";
5421
5793
  style.fillColor = this.context.extractGradientFillColor(gradFill);
@@ -5427,6 +5799,18 @@ var PptxShapeStyleExtractor = class {
5427
5799
  style.fillGradientPathType = this.context.extractGradientPathType(gradFill);
5428
5800
  style.fillGradientFocalPoint = this.context.extractGradientFocalPoint(gradFill);
5429
5801
  style.fillGradientFillToRect = this.context.extractGradientFillToRect(gradFill);
5802
+ const gradFlip = this.context.extractGradientFlip(gradFill);
5803
+ if (gradFlip) {
5804
+ style.fillGradientFlip = gradFlip;
5805
+ }
5806
+ const gradRot = this.context.extractGradientRotWithShape(gradFill);
5807
+ if (gradRot !== void 0) {
5808
+ style.fillGradientRotWithShape = gradRot;
5809
+ }
5810
+ const gradScaled = this.context.extractGradientScaled(gradFill);
5811
+ if (gradScaled !== void 0) {
5812
+ style.fillGradientScaled = gradScaled;
5813
+ }
5430
5814
  } else if (pattFill) {
5431
5815
  style.fillMode = "pattern";
5432
5816
  style.fillColor = this.context.parseColor(pattFill["a:fgClr"]) || this.context.parseColor(pattFill["a:bgClr"]);
@@ -5508,10 +5892,45 @@ var PptxShapeStyleExtractor = class {
5508
5892
  if (styleNode?.["a:effectRef"]) {
5509
5893
  this.context.resolveThemeEffectRef(styleNode["a:effectRef"], style);
5510
5894
  }
5895
+ const fontRef = styleNode?.["a:fontRef"];
5896
+ if (fontRef) {
5897
+ const idxAttr = String(fontRef["@_idx"] || "").trim();
5898
+ if (idxAttr.length > 0) {
5899
+ style.fontRefIdx = idxAttr;
5900
+ }
5901
+ const overrideColorXml = this.extractFontRefColorXml(fontRef);
5902
+ if (overrideColorXml) {
5903
+ style.fontRefColorXml = overrideColorXml;
5904
+ }
5905
+ }
5511
5906
  applyScene3dStyle(shapeProps, style);
5512
5907
  applyShape3dStyle(shapeProps, style, this.context);
5513
5908
  return style;
5514
5909
  }
5910
+ /**
5911
+ * Pull the verbatim colour-choice child out of an `a:fontRef` element,
5912
+ * preserving any contained colour transforms for round-trip.
5913
+ */
5914
+ extractFontRefColorXml(refNode) {
5915
+ if (!refNode) {
5916
+ return void 0;
5917
+ }
5918
+ const keys = [
5919
+ "a:scrgbClr",
5920
+ "a:srgbClr",
5921
+ "a:hslClr",
5922
+ "a:sysClr",
5923
+ "a:schemeClr",
5924
+ "a:prstClr"
5925
+ ];
5926
+ for (const key of keys) {
5927
+ const child = refNode[key];
5928
+ if (child !== void 0) {
5929
+ return { [key]: child };
5930
+ }
5931
+ }
5932
+ return void 0;
5933
+ }
5515
5934
  /**
5516
5935
  * Extract p14:hiddenFill from the shape properties extension list.
5517
5936
  * URI: {AF507438-7753-43E0-B8FC-AC1667EBCBE1}
@@ -5562,10 +5981,15 @@ var PptxShapeStyleExtractor = class {
5562
5981
  function applyCellFillStyle(cellProperties, style, context) {
5563
5982
  let hasStyle = false;
5564
5983
  if (cellProperties?.["a:solidFill"]) {
5565
- const fillColor = context.parseColor(cellProperties["a:solidFill"]);
5984
+ const solidFillNode = cellProperties["a:solidFill"];
5985
+ const fillColor = context.parseColor(solidFillNode);
5566
5986
  if (fillColor) {
5567
5987
  style.fillMode = "solid";
5568
5988
  style.backgroundColor = fillColor;
5989
+ const bgColorXml = extractColorChoiceXml(solidFillNode);
5990
+ if (bgColorXml) {
5991
+ style.backgroundColorXml = bgColorXml;
5992
+ }
5569
5993
  hasStyle = true;
5570
5994
  }
5571
5995
  }
@@ -5602,6 +6026,10 @@ function applyCellFillStyle(cellProperties, style, context) {
5602
6026
  }
5603
6027
  }
5604
6028
  }
6029
+ if (cellProperties?.["a:noFill"] !== void 0) {
6030
+ style.fillMode = "none";
6031
+ hasStyle = true;
6032
+ }
5605
6033
  if (cellProperties?.["a:pattFill"]) {
5606
6034
  const pattFill = cellProperties["a:pattFill"];
5607
6035
  const fgColor = context.parseColor(pattFill["a:fgClr"]);
@@ -5908,8 +6336,7 @@ var PptxTableDataParser = class {
5908
6336
  return width / totalWidthEmu;
5909
6337
  }) : gridColumns.map(() => 1 / Math.max(gridColumns.length, 1));
5910
6338
  const tableProperties = tableNode["a:tblPr"] || {};
5911
- const tableStyleNode = tableProperties["a:tblStyle"];
5912
- const tableStyleId = String(tableStyleNode?.["@_val"] || tableProperties["@_tblStyle"] || "").trim() || void 0;
6339
+ const tableStyleId = this.extractTableStyleId(tableProperties);
5913
6340
  const xmlRows = this.context.ensureArray(tableNode["a:tr"]);
5914
6341
  const rows = xmlRows.map((rowNode) => {
5915
6342
  const rowHeightEmu = parseInt(String(rowNode?.["@_h"] || "0"), 10) || 0;
@@ -5944,6 +6371,28 @@ var PptxTableDataParser = class {
5944
6371
  return void 0;
5945
6372
  }
5946
6373
  }
6374
+ /**
6375
+ * Read the table style ID from `a:tblPr`.
6376
+ *
6377
+ * ECMA-376 §21.1.3.13 defines `<a:tableStyleId>{GUID}</a:tableStyleId>` as
6378
+ * a child element of `a:tblPr` carrying the GUID as element text. Older
6379
+ * inputs (and earlier versions of this library) used the legacy
6380
+ * `<a:tblStyle val="{GUID}"/>` child element or a `@_tblStyle` attribute.
6381
+ * Accept all three; the spec form takes precedence.
6382
+ */
6383
+ extractTableStyleId(tableProperties) {
6384
+ const tableStyleIdNode = tableProperties["a:tableStyleId"];
6385
+ if (tableStyleIdNode !== void 0 && tableStyleIdNode !== null) {
6386
+ const direct = typeof tableStyleIdNode === "string" || typeof tableStyleIdNode === "number" ? String(tableStyleIdNode) : String(tableStyleIdNode["#text"] ?? "");
6387
+ const trimmed = direct.trim();
6388
+ if (trimmed.length > 0) {
6389
+ return trimmed;
6390
+ }
6391
+ }
6392
+ const tableStyleNode = tableProperties["a:tblStyle"];
6393
+ const legacy = String(tableStyleNode?.["@_val"] || tableProperties["@_tblStyle"] || "").trim();
6394
+ return legacy.length > 0 ? legacy : void 0;
6395
+ }
5947
6396
  extractTableCellText(tableCell) {
5948
6397
  const paragraphs = this.context.ensureArray(tableCell?.["a:txBody"]?.["a:p"]);
5949
6398
  const lines = [];
@@ -6240,6 +6689,19 @@ var PptxGraphicFrameParser = class {
6240
6689
  if (graphicData["a:videoFile"] || graphicData["a:audioFile"] || uri.includes("/drawingml/2006/media")) {
6241
6690
  return "media";
6242
6691
  }
6692
+ if (graphicData["aink:ink"] || uri.includes("/2010/ink") || uri.includes("drawing/2010/ink")) {
6693
+ return "ink";
6694
+ }
6695
+ const alternateContent = graphicData["mc:AlternateContent"];
6696
+ if (alternateContent) {
6697
+ const choices = Array.isArray(alternateContent["mc:Choice"]) ? alternateContent["mc:Choice"] : alternateContent["mc:Choice"] ? [alternateContent["mc:Choice"]] : [];
6698
+ for (const choice of choices) {
6699
+ const requires = String(choice?.["@_Requires"] || "").toLowerCase();
6700
+ if (requires.includes("aink") || choice?.["aink:ink"]) {
6701
+ return "ink";
6702
+ }
6703
+ }
6704
+ }
6243
6705
  return "unknown";
6244
6706
  }
6245
6707
  };
@@ -7141,6 +7603,7 @@ var PptxDocumentPropertiesUpdater = class {
7141
7603
  }));
7142
7604
  if (sanitized.length === 0) {
7143
7605
  this.context.zip.remove("docProps/custom.xml");
7606
+ await this.removeCustomPropertiesPackagingArtifacts();
7144
7607
  return;
7145
7608
  }
7146
7609
  const customXml = {
@@ -7160,6 +7623,116 @@ var PptxDocumentPropertiesUpdater = class {
7160
7623
  }
7161
7624
  };
7162
7625
  this.context.zip.file("docProps/custom.xml", this.context.builder.build(customXml));
7626
+ await this.ensureCustomPropertiesPackagingArtifacts();
7627
+ }
7628
+ /**
7629
+ * Ensure `[Content_Types].xml` has an `Override` for `docProps/custom.xml`
7630
+ * and the root `_rels/.rels` references it (ECMA-376 §15.2.12.2 +
7631
+ * Part 2 §10.1.2.5). Without these, the package fails OPC validation
7632
+ * and Office strips the custom properties on next save.
7633
+ */
7634
+ async ensureCustomPropertiesPackagingArtifacts() {
7635
+ const customContentType = "application/vnd.openxmlformats-officedocument.custom-properties+xml";
7636
+ const customRelType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties";
7637
+ const ctFile = this.context.zip.file("[Content_Types].xml");
7638
+ if (ctFile) {
7639
+ try {
7640
+ const ctXml = await ctFile.async("string");
7641
+ const ctData = this.context.parser.parse(ctXml);
7642
+ const types = ctData["Types"];
7643
+ if (types) {
7644
+ const overrides = Array.isArray(types["Override"]) ? types["Override"] : types["Override"] ? [types["Override"]] : [];
7645
+ const hasCustomOverride = overrides.some(
7646
+ (o) => String(o?.["@_PartName"] || "") === "/docProps/custom.xml"
7647
+ );
7648
+ if (!hasCustomOverride) {
7649
+ overrides.push({
7650
+ "@_PartName": "/docProps/custom.xml",
7651
+ "@_ContentType": customContentType
7652
+ });
7653
+ types["Override"] = overrides.length === 1 ? overrides[0] : overrides;
7654
+ this.context.zip.file("[Content_Types].xml", this.context.builder.build(ctData));
7655
+ }
7656
+ }
7657
+ } catch (error) {
7658
+ console.warn("Failed to update [Content_Types].xml for custom properties:", error);
7659
+ }
7660
+ }
7661
+ const relsFile = this.context.zip.file("_rels/.rels");
7662
+ if (relsFile) {
7663
+ try {
7664
+ const relsXml = await relsFile.async("string");
7665
+ const relsData = this.context.parser.parse(relsXml);
7666
+ const relationships = relsData["Relationships"];
7667
+ if (relationships) {
7668
+ const rels = Array.isArray(relationships["Relationship"]) ? relationships["Relationship"] : relationships["Relationship"] ? [relationships["Relationship"]] : [];
7669
+ const hasCustomRel = rels.some((r) => String(r?.["@_Type"] || "") === customRelType);
7670
+ if (!hasCustomRel) {
7671
+ let maxId = 0;
7672
+ for (const rel of rels) {
7673
+ const id = String(rel?.["@_Id"] || "");
7674
+ const num = Number.parseInt(id.replace(/^rId/, ""), 10);
7675
+ if (Number.isFinite(num) && num > maxId) {
7676
+ maxId = num;
7677
+ }
7678
+ }
7679
+ rels.push({
7680
+ "@_Id": `rId${maxId + 1}`,
7681
+ "@_Type": customRelType,
7682
+ "@_Target": "docProps/custom.xml"
7683
+ });
7684
+ relationships["Relationship"] = rels;
7685
+ this.context.zip.file("_rels/.rels", this.context.builder.build(relsData));
7686
+ }
7687
+ }
7688
+ } catch (error) {
7689
+ console.warn("Failed to update _rels/.rels for custom properties:", error);
7690
+ }
7691
+ }
7692
+ }
7693
+ /**
7694
+ * Remove the Override + root rel for `docProps/custom.xml` when the
7695
+ * caller has emptied custom properties so the package doesn't keep an
7696
+ * orphan content-type entry referencing a deleted part.
7697
+ */
7698
+ async removeCustomPropertiesPackagingArtifacts() {
7699
+ const customRelType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties";
7700
+ const ctFile = this.context.zip.file("[Content_Types].xml");
7701
+ if (ctFile) {
7702
+ try {
7703
+ const ctXml = await ctFile.async("string");
7704
+ const ctData = this.context.parser.parse(ctXml);
7705
+ const types = ctData["Types"];
7706
+ if (types) {
7707
+ const overrides = Array.isArray(types["Override"]) ? types["Override"] : types["Override"] ? [types["Override"]] : [];
7708
+ const filtered = overrides.filter(
7709
+ (o) => String(o?.["@_PartName"] || "") !== "/docProps/custom.xml"
7710
+ );
7711
+ if (filtered.length !== overrides.length) {
7712
+ types["Override"] = filtered.length === 1 ? filtered[0] : filtered;
7713
+ this.context.zip.file("[Content_Types].xml", this.context.builder.build(ctData));
7714
+ }
7715
+ }
7716
+ } catch {
7717
+ }
7718
+ }
7719
+ const relsFile = this.context.zip.file("_rels/.rels");
7720
+ if (relsFile) {
7721
+ try {
7722
+ const relsXml = await relsFile.async("string");
7723
+ const relsData = this.context.parser.parse(relsXml);
7724
+ const relationships = relsData["Relationships"];
7725
+ if (relationships) {
7726
+ const rels = Array.isArray(relationships["Relationship"]) ? relationships["Relationship"] : relationships["Relationship"] ? [relationships["Relationship"]] : [];
7727
+ const filtered = rels.filter((r) => String(r?.["@_Type"] || "") !== customRelType);
7728
+ if (filtered.length !== rels.length) {
7729
+ relationships["Relationship"] = filtered;
7730
+ this.context.zip.file("_rels/.rels", this.context.builder.build(relsData));
7731
+ }
7732
+ }
7733
+ } catch {
7734
+ }
7735
+ }
7163
7736
  }
7164
7737
  normalizeCustomPropertyType(type) {
7165
7738
  const supportedTypes = /* @__PURE__ */ new Set([
@@ -7512,6 +8085,7 @@ var PptxSlideLoaderService = class {
7512
8085
  await params.loadSlideRelationships(path, slideRelsPath);
7513
8086
  const clrMapOverride = params.parseSlideClrMapOverride(slideXmlObj);
7514
8087
  params.setCurrentSlideClrMapOverride(clrMapOverride);
8088
+ await params.setActiveMasterForSlide?.(path);
7515
8089
  let restoreThemeOverride;
7516
8090
  try {
7517
8091
  const layoutPathForOverride = params.findLayoutPathForSlide(path);
@@ -12487,6 +13061,20 @@ var AXIS_TYPE_MAP = {
12487
13061
  dateAx: "dateAx",
12488
13062
  serAx: "serAx"
12489
13063
  };
13064
+ function upsertChartAxisChild(parent, localName, value, getLocalName) {
13065
+ const existingKey = Object.keys(parent).find((k) => getLocalName(k) === localName);
13066
+ if (value === void 0) {
13067
+ if (existingKey) {
13068
+ delete parent[existingKey];
13069
+ }
13070
+ return;
13071
+ }
13072
+ if (existingKey) {
13073
+ parent[existingKey]["@_val"] = value;
13074
+ } else {
13075
+ parent[`c:${localName}`] = { "@_val": value };
13076
+ }
13077
+ }
12490
13078
  function parseChartAxes(plotArea, xmlLookup, colorParser, getLocalName) {
12491
13079
  const result = [];
12492
13080
  for (const key of Object.keys(plotArea)) {
@@ -12607,6 +13195,27 @@ function parseSingleAxis(axisNode, axisType, xmlLookup, colorParser) {
12607
13195
  if (dispUnitsNode) {
12608
13196
  parseDisplayUnits(dispUnitsNode, xmlLookup, result);
12609
13197
  }
13198
+ const majorUnitNode = xmlLookup.getChildByLocalName(axisNode, "majorUnit");
13199
+ if (majorUnitNode) {
13200
+ const majorVal = parseFloat(String(majorUnitNode["@_val"]));
13201
+ if (Number.isFinite(majorVal)) {
13202
+ result.majorUnit = majorVal;
13203
+ }
13204
+ }
13205
+ const minorUnitNode = xmlLookup.getChildByLocalName(axisNode, "minorUnit");
13206
+ if (minorUnitNode) {
13207
+ const minorVal = parseFloat(String(minorUnitNode["@_val"]));
13208
+ if (Number.isFinite(minorVal)) {
13209
+ result.minorUnit = minorVal;
13210
+ }
13211
+ }
13212
+ const tickLblPosNode = xmlLookup.getChildByLocalName(axisNode, "tickLblPos");
13213
+ if (tickLblPosNode) {
13214
+ const v = String(tickLblPosNode["@_val"] || "").trim();
13215
+ if (v === "high" || v === "low" || v === "nextTo" || v === "none") {
13216
+ result.tickLblPos = v;
13217
+ }
13218
+ }
12610
13219
  return result;
12611
13220
  }
12612
13221
  var VALID_DISPLAY_UNITS = /* @__PURE__ */ new Set([
@@ -13919,23 +14528,55 @@ var SHAPE_TREE_ELEMENT_TAGS = /* @__PURE__ */ new Set([
13919
14528
  "p16:model3D",
13920
14529
  ...VML_SHAPE_TAGS
13921
14530
  ]);
14531
+ function diagnoseSelection(ac) {
14532
+ const choices = ensureArray2(ac["mc:Choice"]);
14533
+ for (let i = 0; i < choices.length; i++) {
14534
+ const choice = choices[i];
14535
+ const requires = String(choice?.["@_Requires"] ?? "").trim();
14536
+ if (requires.length === 0 || areNamespacesSupported(requires)) {
14537
+ const resolved = resolveNestedAlternateContent(choice);
14538
+ return { branch: "choice", choiceIndex: i, resolved };
14539
+ }
14540
+ }
14541
+ const fallback = ac["mc:Fallback"];
14542
+ if (fallback) {
14543
+ return { branch: "fallback", resolved: resolveNestedAlternateContent(fallback) };
14544
+ }
14545
+ return void 0;
14546
+ }
13922
14547
  function unwrapAlternateContent(container) {
13923
14548
  const altContents = ensureArray2(container["mc:AlternateContent"]);
13924
14549
  if (altContents.length === 0) {
13925
- return;
14550
+ return [];
13926
14551
  }
14552
+ const blocks = [];
13927
14553
  for (const ac of altContents) {
13928
- const branch = selectAlternateContentBranch(ac);
13929
- if (!branch) {
14554
+ const diagnosis = diagnoseSelection(ac);
14555
+ if (!diagnosis) {
13930
14556
  continue;
13931
14557
  }
14558
+ const block = {
14559
+ rawAc: ac,
14560
+ selectedBranch: diagnosis.branch,
14561
+ choiceIndex: diagnosis.branch === "choice" ? diagnosis.choiceIndex : void 0,
14562
+ childRefs: []
14563
+ };
14564
+ const branch = diagnosis.resolved;
13932
14565
  for (const tag of SHAPE_TREE_ELEMENT_TAGS) {
13933
14566
  const children = ensureArray2(branch[tag]);
13934
14567
  if (children.length > 0) {
13935
14568
  container[tag] = [...ensureArray2(container[tag]), ...children];
14569
+ for (const child of children) {
14570
+ block.childRefs.push({ tag, node: child });
14571
+ }
13936
14572
  }
13937
14573
  }
14574
+ if (block.childRefs.length > 0) {
14575
+ blocks.push(block);
14576
+ }
13938
14577
  }
14578
+ delete container["mc:AlternateContent"];
14579
+ return blocks;
13939
14580
  }
13940
14581
  function isNamespaceSupported(ns) {
13941
14582
  return SUPPORTED_MC_NAMESPACES.has(ns);
@@ -13953,7 +14594,7 @@ function ensureArray2(val) {
13953
14594
 
13954
14595
  // src/core/utils/body-properties-parser.ts
13955
14596
  function parseBodyPrBooleanAttrs(bodyPr, textStyle) {
13956
- const parseBoolAttr = (attr) => {
14597
+ const parseBoolAttr2 = (attr) => {
13957
14598
  const raw = bodyPr[attr];
13958
14599
  if (raw === void 0) {
13959
14600
  return void 0;
@@ -13961,19 +14602,19 @@ function parseBodyPrBooleanAttrs(bodyPr, textStyle) {
13961
14602
  const val = String(raw).trim().toLowerCase();
13962
14603
  return val === "1" || val === "true";
13963
14604
  };
13964
- const compatLnSpc = parseBoolAttr("@_compatLnSpc");
14605
+ const compatLnSpc = parseBoolAttr2("@_compatLnSpc");
13965
14606
  if (compatLnSpc !== void 0) {
13966
14607
  textStyle.compatibleLineSpacing = compatLnSpc;
13967
14608
  }
13968
- const forceAA = parseBoolAttr("@_forceAA");
14609
+ const forceAA = parseBoolAttr2("@_forceAA");
13969
14610
  if (forceAA !== void 0) {
13970
14611
  textStyle.forceAntiAlias = forceAA;
13971
14612
  }
13972
- const upright = parseBoolAttr("@_upright");
14613
+ const upright = parseBoolAttr2("@_upright");
13973
14614
  if (upright !== void 0) {
13974
14615
  textStyle.upright = upright;
13975
14616
  }
13976
- const fromWordArt = parseBoolAttr("@_fromWordArt");
14617
+ const fromWordArt = parseBoolAttr2("@_fromWordArt");
13977
14618
  if (fromWordArt !== void 0) {
13978
14619
  textStyle.fromWordArt = fromWordArt;
13979
14620
  }
@@ -13996,100 +14637,6 @@ function writeBodyPrBooleanAttrs(bodyPr, textStyle) {
13996
14637
  }
13997
14638
  }
13998
14639
 
13999
- // src/core/utils/theme-override-utils.ts
14000
- var COLOR_MAP_ALIAS_KEYS = [
14001
- "bg1",
14002
- "tx1",
14003
- "bg2",
14004
- "tx2",
14005
- "accent1",
14006
- "accent2",
14007
- "accent3",
14008
- "accent4",
14009
- "accent5",
14010
- "accent6",
14011
- "hlink",
14012
- "folHlink"
14013
- ];
14014
- var DEFAULT_COLOR_MAP = {
14015
- bg1: "lt1",
14016
- tx1: "dk1",
14017
- bg2: "lt2",
14018
- tx2: "dk2",
14019
- accent1: "accent1",
14020
- accent2: "accent2",
14021
- accent3: "accent3",
14022
- accent4: "accent4",
14023
- accent5: "accent5",
14024
- accent6: "accent6",
14025
- hlink: "hlink",
14026
- folHlink: "folHlink"
14027
- };
14028
- function buildClrMapOverrideXml(override) {
14029
- if (!override || Object.keys(override).length === 0) {
14030
- return { "a:masterClrMapping": {} };
14031
- }
14032
- const attrs2 = {};
14033
- for (const key of COLOR_MAP_ALIAS_KEYS) {
14034
- attrs2[`@_${key}`] = override[key] ?? DEFAULT_COLOR_MAP[key];
14035
- }
14036
- return { "a:overrideClrMapping": attrs2 };
14037
- }
14038
- function mergeThemeColorOverride(base, override) {
14039
- if (!override || Object.keys(override).length === 0) {
14040
- return { ...base };
14041
- }
14042
- const slotLookup = {};
14043
- for (const key of THEME_COLOR_SCHEME_KEYS) {
14044
- slotLookup[key] = base[key];
14045
- }
14046
- slotLookup["bg1"] = base.lt1;
14047
- slotLookup["tx1"] = base.dk1;
14048
- slotLookup["bg2"] = base.lt2;
14049
- slotLookup["tx2"] = base.dk2;
14050
- const result = { ...base };
14051
- for (const [alias, targetSlot] of Object.entries(override)) {
14052
- const resolvedColor = slotLookup[targetSlot] ?? base[targetSlot];
14053
- if (!resolvedColor) {
14054
- continue;
14055
- }
14056
- switch (alias) {
14057
- case "bg1":
14058
- result.lt1 = resolvedColor;
14059
- break;
14060
- case "tx1":
14061
- result.dk1 = resolvedColor;
14062
- break;
14063
- case "bg2":
14064
- result.lt2 = resolvedColor;
14065
- break;
14066
- case "tx2":
14067
- result.dk2 = resolvedColor;
14068
- break;
14069
- default: {
14070
- const schemeKey = alias;
14071
- if (schemeKey in result) {
14072
- result[schemeKey] = resolvedColor;
14073
- }
14074
- break;
14075
- }
14076
- }
14077
- }
14078
- return result;
14079
- }
14080
- function hasNonTrivialOverride(override) {
14081
- if (!override) {
14082
- return false;
14083
- }
14084
- for (const key of COLOR_MAP_ALIAS_KEYS) {
14085
- const overrideValue = override[key];
14086
- if (overrideValue && overrideValue !== DEFAULT_COLOR_MAP[key]) {
14087
- return true;
14088
- }
14089
- }
14090
- return false;
14091
- }
14092
-
14093
14640
  // src/core/utils/clone-utils.ts
14094
14641
  function cloneTextStyle(style) {
14095
14642
  if (!style) {
@@ -17130,6 +17677,100 @@ function resolveLayoutCategory(layoutType) {
17130
17677
  return "list";
17131
17678
  }
17132
17679
 
17680
+ // src/core/utils/theme-override-utils.ts
17681
+ var COLOR_MAP_ALIAS_KEYS = [
17682
+ "bg1",
17683
+ "tx1",
17684
+ "bg2",
17685
+ "tx2",
17686
+ "accent1",
17687
+ "accent2",
17688
+ "accent3",
17689
+ "accent4",
17690
+ "accent5",
17691
+ "accent6",
17692
+ "hlink",
17693
+ "folHlink"
17694
+ ];
17695
+ var DEFAULT_COLOR_MAP = {
17696
+ bg1: "lt1",
17697
+ tx1: "dk1",
17698
+ bg2: "lt2",
17699
+ tx2: "dk2",
17700
+ accent1: "accent1",
17701
+ accent2: "accent2",
17702
+ accent3: "accent3",
17703
+ accent4: "accent4",
17704
+ accent5: "accent5",
17705
+ accent6: "accent6",
17706
+ hlink: "hlink",
17707
+ folHlink: "folHlink"
17708
+ };
17709
+ function buildClrMapOverrideXml(override) {
17710
+ if (!override || Object.keys(override).length === 0) {
17711
+ return { "a:masterClrMapping": {} };
17712
+ }
17713
+ const attrs2 = {};
17714
+ for (const key of COLOR_MAP_ALIAS_KEYS) {
17715
+ attrs2[`@_${key}`] = override[key] ?? DEFAULT_COLOR_MAP[key];
17716
+ }
17717
+ return { "a:overrideClrMapping": attrs2 };
17718
+ }
17719
+ function mergeThemeColorOverride(base, override) {
17720
+ if (!override || Object.keys(override).length === 0) {
17721
+ return { ...base };
17722
+ }
17723
+ const slotLookup = {};
17724
+ for (const key of THEME_COLOR_SCHEME_KEYS) {
17725
+ slotLookup[key] = base[key];
17726
+ }
17727
+ slotLookup["bg1"] = base.lt1;
17728
+ slotLookup["tx1"] = base.dk1;
17729
+ slotLookup["bg2"] = base.lt2;
17730
+ slotLookup["tx2"] = base.dk2;
17731
+ const result = { ...base };
17732
+ for (const [alias, targetSlot] of Object.entries(override)) {
17733
+ const resolvedColor = slotLookup[targetSlot] ?? base[targetSlot];
17734
+ if (!resolvedColor) {
17735
+ continue;
17736
+ }
17737
+ switch (alias) {
17738
+ case "bg1":
17739
+ result.lt1 = resolvedColor;
17740
+ break;
17741
+ case "tx1":
17742
+ result.dk1 = resolvedColor;
17743
+ break;
17744
+ case "bg2":
17745
+ result.lt2 = resolvedColor;
17746
+ break;
17747
+ case "tx2":
17748
+ result.dk2 = resolvedColor;
17749
+ break;
17750
+ default: {
17751
+ const schemeKey = alias;
17752
+ if (schemeKey in result) {
17753
+ result[schemeKey] = resolvedColor;
17754
+ }
17755
+ break;
17756
+ }
17757
+ }
17758
+ }
17759
+ return result;
17760
+ }
17761
+ function hasNonTrivialOverride(override) {
17762
+ if (!override) {
17763
+ return false;
17764
+ }
17765
+ for (const key of COLOR_MAP_ALIAS_KEYS) {
17766
+ const overrideValue = override[key];
17767
+ if (overrideValue && overrideValue !== DEFAULT_COLOR_MAP[key]) {
17768
+ return true;
17769
+ }
17770
+ }
17771
+ return false;
17772
+ }
17773
+
17133
17774
  // src/core/utils/encryption-detection.ts
17134
17775
  var OLE_MAGIC = new Uint8Array([208, 207, 17, 224, 161, 27, 26, 225]);
17135
17776
  var ZIP_MAGIC = new Uint8Array([80, 75]);
@@ -24354,7 +24995,7 @@ async function repairPptx(buffer) {
24354
24995
  }
24355
24996
 
24356
24997
  // src/core/utils/theme-switching.ts
24357
- function normalizeHex(hex) {
24998
+ function normalizeHex2(hex) {
24358
24999
  if (!hex) {
24359
25000
  return "";
24360
25001
  }
@@ -24364,8 +25005,8 @@ function buildColorRemapTable(oldColorMap, newColorMap) {
24364
25005
  const remap = /* @__PURE__ */ new Map();
24365
25006
  const allKeys = [...THEME_COLOR_SCHEME_KEYS, "tx1", "bg1", "tx2", "bg2"];
24366
25007
  for (const key of allKeys) {
24367
- const oldVal = normalizeHex(oldColorMap[key]);
24368
- const newVal = normalizeHex(newColorMap[key]);
25008
+ const oldVal = normalizeHex2(oldColorMap[key]);
25009
+ const newVal = normalizeHex2(newColorMap[key]);
24369
25010
  if (oldVal && newVal && oldVal !== newVal) {
24370
25011
  remap.set(oldVal, `#${newVal}`);
24371
25012
  remap.set(`#${oldVal}`, `#${newVal}`);
@@ -24377,7 +25018,7 @@ function remapColor(color, remap) {
24377
25018
  if (!color) {
24378
25019
  return color;
24379
25020
  }
24380
- const normalized = normalizeHex(color);
25021
+ const normalized = normalizeHex2(color);
24381
25022
  const remapped = remap.get(normalized) ?? remap.get(`#${normalized}`);
24382
25023
  return remapped ?? color;
24383
25024
  }
@@ -24517,7 +25158,7 @@ function remapSlideColors(slide, remap) {
24517
25158
  function buildThemeColorMap(colorScheme) {
24518
25159
  const map = {};
24519
25160
  for (const key of THEME_COLOR_SCHEME_KEYS) {
24520
- map[key] = normalizeHex(colorScheme[key]);
25161
+ map[key] = normalizeHex2(colorScheme[key]);
24521
25162
  }
24522
25163
  map.tx1 = map.dk1;
24523
25164
  map.bg1 = map.lt1;
@@ -25490,8 +26131,11 @@ function relayoutSmartArt(smartArtData, containerWidth, containerHeight) {
25490
26131
 
25491
26132
  // src/core/core/runtime/PptxHandlerRuntimeSaveParagraphHelpers.ts
25492
26133
  var EMU_PER_PX5 = 9525;
25493
- function buildParagraphPropertiesXml(textStyle, paragraphAlign, bulletInfo, spacing) {
26134
+ function buildParagraphPropertiesXml(textStyle, paragraphAlign, bulletInfo, spacing, level) {
25494
26135
  const paragraphProps = {};
26136
+ if (typeof level === "number" && Number.isFinite(level) && level > 0) {
26137
+ paragraphProps["@_lvl"] = String(Math.min(Math.max(Math.round(level), 0), 8));
26138
+ }
25495
26139
  if (paragraphAlign) {
25496
26140
  paragraphProps["@_algn"] = paragraphAlign;
25497
26141
  }
@@ -25563,23 +26207,28 @@ function applyBulletProperties(paragraphProps, bulletInfo) {
25563
26207
  paragraphProps["a:buNone"] = {};
25564
26208
  return;
25565
26209
  }
25566
- if (bulletInfo.color) {
26210
+ if (bulletInfo.colorInherit) {
26211
+ paragraphProps["a:buClrTx"] = {};
26212
+ } else if (bulletInfo.color) {
25567
26213
  const colorHex = bulletInfo.color.replace("#", "");
25568
26214
  paragraphProps["a:buClr"] = {
25569
26215
  "a:srgbClr": { "@_val": colorHex }
25570
26216
  };
25571
26217
  }
25572
- if (bulletInfo.sizePercent !== void 0) {
26218
+ if (bulletInfo.sizeInherit) {
26219
+ paragraphProps["a:buSzTx"] = {};
26220
+ } else if (bulletInfo.sizePercent !== void 0) {
25573
26221
  paragraphProps["a:buSzPct"] = {
25574
26222
  "@_val": String(Math.round(bulletInfo.sizePercent * 1e3))
25575
26223
  };
25576
- }
25577
- if (bulletInfo.sizePts !== void 0) {
26224
+ } else if (bulletInfo.sizePts !== void 0) {
25578
26225
  paragraphProps["a:buSzPts"] = {
25579
26226
  "@_val": String(Math.round(bulletInfo.sizePts * 100))
25580
26227
  };
25581
26228
  }
25582
- if (bulletInfo.fontFamily) {
26229
+ if (bulletInfo.fontInherit) {
26230
+ paragraphProps["a:buFontTx"] = {};
26231
+ } else if (bulletInfo.fontFamily) {
25583
26232
  paragraphProps["a:buFont"] = {
25584
26233
  "@_typeface": bulletInfo.fontFamily
25585
26234
  };
@@ -25602,7 +26251,7 @@ function applyBulletProperties(paragraphProps, bulletInfo) {
25602
26251
  };
25603
26252
  }
25604
26253
  }
25605
- function assembleParagraphXml(runs, paragraphProps) {
26254
+ function assembleParagraphXml(runs, paragraphProps, endParaRunProperties) {
25606
26255
  const paragraph = {
25607
26256
  "a:pPr": paragraphProps
25608
26257
  };
@@ -25624,7 +26273,11 @@ function assembleParagraphXml(runs, paragraphProps) {
25624
26273
  if (cleanRegularRuns.length === 0 && fieldRuns.length === 0) {
25625
26274
  paragraph["a:r"] = runs.length > 1 ? runs : runs[0];
25626
26275
  }
25627
- paragraph["a:endParaRPr"] = { "@_lang": "en-US" };
26276
+ if (endParaRunProperties && typeof endParaRunProperties === "object") {
26277
+ paragraph["a:endParaRPr"] = endParaRunProperties;
26278
+ } else {
26279
+ paragraph["a:endParaRPr"] = { "@_lang": "en-US" };
26280
+ }
25628
26281
  return paragraph;
25629
26282
  }
25630
26283
  function computeUniformSegmentOverrides(textStyle, textSegments) {
@@ -25928,6 +26581,140 @@ var PptxHandlerRuntime = class {
25928
26581
  * `p:clrMapOvr / a:overrideClrMapping`.
25929
26582
  */
25930
26583
  currentSlideClrMapOverride = null;
26584
+ /**
26585
+ * Per-master colour map alias dictionaries parsed from each master's
26586
+ * `<p:clrMap>` element (e.g. `bg1 → lt1`, `tx1 → dk1`, `accent1 → accent1`).
26587
+ *
26588
+ * `clrMap` is the *aliasing* layer between logical colour names used in
26589
+ * DrawingML and the raw theme scheme slots. Per ECMA-376 §19.3.1.7 it
26590
+ * lives on each `p:sldMaster`, and slide layouts/slides may further
26591
+ * override it via `p:clrMapOvr`. Resolution must happen at colour-lookup
26592
+ * time, *not* by baking it into {@link themeColorMap}.
26593
+ *
26594
+ * Phase 2 Stream B / C-H4.
26595
+ */
26596
+ masterClrMaps = /* @__PURE__ */ new Map();
26597
+ /**
26598
+ * Per-master theme color maps. Each master may reference its own theme
26599
+ * file via `_rels/slideMasterN.xml.rels`. For multi-master decks, slides
26600
+ * must resolve scheme colours against their *own* master's theme.
26601
+ *
26602
+ * Falls back to {@link themeColorMap} when a master entry is missing.
26603
+ *
26604
+ * Phase 2 Stream B / C-H4.
26605
+ */
26606
+ masterThemeColorMaps = /* @__PURE__ */ new Map();
26607
+ /**
26608
+ * Per-master theme font maps. Same rationale as
26609
+ * {@link masterThemeColorMaps}: multi-master decks may have one font
26610
+ * scheme per theme.
26611
+ */
26612
+ masterThemeFontMaps = /* @__PURE__ */ new Map();
26613
+ /**
26614
+ * Per-master format schemes (fmtScheme). For multi-master decks each
26615
+ * master's slides should resolve fill/line/effect refs against the
26616
+ * matrix from that master's theme.
26617
+ */
26618
+ masterThemeFormatSchemes = /* @__PURE__ */ new Map();
26619
+ /**
26620
+ * Per-master mapping from slide-master path to the theme path it
26621
+ * references via `_rels/slideMasterN.xml.rels`. Populated by
26622
+ * {@link loadPerMasterThemes} during load. Used by the save-side
26623
+ * theme writer to know which themeN.xml to (re)emit for each master.
26624
+ *
26625
+ * Phase 4 Stream A / C-H3.
26626
+ */
26627
+ masterThemePaths = /* @__PURE__ */ new Map();
26628
+ /**
26629
+ * Per-script font tables for major and minor fonts. Captured per master
26630
+ * theme. Keys are master paths; values map `mj`/`mn` -> script tag (e.g.
26631
+ * `Hans`, `Hant`, `Arab`, `Hebr`, `Thai`, `Beng`, …) -> typeface name.
26632
+ *
26633
+ * Phase 4 Stream A / M4.
26634
+ */
26635
+ masterThemeMajorFontScripts = /* @__PURE__ */ new Map();
26636
+ masterThemeMinorFontScripts = /* @__PURE__ */ new Map();
26637
+ /**
26638
+ * Theme name attribute (`<a:theme @name>`) per master theme path.
26639
+ * Captured for byte-stable round-trip.
26640
+ */
26641
+ masterThemeNames = /* @__PURE__ */ new Map();
26642
+ /**
26643
+ * `<a:fontScheme @name>` per master theme path.
26644
+ */
26645
+ masterThemeFontSchemeNames = /* @__PURE__ */ new Map();
26646
+ /**
26647
+ * `<a:clrScheme @name>` per master theme path.
26648
+ */
26649
+ masterThemeColorSchemeNames = /* @__PURE__ */ new Map();
26650
+ /**
26651
+ * Raw original theme XML keyed by theme path. Captured at load-time.
26652
+ * Used by the save pipeline to passthrough the full theme XML when no
26653
+ * in-memory mutation has occurred — preserving fillStyleLst /
26654
+ * lnStyleLst / effectStyleLst / bgFillStyleLst /
26655
+ * extraClrSchemeLst / objectDefaults / extLst exactly as written.
26656
+ *
26657
+ * Phase 4 Stream A / C-H3.
26658
+ */
26659
+ originalThemeXmlByPath = /* @__PURE__ */ new Map();
26660
+ /**
26661
+ * Set of theme paths whose in-memory state has been mutated since
26662
+ * load. Saving a theme path that's NOT dirty is a no-op (the original
26663
+ * file already exists in the ZIP). Saving a dirty theme path
26664
+ * regenerates the part from in-memory state.
26665
+ *
26666
+ * Phase 4 Stream A / C-H3.
26667
+ */
26668
+ dirtyThemePaths = /* @__PURE__ */ new Set();
26669
+ /**
26670
+ * Per-master parsed `<p:txStyles>` (titleStyle/bodyStyle/otherStyle).
26671
+ * Populated by {@link enrichSlideMastersWithTxStyles} during load so the
26672
+ * inheritance chain can find the master text-style cascade without
26673
+ * re-parsing master XML on every lookup. Phase 4 Stream B / P-H1.
26674
+ */
26675
+ masterTxStylesCache = /* @__PURE__ */ new Map();
26676
+ /**
26677
+ * Captured `<a:objectDefaults>` snapshot per master theme path. The
26678
+ * full ECMA-376 inheritance chain (master / layout / placeholder /
26679
+ * objectDefaults) is non-trivial; we store the raw spDef/lnDef/txDef
26680
+ * subtrees and re-emit them verbatim for round-trip.
26681
+ *
26682
+ * Phase 4 Stream A / M5.
26683
+ */
26684
+ masterThemeObjectDefaults = /* @__PURE__ */ new Map();
26685
+ /**
26686
+ * Captured `<a:extraClrSchemeLst>` raw subtree per master theme path
26687
+ * for verbatim round-trip.
26688
+ *
26689
+ * Phase 4 Stream A.
26690
+ */
26691
+ masterThemeExtraClrSchemeLst = /* @__PURE__ */ new Map();
26692
+ /**
26693
+ * Captured `<a:custClrLst>` raw subtree per master theme path
26694
+ * for verbatim round-trip.
26695
+ *
26696
+ * Phase 4 Stream A.
26697
+ */
26698
+ masterThemeCustClrLst = /* @__PURE__ */ new Map();
26699
+ /**
26700
+ * Captured theme-level `<a:extLst>` raw subtree per master theme path.
26701
+ */
26702
+ masterThemeExtLst = /* @__PURE__ */ new Map();
26703
+ /**
26704
+ * Active master's clrMap for the slide currently being parsed. Walked
26705
+ * after `currentSlideClrMapOverride` (slide and layout overrides take
26706
+ * precedence). `null` means "fall through to themeColorMap directly".
26707
+ */
26708
+ currentMasterClrMap = null;
26709
+ /**
26710
+ * Snapshot of the global theme state taken right after
26711
+ * {@link loadThemeData} completes. Used as the fallback when a slide's
26712
+ * master has no per-master theme entry, so per-slide multi-master
26713
+ * switching does not leak the previous slide's master state.
26714
+ */
26715
+ globalThemeColorMapSnapshot = {};
26716
+ globalThemeFontMapSnapshot = {};
26717
+ globalThemeFormatSchemeSnapshot;
25931
26718
  /** Thumbnail image data from `docProps/thumbnail.jpeg` preserved for round-trip. */
25932
26719
  thumbnailData = null;
25933
26720
  /** Raw VBA project binary preserved for macro-enabled (.pptm) round-trip. */
@@ -25938,6 +26725,19 @@ var PptxHandlerRuntime = class {
25938
26725
  signatureDetection = null;
25939
26726
  /** Custom XML data parts parsed from `customXml/` in the OPC package. */
25940
26727
  customXmlParts = [];
26728
+ /**
26729
+ * Maps an element's `rawXml` reference to the `mc:AlternateContent`
26730
+ * envelope that originally wrapped it (CC-4). Populated during slide
26731
+ * (and `p:grpSp`) parsing; consulted at save time to re-emit the
26732
+ * original `<mc:Choice>` / `<mc:Fallback>` shape so legacy renderers
26733
+ * keep their fallback content.
26734
+ *
26735
+ * Multiple sibling elements may share the same `AlternateContentBlock`
26736
+ * value (a single AC envelope often wraps several child shapes — e.g.
26737
+ * `p14:media` + its `p:pic` fallback nest one each). WeakMap so AC
26738
+ * envelopes are GC'd if the parsed XmlObject is dropped.
26739
+ */
26740
+ alternateContentBlockByRawXml = /* @__PURE__ */ new WeakMap();
25941
26741
  /** Embedded fonts extracted during load, preserved for automatic re-embedding on save. */
25942
26742
  loadedEmbeddedFonts = [];
25943
26743
  /** Map of comment author IDs to display names (from `ppt/commentAuthors.xml`). */
@@ -27751,7 +28551,12 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
27751
28551
  const bgColor = this.parseBackgroundColor(bg);
27752
28552
  const spTree = master["p:cSld"]?.["p:spTree"];
27753
28553
  const placeholders = this.extractPlaceholderList(spTree);
27754
- return { path, backgroundColor: bgColor, placeholders };
28554
+ const result = { path, backgroundColor: bgColor, placeholders };
28555
+ const hf = parseHeaderFooterFlags(master["p:hf"]);
28556
+ if (hf) {
28557
+ result.headerFooter = hf;
28558
+ }
28559
+ return result;
27755
28560
  } catch (e) {
27756
28561
  console.warn("Failed to parse handout master:", e);
27757
28562
  return void 0;
@@ -27777,7 +28582,12 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
27777
28582
  const bgColor = this.parseBackgroundColor(bg);
27778
28583
  const spTree = master["p:cSld"]?.["p:spTree"];
27779
28584
  const placeholders = this.extractPlaceholderList(spTree);
27780
- return { path, backgroundColor: bgColor, placeholders };
28585
+ const result = { path, backgroundColor: bgColor, placeholders };
28586
+ const hf = parseHeaderFooterFlags(master["p:hf"]);
28587
+ if (hf) {
28588
+ result.headerFooter = hf;
28589
+ }
28590
+ return result;
27781
28591
  } catch (e) {
27782
28592
  console.warn("Failed to parse notes master:", e);
27783
28593
  return void 0;
@@ -27822,6 +28632,10 @@ var PptxHandlerRuntime9 = class extends PptxHandlerRuntime8 {
27822
28632
  const uVal = String(userDrawn).trim().toLowerCase();
27823
28633
  layout.userDrawn = uVal === "1" || uVal === "true";
27824
28634
  }
28635
+ const hf = parseHeaderFooterFlags(sldLayout["p:hf"]);
28636
+ if (hf) {
28637
+ layout.headerFooter = hf;
28638
+ }
27825
28639
  const clrMapOvr = sldLayout["p:clrMapOvr"];
27826
28640
  if (clrMapOvr && clrMapOvr["a:masterClrMapping"] === void 0) {
27827
28641
  const overrideNode = clrMapOvr["a:overrideClrMapping"];
@@ -28427,6 +29241,18 @@ function buildClrChangeNode(style) {
28427
29241
  }
28428
29242
 
28429
29243
  // src/core/core/runtime/PptxHandlerRuntimeSaveRunProperties.ts
29244
+ function applyFontMetadata(fontNode, panose, pitchFamily, charset) {
29245
+ if (panose && panose.length > 0) {
29246
+ fontNode["@_panose"] = panose;
29247
+ }
29248
+ if (typeof pitchFamily === "number" && Number.isFinite(pitchFamily)) {
29249
+ fontNode["@_pitchFamily"] = String(pitchFamily);
29250
+ }
29251
+ if (typeof charset === "number" && Number.isFinite(charset)) {
29252
+ fontNode["@_charset"] = String(charset);
29253
+ }
29254
+ return fontNode;
29255
+ }
28430
29256
  var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime11 {
28431
29257
  createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId) {
28432
29258
  const runProps = {
@@ -28484,6 +29310,12 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
28484
29310
  if (style.bookmark) {
28485
29311
  runProps["@_bmk"] = style.bookmark;
28486
29312
  }
29313
+ if (style.altLanguage) {
29314
+ runProps["@_altLang"] = style.altLanguage;
29315
+ }
29316
+ if (typeof style.smartTagId === "number" && Number.isFinite(style.smartTagId)) {
29317
+ runProps["@_smtId"] = String(style.smartTagId);
29318
+ }
28487
29319
  if (style.textOutlineWidth || style.textOutlineColor) {
28488
29320
  const lnObj = {};
28489
29321
  if (typeof style.textOutlineWidth === "number" && style.textOutlineWidth > 0) {
@@ -28499,11 +29331,12 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
28499
29331
  runProps["a:ln"] = lnObj;
28500
29332
  }
28501
29333
  if (style.color) {
28502
- runProps["a:solidFill"] = {
28503
- "a:srgbClr": {
28504
- "@_val": style.color.replace("#", "")
28505
- }
28506
- };
29334
+ const resolvedOriginalColor = style.colorXml ? this.parseColor(style.colorXml) : void 0;
29335
+ runProps["a:solidFill"] = serializeColorChoice(
29336
+ style.colorXml,
29337
+ resolvedOriginalColor,
29338
+ style.color
29339
+ );
28507
29340
  } else if (style.textFillGradientStops && style.textFillGradientStops.length > 0) {
28508
29341
  const gradStops = style.textFillGradientStops.filter((stop) => Boolean(stop?.color)).map((stop) => {
28509
29342
  const rawPos = (stop.position ?? 0) / 100;
@@ -28576,16 +29409,32 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
28576
29409
  };
28577
29410
  }
28578
29411
  if (style.fontFamily) {
28579
- runProps["a:latin"] = { "@_typeface": style.fontFamily };
28580
- runProps["a:ea"] = {
28581
- "@_typeface": style.eastAsiaFont || style.fontFamily
28582
- };
28583
- runProps["a:cs"] = {
28584
- "@_typeface": style.complexScriptFont || style.fontFamily
28585
- };
29412
+ runProps["a:latin"] = applyFontMetadata(
29413
+ { "@_typeface": style.fontFamily },
29414
+ style.latinFontPanose,
29415
+ style.latinFontPitchFamily,
29416
+ style.latinFontCharset
29417
+ );
29418
+ runProps["a:ea"] = applyFontMetadata(
29419
+ { "@_typeface": style.eastAsiaFont || style.fontFamily },
29420
+ style.eastAsiaFontPanose,
29421
+ style.eastAsiaFontPitchFamily,
29422
+ style.eastAsiaFontCharset
29423
+ );
29424
+ runProps["a:cs"] = applyFontMetadata(
29425
+ { "@_typeface": style.complexScriptFont || style.fontFamily },
29426
+ style.complexScriptFontPanose,
29427
+ style.complexScriptFontPitchFamily,
29428
+ style.complexScriptFontCharset
29429
+ );
28586
29430
  }
28587
29431
  if (style.symbolFont) {
28588
- runProps["a:sym"] = { "@_typeface": style.symbolFont };
29432
+ runProps["a:sym"] = applyFontMetadata(
29433
+ { "@_typeface": style.symbolFont },
29434
+ style.symbolFontPanose,
29435
+ style.symbolFontPitchFamily,
29436
+ style.symbolFontCharset
29437
+ );
28589
29438
  }
28590
29439
  if (style.hyperlink && resolveHyperlinkRelationshipId) {
28591
29440
  const hyperlinkTarget = String(style.hyperlink).trim();
@@ -28660,14 +29509,15 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
28660
29509
  lineSpacing: this.createLineSpacingXmlFromMultiplier(textStyle?.lineSpacing),
28661
29510
  lineSpacingExactPt: textStyle?.lineSpacingExactPt
28662
29511
  };
28663
- const createParagraph = (runs, bulletInfo) => {
29512
+ const createParagraph = (runs, bulletInfo, level, endParaRunProperties) => {
28664
29513
  const paragraphProps = buildParagraphPropertiesXml(
28665
29514
  textStyle,
28666
29515
  paragraphAlign,
28667
29516
  bulletInfo,
28668
- spacing
29517
+ spacing,
29518
+ level
28669
29519
  );
28670
- return assembleParagraphXml(runs, paragraphProps);
29520
+ return assembleParagraphXml(runs, paragraphProps, endParaRunProperties);
28671
29521
  };
28672
29522
  const createRun = (runText, style) => ({
28673
29523
  "a:rPr": this.createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId),
@@ -28715,13 +29565,19 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
28715
29565
  const paragraphs = [];
28716
29566
  let currentRuns = [];
28717
29567
  let currentBulletInfo;
29568
+ let currentLevel;
29569
+ let currentEndParaRunProperties;
28718
29570
  const pushParagraph = () => {
28719
29571
  if (currentRuns.length === 0) {
28720
29572
  currentRuns.push(createRun("", textStyle));
28721
29573
  }
28722
- paragraphs.push(createParagraph(currentRuns, currentBulletInfo));
29574
+ paragraphs.push(
29575
+ createParagraph(currentRuns, currentBulletInfo, currentLevel, currentEndParaRunProperties)
29576
+ );
28723
29577
  currentRuns = [];
28724
29578
  currentBulletInfo = void 0;
29579
+ currentLevel = void 0;
29580
+ currentEndParaRunProperties = void 0;
28725
29581
  };
28726
29582
  if (textSegments && textSegments.length > 0) {
28727
29583
  const uniformSegmentOverrides = computeUniformSegmentOverrides(textStyle, textSegments);
@@ -28733,8 +29589,16 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
28733
29589
  };
28734
29590
  const segmentText = String(segment.text ?? "");
28735
29591
  const lineParts = segmentText.split("\n");
28736
- if (currentRuns.length === 0 && segment.bulletInfo) {
28737
- currentBulletInfo = segment.bulletInfo;
29592
+ if (currentRuns.length === 0) {
29593
+ if (segment.bulletInfo) {
29594
+ currentBulletInfo = segment.bulletInfo;
29595
+ }
29596
+ if (segment.paragraphLevel !== void 0) {
29597
+ currentLevel = segment.paragraphLevel;
29598
+ }
29599
+ if (segment.endParaRunProperties) {
29600
+ currentEndParaRunProperties = segment.endParaRunProperties;
29601
+ }
28738
29602
  }
28739
29603
  lineParts.forEach((linePart, lineIndex) => {
28740
29604
  if (segment.rubyText !== void 0) {
@@ -28832,6 +29696,9 @@ var PptxHandlerRuntime14 = class extends PptxHandlerRuntime13 {
28832
29696
  };
28833
29697
 
28834
29698
  // src/core/core/runtime/PptxHandlerRuntimeSaveShapeXml.ts
29699
+ var OLE_OBJECT_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
29700
+ var IMAGE_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
29701
+ var OLE_GRAPHIC_DATA_URI = "http://schemas.openxmlformats.org/presentationml/2006/ole";
28835
29702
  var PptxHandlerRuntime15 = class _PptxHandlerRuntime extends PptxHandlerRuntime14 {
28836
29703
  /**
28837
29704
  * Build a `p:graphicFrame` XML skeleton for an SDK-created table.
@@ -28882,6 +29749,148 @@ var PptxHandlerRuntime15 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
28882
29749
  }
28883
29750
  };
28884
29751
  }
29752
+ /**
29753
+ * Build a `p:graphicFrame` XML skeleton for an OLE object element.
29754
+ *
29755
+ * Used both for SDK-created OLE elements (no `rawXml`) and to refresh
29756
+ * a few key attributes on a loaded element when the typed fields have
29757
+ * been mutated. The output is the canonical
29758
+ * `p:graphicFrame > a:graphic > a:graphicData uri="…/ole" > p:oleObj`
29759
+ * shape per ECMA-376 §19.3.1.34 / §13.3.4.
29760
+ *
29761
+ * The caller (`processSlideElement`) is responsible for ensuring the
29762
+ * embed / preview-image relationships referenced from `r:id` / `r:embed`
29763
+ * exist in the slide's rels file. This method does not register them
29764
+ * itself because the typed model does not currently carry the binary
29765
+ * payload — the binary part must already be in the package (loaded from
29766
+ * the original file). A fully-fabricated SDK OLE element therefore
29767
+ * still requires the consumer to attach the binary out-of-band; this
29768
+ * method simply emits a schema-valid envelope referencing the
29769
+ * specified relationship ID.
29770
+ */
29771
+ createOleGraphicFrameXml(el, embedRelationshipId) {
29772
+ const EMU = _PptxHandlerRuntime.EMU_PER_PX;
29773
+ const offX = String(Math.round(el.x * EMU));
29774
+ const offY = String(Math.round(el.y * EMU));
29775
+ const extCx = String(Math.round(Math.max(el.width, 1) * EMU));
29776
+ const extCy = String(Math.round(Math.max(el.height, 1) * EMU));
29777
+ const oleObj = {
29778
+ "@_showAsIcon": "0",
29779
+ "@_imgW": extCx,
29780
+ "@_imgH": extCy
29781
+ };
29782
+ if (el.oleProgId) {
29783
+ oleObj["@_progId"] = el.oleProgId;
29784
+ }
29785
+ if (el.oleName) {
29786
+ oleObj["@_name"] = el.oleName;
29787
+ }
29788
+ if (el.oleClsId) {
29789
+ oleObj["@_classid"] = el.oleClsId;
29790
+ }
29791
+ if (embedRelationshipId) {
29792
+ oleObj["@_r:id"] = embedRelationshipId;
29793
+ }
29794
+ if (el.isLinked) {
29795
+ oleObj["p:link"] = {
29796
+ "@_r:id": embedRelationshipId,
29797
+ "@_updateAutomatic": "1"
29798
+ };
29799
+ } else {
29800
+ oleObj["p:embed"] = {};
29801
+ }
29802
+ oleObj["p:pic"] = {
29803
+ "p:nvPicPr": {
29804
+ "p:cNvPr": { "@_id": "0", "@_name": el.oleName || "OleObject" },
29805
+ "p:cNvPicPr": {},
29806
+ "p:nvPr": {}
29807
+ },
29808
+ "p:blipFill": {
29809
+ "a:blip": {},
29810
+ "a:stretch": { "a:fillRect": {} }
29811
+ },
29812
+ "p:spPr": {
29813
+ "a:xfrm": {
29814
+ "a:off": { "@_x": offX, "@_y": offY },
29815
+ "a:ext": { "@_cx": extCx, "@_cy": extCy }
29816
+ },
29817
+ "a:prstGeom": { "@_prst": "rect", "a:avLst": {} }
29818
+ }
29819
+ };
29820
+ return {
29821
+ "p:nvGraphicFramePr": {
29822
+ "p:cNvPr": { "@_id": "0", "@_name": el.oleName || el.fileName || "OleObject" },
29823
+ "p:cNvGraphicFramePr": {
29824
+ "a:graphicFrameLocks": { "@_noChangeAspect": "1" }
29825
+ },
29826
+ "p:nvPr": {}
29827
+ },
29828
+ "p:xfrm": {
29829
+ "a:off": { "@_x": offX, "@_y": offY },
29830
+ "a:ext": { "@_cx": extCx, "@_cy": extCy }
29831
+ },
29832
+ "a:graphic": {
29833
+ "a:graphicData": {
29834
+ "@_uri": OLE_GRAPHIC_DATA_URI,
29835
+ "p:oleObj": oleObj
29836
+ }
29837
+ }
29838
+ };
29839
+ }
29840
+ /**
29841
+ * Refresh editable typed-field attributes on a loaded OLE graphicFrame's
29842
+ * raw XML. Only attributes that round-trip through the typed model
29843
+ * (`progId`, `name`, `classid`) are touched so unknown extension data
29844
+ * passes through verbatim.
29845
+ */
29846
+ applyOleTypedFieldUpdates(shape, el) {
29847
+ const oleObj = shape["a:graphic"]?.["a:graphicData"]?.["p:oleObj"];
29848
+ if (!oleObj) {
29849
+ return;
29850
+ }
29851
+ if (el.oleProgId) {
29852
+ oleObj["@_progId"] = el.oleProgId;
29853
+ }
29854
+ if (el.oleName !== void 0) {
29855
+ if (el.oleName.length > 0) {
29856
+ oleObj["@_name"] = el.oleName;
29857
+ } else {
29858
+ delete oleObj["@_name"];
29859
+ }
29860
+ }
29861
+ if (el.oleClsId) {
29862
+ oleObj["@_classid"] = el.oleClsId;
29863
+ }
29864
+ }
29865
+ /** Look up the existing OLE binary relationship ID for this slide, if any. */
29866
+ resolveOleEmbedRelationshipId(slideRelationships, oleTarget) {
29867
+ if (!oleTarget) {
29868
+ return void 0;
29869
+ }
29870
+ const normalisedTarget = oleTarget.replace(/^ppt\//, "../").replace(/^\/+/, "");
29871
+ const lowerTarget = normalisedTarget.toLowerCase();
29872
+ for (const rel of slideRelationships) {
29873
+ const relType = String(rel?.["@_Type"] || "");
29874
+ if (relType !== OLE_OBJECT_RELATIONSHIP_TYPE) {
29875
+ continue;
29876
+ }
29877
+ const target = String(rel?.["@_Target"] || "").toLowerCase().trim();
29878
+ if (target === lowerTarget || target.endsWith(lowerTarget) || lowerTarget.endsWith(target)) {
29879
+ const relId = String(rel?.["@_Id"] || "").trim();
29880
+ if (relId.length > 0) {
29881
+ return relId;
29882
+ }
29883
+ }
29884
+ }
29885
+ const fallback = slideRelationships.find(
29886
+ (rel) => String(rel?.["@_Type"] || "") === OLE_OBJECT_RELATIONSHIP_TYPE
29887
+ );
29888
+ const fallbackId = String(fallback?.["@_Id"] || "").trim();
29889
+ return fallbackId.length > 0 ? fallbackId : void 0;
29890
+ }
29891
+ /** Constants are exposed so the element-writer mixin can reuse them. */
29892
+ static OLE_OBJECT_RELATIONSHIP_TYPE = OLE_OBJECT_RELATIONSHIP_TYPE;
29893
+ static OLE_IMAGE_RELATIONSHIP_TYPE = IMAGE_RELATIONSHIP_TYPE;
28885
29894
  /**
28886
29895
  * Build a p:sp XML object for an ink annotation element.
28887
29896
  * Each ink path becomes a separate a:path within a:pathLst,
@@ -29198,6 +30207,9 @@ var PptxHandlerRuntime16 = class extends PptxHandlerRuntime15 {
29198
30207
  buildOuterShadowXml(shapeStyle) {
29199
30208
  return this.colorStyleCodec.buildOuterShadowXml(shapeStyle);
29200
30209
  }
30210
+ buildPresetShadowXml(shapeStyle) {
30211
+ return this.colorStyleCodec.buildPresetShadowXml(shapeStyle);
30212
+ }
29201
30213
  buildInnerShadowXml(shapeStyle) {
29202
30214
  return this.colorStyleCodec.buildInnerShadowXml(shapeStyle);
29203
30215
  }
@@ -29748,6 +30760,10 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
29748
30760
  const solidFill = runProperties["a:solidFill"];
29749
30761
  if (solidFill) {
29750
30762
  style.color = this.parseColor(solidFill);
30763
+ const colorXml = extractColorChoiceXml(solidFill);
30764
+ if (colorXml) {
30765
+ style.colorXml = colorXml;
30766
+ }
29751
30767
  }
29752
30768
  this.applyHyperlinkStyle(style, runProperties, relationshipMap);
29753
30769
  const capAttr = String(runProperties["@_cap"] || "").trim().toLowerCase();
@@ -29795,12 +30811,86 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
29795
30811
  if (bmk) {
29796
30812
  style.bookmark = bmk;
29797
30813
  }
30814
+ const altLang = String(runProperties["@_altLang"] || "").trim();
30815
+ if (altLang) {
30816
+ style.altLanguage = altLang;
30817
+ }
30818
+ if (runProperties["@_smtId"] !== void 0) {
30819
+ const smtIdRaw = Number.parseInt(String(runProperties["@_smtId"]), 10);
30820
+ if (Number.isFinite(smtIdRaw)) {
30821
+ style.smartTagId = smtIdRaw;
30822
+ }
30823
+ }
30824
+ this.applyTextFontMetadata(style, latin, "latin");
30825
+ this.applyTextFontMetadata(style, eastAsian, "eastAsia");
30826
+ this.applyTextFontMetadata(style, complexScript, "complexScript");
30827
+ this.applyTextFontMetadata(style, runProperties["a:sym"], "symbol");
29798
30828
  const runEffectList = runProperties["a:effectLst"];
29799
30829
  if (runEffectList) {
29800
30830
  this.applyTextRunEffects(style, runEffectList);
29801
30831
  }
29802
30832
  return style;
29803
30833
  }
30834
+ /**
30835
+ * Copy `@panose` / `@pitchFamily` / `@charset` from a font child node
30836
+ * (`a:latin`, `a:ea`, `a:cs`, `a:sym`) onto the matching `*Font*`
30837
+ * fields of `style`.
30838
+ */
30839
+ applyTextFontMetadata(style, fontNode, kind) {
30840
+ if (!fontNode) {
30841
+ return;
30842
+ }
30843
+ const panose = String(fontNode["@_panose"] || "").trim();
30844
+ const pitchRaw = fontNode["@_pitchFamily"];
30845
+ const charsetRaw = fontNode["@_charset"];
30846
+ const pitch = pitchRaw !== void 0 && pitchRaw !== null ? Number.parseInt(String(pitchRaw), 10) : void 0;
30847
+ const charset = charsetRaw !== void 0 && charsetRaw !== null ? Number.parseInt(String(charsetRaw), 10) : void 0;
30848
+ if (kind === "latin") {
30849
+ if (panose) {
30850
+ style.latinFontPanose = panose;
30851
+ }
30852
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30853
+ style.latinFontPitchFamily = pitch;
30854
+ }
30855
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30856
+ style.latinFontCharset = charset;
30857
+ }
30858
+ return;
30859
+ }
30860
+ if (kind === "eastAsia") {
30861
+ if (panose) {
30862
+ style.eastAsiaFontPanose = panose;
30863
+ }
30864
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30865
+ style.eastAsiaFontPitchFamily = pitch;
30866
+ }
30867
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30868
+ style.eastAsiaFontCharset = charset;
30869
+ }
30870
+ return;
30871
+ }
30872
+ if (kind === "complexScript") {
30873
+ if (panose) {
30874
+ style.complexScriptFontPanose = panose;
30875
+ }
30876
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30877
+ style.complexScriptFontPitchFamily = pitch;
30878
+ }
30879
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30880
+ style.complexScriptFontCharset = charset;
30881
+ }
30882
+ return;
30883
+ }
30884
+ if (panose) {
30885
+ style.symbolFontPanose = panose;
30886
+ }
30887
+ if (typeof pitch === "number" && Number.isFinite(pitch)) {
30888
+ style.symbolFontPitchFamily = pitch;
30889
+ }
30890
+ if (typeof charset === "number" && Number.isFinite(charset)) {
30891
+ style.symbolFontCharset = charset;
30892
+ }
30893
+ }
29804
30894
  };
29805
30895
 
29806
30896
  // src/core/core/runtime/PptxHandlerRuntimeTextEditing.ts
@@ -30236,7 +31326,7 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
30236
31326
  };
30237
31327
 
30238
31328
  // src/core/core/runtime/table-cell-save-helpers.ts
30239
- function writeCellFill(tcPr, style) {
31329
+ function writeCellFill(tcPr, style, resolveColorXml) {
30240
31330
  if (style.fillMode === "gradient" && style.gradientFillStops && style.gradientFillStops.length > 0) {
30241
31331
  delete tcPr["a:solidFill"];
30242
31332
  delete tcPr["a:pattFill"];
@@ -30315,11 +31405,12 @@ function writeCellFill(tcPr, style) {
30315
31405
  } else if (style.backgroundColor) {
30316
31406
  delete tcPr["a:gradFill"];
30317
31407
  delete tcPr["a:pattFill"];
30318
- tcPr["a:solidFill"] = {
30319
- "a:srgbClr": {
30320
- "@_val": style.backgroundColor.replace("#", "")
30321
- }
30322
- };
31408
+ const resolvedOriginal = style.backgroundColorXml && resolveColorXml ? resolveColorXml(style.backgroundColorXml) : void 0;
31409
+ tcPr["a:solidFill"] = serializeColorChoice(
31410
+ style.backgroundColorXml,
31411
+ resolvedOriginal,
31412
+ style.backgroundColor
31413
+ );
30323
31414
  }
30324
31415
  }
30325
31416
  function writeDiagonalBorders(tcPr, style, emuPerPx) {
@@ -30450,7 +31541,7 @@ var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30450
31541
  xmlCell["a:tcPr"] = {};
30451
31542
  }
30452
31543
  const tcPr = xmlCell["a:tcPr"];
30453
- writeCellFill(tcPr, style);
31544
+ writeCellFill(tcPr, style, (colorXml) => this.parseColor(colorXml));
30454
31545
  if (style.vAlign) {
30455
31546
  const vAlignMap = {
30456
31547
  top: "t",
@@ -30532,35 +31623,29 @@ var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
30532
31623
  }
30533
31624
  }
30534
31625
  }
30535
- if (style.marginLeft !== void 0 || style.marginRight !== void 0 || style.marginTop !== void 0 || style.marginBottom !== void 0) {
30536
- const emuPerPx = _PptxHandlerRuntime.EMU_PER_PX;
30537
- if (!tcPr["a:tcMar"]) {
30538
- tcPr["a:tcMar"] = {};
30539
- }
30540
- const tcMar = tcPr["a:tcMar"];
30541
- if (style.marginLeft !== void 0) {
30542
- tcMar["a:marL"] = {
30543
- "@_w": String(Math.round(style.marginLeft * emuPerPx))
30544
- };
30545
- }
30546
- if (style.marginRight !== void 0) {
30547
- tcMar["a:marR"] = {
30548
- "@_w": String(Math.round(style.marginRight * emuPerPx))
30549
- };
30550
- }
30551
- if (style.marginTop !== void 0) {
30552
- tcMar["a:marT"] = {
30553
- "@_w": String(Math.round(style.marginTop * emuPerPx))
30554
- };
30555
- }
30556
- if (style.marginBottom !== void 0) {
30557
- tcMar["a:marB"] = {
30558
- "@_w": String(Math.round(style.marginBottom * emuPerPx))
30559
- };
30560
- }
31626
+ const emuPerPx = _PptxHandlerRuntime.EMU_PER_PX;
31627
+ if (style.marginLeft !== void 0) {
31628
+ tcPr["@_marL"] = String(Math.round(style.marginLeft * emuPerPx));
31629
+ }
31630
+ if (style.marginRight !== void 0) {
31631
+ tcPr["@_marR"] = String(Math.round(style.marginRight * emuPerPx));
31632
+ }
31633
+ if (style.marginTop !== void 0) {
31634
+ tcPr["@_marT"] = String(Math.round(style.marginTop * emuPerPx));
31635
+ }
31636
+ if (style.marginBottom !== void 0) {
31637
+ tcPr["@_marB"] = String(Math.round(style.marginBottom * emuPerPx));
30561
31638
  }
31639
+ delete tcPr["a:tcMar"];
30562
31640
  writeDiagonalBorders(tcPr, style, _PptxHandlerRuntime.EMU_PER_PX);
30563
31641
  writeCellTextFormatting(xmlCell, style, this.ensureArray.bind(this));
31642
+ const reordered = reorderObjectKeys(tcPr, TC_PR_BORDERS_ORDER);
31643
+ for (const key of Object.keys(tcPr)) {
31644
+ delete tcPr[key];
31645
+ }
31646
+ for (const key of Object.keys(reordered)) {
31647
+ tcPr[key] = reordered[key];
31648
+ }
30564
31649
  }
30565
31650
  };
30566
31651
 
@@ -30664,6 +31749,49 @@ function createDefaultXmlCell() {
30664
31749
  // src/core/core/runtime/table-xml-rebuild.ts
30665
31750
  var GRID_COL_ID_EXT_URI = "{9D8B030D-6E8A-4147-A177-3AD203B41FA5}";
30666
31751
  var A16_NAMESPACE = "http://schemas.microsoft.com/office/drawing/2014/main";
31752
+ function ensureA16NamespaceOnSlideRoot(slideRoot) {
31753
+ if (!slideRoot["@_xmlns:a16"]) {
31754
+ slideRoot["@_xmlns:a16"] = A16_NAMESPACE;
31755
+ }
31756
+ if (!slideRoot["@_xmlns:mc"]) {
31757
+ slideRoot["@_xmlns:mc"] = "http://schemas.openxmlformats.org/markup-compatibility/2006";
31758
+ }
31759
+ const existingIgnorable = String(slideRoot["@_mc:Ignorable"] || "").trim();
31760
+ if (existingIgnorable.length === 0) {
31761
+ slideRoot["@_mc:Ignorable"] = "a16";
31762
+ return;
31763
+ }
31764
+ const tokens = existingIgnorable.split(/\s+/).filter((token) => token.length > 0);
31765
+ if (!tokens.includes("a16")) {
31766
+ tokens.push("a16");
31767
+ slideRoot["@_mc:Ignorable"] = tokens.join(" ");
31768
+ }
31769
+ }
31770
+ function slideContainsA16Element(node) {
31771
+ if (node === null || node === void 0) {
31772
+ return false;
31773
+ }
31774
+ if (Array.isArray(node)) {
31775
+ for (const entry of node) {
31776
+ if (slideContainsA16Element(entry)) {
31777
+ return true;
31778
+ }
31779
+ }
31780
+ return false;
31781
+ }
31782
+ if (typeof node !== "object") {
31783
+ return false;
31784
+ }
31785
+ for (const [key, value] of Object.entries(node)) {
31786
+ if (key.startsWith("a16:")) {
31787
+ return true;
31788
+ }
31789
+ if (slideContainsA16Element(value)) {
31790
+ return true;
31791
+ }
31792
+ }
31793
+ return false;
31794
+ }
30667
31795
  function randomColumnId() {
30668
31796
  return String(Math.floor(Math.random() * 4294967295));
30669
31797
  }
@@ -30694,8 +31822,10 @@ function rebuildTableXmlFromData(tbl, tableData, emuPerPx, ensureArrayFn) {
30694
31822
  "a:extLst": {
30695
31823
  "a:ext": {
30696
31824
  "@_uri": GRID_COL_ID_EXT_URI,
31825
+ // `xmlns:a16` is declared on the slide root by
31826
+ // `ensureA16NamespaceOnSlideRoot`; emitting it here too is
31827
+ // schema-redundant and PowerPoint flags it.
30697
31828
  "a16:colId": {
30698
- "@_xmlns:a16": A16_NAMESPACE,
30699
31829
  "@_val": existingColIds[i] || randomColumnId()
30700
31830
  }
30701
31831
  }
@@ -31054,26 +32184,64 @@ var PptxHandlerRuntime23 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
31054
32184
  continue;
31055
32185
  }
31056
32186
  const scalingNode = this.xmlLookupService.getChildByLocalName(axisNode, "scaling");
31057
- if (!scalingNode) {
31058
- continue;
32187
+ if (scalingNode) {
32188
+ if (matchingAxis.logBase !== void 0 && matchingAxis.logBase > 0) {
32189
+ const logBaseKey = Object.keys(scalingNode).find(
32190
+ (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32191
+ );
32192
+ if (logBaseKey) {
32193
+ scalingNode[logBaseKey]["@_val"] = String(matchingAxis.logBase);
32194
+ } else {
32195
+ scalingNode["c:logBase"] = {
32196
+ "@_val": String(matchingAxis.logBase)
32197
+ };
32198
+ }
32199
+ } else if (matchingAxis.logScale === false) {
32200
+ const logBaseKey = Object.keys(scalingNode).find(
32201
+ (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32202
+ );
32203
+ if (logBaseKey) {
32204
+ delete scalingNode[logBaseKey];
32205
+ }
32206
+ }
32207
+ this.upsertChartAxisChild(
32208
+ scalingNode,
32209
+ "min",
32210
+ matchingAxis.min !== void 0 ? String(matchingAxis.min) : void 0
32211
+ );
32212
+ this.upsertChartAxisChild(
32213
+ scalingNode,
32214
+ "max",
32215
+ matchingAxis.max !== void 0 ? String(matchingAxis.max) : void 0
32216
+ );
31059
32217
  }
31060
- if (matchingAxis.logBase !== void 0 && matchingAxis.logBase > 0) {
31061
- const logBaseKey = Object.keys(scalingNode).find(
31062
- (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32218
+ if (matchingAxis.numFmt) {
32219
+ const numFmtKey = Object.keys(axisNode).find(
32220
+ (k) => this.compatibilityService.getXmlLocalName(k) === "numFmt"
31063
32221
  );
31064
- if (logBaseKey) {
31065
- scalingNode[logBaseKey]["@_val"] = String(matchingAxis.logBase);
32222
+ const numFmtAttrs = {
32223
+ "@_formatCode": matchingAxis.numFmt.formatCode,
32224
+ "@_sourceLinked": matchingAxis.numFmt.sourceLinked ? "1" : "0"
32225
+ };
32226
+ if (numFmtKey) {
32227
+ axisNode[numFmtKey] = numFmtAttrs;
31066
32228
  } else {
31067
- scalingNode["c:logBase"] = {
31068
- "@_val": String(matchingAxis.logBase)
31069
- };
32229
+ axisNode["c:numFmt"] = numFmtAttrs;
31070
32230
  }
31071
- } else if (matchingAxis.logScale === false) {
31072
- const logBaseKey = Object.keys(scalingNode).find(
31073
- (k) => this.compatibilityService.getXmlLocalName(k) === "logBase"
32231
+ }
32232
+ this.upsertChartAxisChild(
32233
+ axisNode,
32234
+ "majorUnit",
32235
+ matchingAxis.majorUnit !== void 0 ? String(matchingAxis.majorUnit) : void 0
32236
+ );
32237
+ if (matchingAxis.tickLblPos !== void 0) {
32238
+ const tickLblKey = Object.keys(axisNode).find(
32239
+ (k) => this.compatibilityService.getXmlLocalName(k) === "tickLblPos"
31074
32240
  );
31075
- if (logBaseKey) {
31076
- delete scalingNode[logBaseKey];
32241
+ if (tickLblKey) {
32242
+ axisNode[tickLblKey]["@_val"] = matchingAxis.tickLblPos;
32243
+ } else {
32244
+ axisNode["c:tickLblPos"] = { "@_val": matchingAxis.tickLblPos };
31077
32245
  }
31078
32246
  }
31079
32247
  }
@@ -31086,6 +32254,18 @@ var PptxHandlerRuntime23 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
31086
32254
  }
31087
32255
  this.pendingChartUpdates = void 0;
31088
32256
  }
32257
+ /**
32258
+ * Upsert a `c:<localName>` child with `@_val` on an axis or scaling node.
32259
+ * When `value` is undefined, removes any existing child of that local name.
32260
+ */
32261
+ upsertChartAxisChild(parent, localName, value) {
32262
+ upsertChartAxisChild(
32263
+ parent,
32264
+ localName,
32265
+ value,
32266
+ (key) => this.compatibilityService.getXmlLocalName(key)
32267
+ );
32268
+ }
31089
32269
  /**
31090
32270
  * Update the cached point values in a chart reference node
31091
32271
  * (numRef/strRef or numLit/strLit).
@@ -32365,17 +33545,13 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32365
33545
  delete spPr["a:noFill"];
32366
33546
  delete spPr["a:gradFill"];
32367
33547
  delete spPr["a:blipFill"];
32368
- const solidFill = {
32369
- "a:srgbClr": {
32370
- "@_val": fillColor.replace("#", "")
32371
- }
32372
- };
32373
- if (typeof shapeStyle.fillOpacity === "number" && shapeStyle.fillOpacity >= 0 && shapeStyle.fillOpacity < 1) {
32374
- solidFill["a:srgbClr"]["a:alpha"] = {
32375
- "@_val": String(Math.round(this.clampUnitInterval(shapeStyle.fillOpacity) * 1e5))
32376
- };
32377
- }
32378
- spPr["a:solidFill"] = solidFill;
33548
+ const resolvedOriginal = shapeStyle.fillColorXml ? this.parseColor(shapeStyle.fillColorXml) : void 0;
33549
+ spPr["a:solidFill"] = serializeColorChoice(
33550
+ shapeStyle.fillColorXml,
33551
+ resolvedOriginal,
33552
+ fillColor,
33553
+ shapeStyle.fillOpacity
33554
+ );
32379
33555
  }
32380
33556
  }
32381
33557
  if (shapeStyle.strokeColor !== void 0) {
@@ -32390,17 +33566,13 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32390
33566
  delete lineNode["a:solidFill"];
32391
33567
  } else {
32392
33568
  delete lineNode["a:noFill"];
32393
- const lineFill = {
32394
- "a:srgbClr": {
32395
- "@_val": shapeStyle.strokeColor.replace("#", "")
32396
- }
32397
- };
32398
- if (typeof shapeStyle.strokeOpacity === "number" && shapeStyle.strokeOpacity >= 0 && shapeStyle.strokeOpacity < 1) {
32399
- lineFill["a:srgbClr"]["a:alpha"] = {
32400
- "@_val": String(Math.round(this.clampUnitInterval(shapeStyle.strokeOpacity) * 1e5))
32401
- };
32402
- }
32403
- lineNode["a:solidFill"] = lineFill;
33569
+ const resolvedStrokeOriginal = shapeStyle.strokeColorXml ? this.parseColor(shapeStyle.strokeColorXml) : void 0;
33570
+ lineNode["a:solidFill"] = serializeColorChoice(
33571
+ shapeStyle.strokeColorXml,
33572
+ resolvedStrokeOriginal,
33573
+ shapeStyle.strokeColor,
33574
+ shapeStyle.strokeOpacity
33575
+ );
32404
33576
  }
32405
33577
  }
32406
33578
  if (shapeStyle.strokeDash !== void 0) {
@@ -32481,7 +33653,11 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32481
33653
  } else if (shapeStyle.lineJoin === "bevel") {
32482
33654
  lineNode["a:bevel"] = {};
32483
33655
  } else if (shapeStyle.lineJoin === "miter") {
32484
- lineNode["a:miter"] = { "@_lim": "800000" };
33656
+ const miterNode = {};
33657
+ if (typeof shapeStyle.miterLimit === "number" && Number.isFinite(shapeStyle.miterLimit) && shapeStyle.miterLimit !== 8e5) {
33658
+ miterNode["@_lim"] = String(Math.round(shapeStyle.miterLimit));
33659
+ }
33660
+ lineNode["a:miter"] = miterNode;
32485
33661
  }
32486
33662
  }
32487
33663
  if (shapeStyle.lineCap !== void 0) {
@@ -32501,6 +33677,82 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32501
33677
  spPr["a:ln"]["a:effectLst"] = lineEffectListXml;
32502
33678
  }
32503
33679
  }
33680
+ /**
33681
+ * Serialize the shape's `<p:style>` block (CT_ShapeStyle §20.1.2.2.36)
33682
+ * from the persisted ref indices/colour XML. Emits children in spec
33683
+ * order: `lnRef → fillRef → effectRef → fontRef`.
33684
+ *
33685
+ * When the original shape XML already contained a `<p:style>` we mutate
33686
+ * that node in place so any unmodelled attributes/children are preserved.
33687
+ * When it didn't, we create one. When the shape no longer has any ref
33688
+ * data we leave the existing `<p:style>` (if any) untouched — silently
33689
+ * dropping it would break round-tripping.
33690
+ *
33691
+ * Phase 2 Stream B / C-H2.
33692
+ */
33693
+ applyShapeStyleRefs(shape, shapeStyle) {
33694
+ const hasAnyRef = shapeStyle.lnRefIdx !== void 0 || shapeStyle.fillRefIdx !== void 0 || shapeStyle.effectRefIdx !== void 0 || shapeStyle.fontRefIdx !== void 0;
33695
+ if (!hasAnyRef) {
33696
+ return;
33697
+ }
33698
+ const existing = shape["p:style"];
33699
+ const styleNode = existing ?? {};
33700
+ if (shapeStyle.lnRefIdx !== void 0) {
33701
+ const lnRef = styleNode["a:lnRef"] ?? {};
33702
+ lnRef["@_idx"] = String(shapeStyle.lnRefIdx);
33703
+ this.replaceRefColorChoice(lnRef, shapeStyle.lnRefColorXml);
33704
+ styleNode["a:lnRef"] = lnRef;
33705
+ }
33706
+ if (shapeStyle.fillRefIdx !== void 0) {
33707
+ const fillRef = styleNode["a:fillRef"] ?? {};
33708
+ fillRef["@_idx"] = String(shapeStyle.fillRefIdx);
33709
+ this.replaceRefColorChoice(fillRef, shapeStyle.fillRefColorXml);
33710
+ styleNode["a:fillRef"] = fillRef;
33711
+ }
33712
+ if (shapeStyle.effectRefIdx !== void 0) {
33713
+ const effectRef = styleNode["a:effectRef"] ?? {};
33714
+ effectRef["@_idx"] = String(shapeStyle.effectRefIdx);
33715
+ this.replaceRefColorChoice(effectRef, shapeStyle.effectRefColorXml);
33716
+ styleNode["a:effectRef"] = effectRef;
33717
+ }
33718
+ if (shapeStyle.fontRefIdx !== void 0) {
33719
+ const fontRef = styleNode["a:fontRef"] ?? {};
33720
+ fontRef["@_idx"] = shapeStyle.fontRefIdx;
33721
+ this.replaceRefColorChoice(fontRef, shapeStyle.fontRefColorXml);
33722
+ styleNode["a:fontRef"] = fontRef;
33723
+ }
33724
+ const reordered = reorderObjectKeys(styleNode, SHAPE_STYLE_ORDER);
33725
+ for (const key of Object.keys(styleNode)) {
33726
+ delete styleNode[key];
33727
+ }
33728
+ for (const key of Object.keys(reordered)) {
33729
+ styleNode[key] = reordered[key];
33730
+ }
33731
+ shape["p:style"] = styleNode;
33732
+ }
33733
+ /**
33734
+ * Replace any existing colour-choice child on a style-matrix-reference
33735
+ * element with the given preserved XML, or strip all colour children
33736
+ * when the override is undefined.
33737
+ */
33738
+ replaceRefColorChoice(refNode, colorXml) {
33739
+ for (const key of [
33740
+ "a:scrgbClr",
33741
+ "a:srgbClr",
33742
+ "a:hslClr",
33743
+ "a:sysClr",
33744
+ "a:schemeClr",
33745
+ "a:prstClr"
33746
+ ]) {
33747
+ delete refNode[key];
33748
+ }
33749
+ if (!colorXml) {
33750
+ return;
33751
+ }
33752
+ for (const [key, value] of Object.entries(colorXml)) {
33753
+ refNode[key] = value;
33754
+ }
33755
+ }
32504
33756
  };
32505
33757
 
32506
33758
  // src/core/core/runtime/PptxHandlerRuntimeSaveEffectsWriter.ts
@@ -32510,17 +33762,22 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
32510
33762
  * effectDag, 3D scene, and 3D shape properties to the given spPr XML object.
32511
33763
  */
32512
33764
  applyEffectsAndThreeD(spPr, shapeStyle) {
32513
- const outerShadowXml = this.buildOuterShadowXml(shapeStyle);
33765
+ const presetShadowXml = shapeStyle.presetShadowName ? this.buildPresetShadowXml(shapeStyle) : void 0;
33766
+ const outerShadowXml = presetShadowXml ? void 0 : this.buildOuterShadowXml(shapeStyle);
32514
33767
  const innerShadowXml = this.buildInnerShadowXml(shapeStyle);
32515
33768
  const glowXml = this.buildGlowXml(shapeStyle);
32516
33769
  const softEdgeXml = this.buildSoftEdgeXml(shapeStyle);
32517
33770
  const reflectionXml = this.buildReflectionXml(shapeStyle);
32518
33771
  const blurXml = this.buildBlurXml(shapeStyle);
32519
- const hasAnyEffect = outerShadowXml || innerShadowXml || glowXml || softEdgeXml || reflectionXml || blurXml;
33772
+ const hasAnyEffect = outerShadowXml || presetShadowXml || innerShadowXml || glowXml || softEdgeXml || reflectionXml || blurXml;
32520
33773
  if (hasAnyEffect) {
32521
33774
  const effectList = spPr["a:effectLst"] || {};
32522
- if (outerShadowXml) {
33775
+ if (presetShadowXml) {
33776
+ effectList["a:prstShdw"] = presetShadowXml;
33777
+ delete effectList["a:outerShdw"];
33778
+ } else if (outerShadowXml) {
32523
33779
  effectList["a:outerShdw"] = outerShadowXml;
33780
+ delete effectList["a:prstShdw"];
32524
33781
  }
32525
33782
  if (innerShadowXml) {
32526
33783
  effectList["a:innerShdw"] = innerShadowXml;
@@ -32537,12 +33794,13 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
32537
33794
  if (blurXml) {
32538
33795
  effectList["a:blur"] = blurXml;
32539
33796
  }
32540
- spPr["a:effectLst"] = effectList;
33797
+ spPr["a:effectLst"] = reorderObjectKeys(effectList, EFFECT_LST_ORDER);
32541
33798
  } else {
32542
33799
  const effectList = spPr["a:effectLst"];
32543
33800
  if (effectList) {
32544
- if (shapeStyle.shadowColor !== void 0 && !outerShadowXml) {
33801
+ if (shapeStyle.shadowColor !== void 0 && !outerShadowXml && !presetShadowXml) {
32545
33802
  delete effectList["a:outerShdw"];
33803
+ delete effectList["a:prstShdw"];
32546
33804
  }
32547
33805
  if (shapeStyle.innerShadowColor !== void 0 && !innerShadowXml) {
32548
33806
  delete effectList["a:innerShdw"];
@@ -32561,6 +33819,8 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
32561
33819
  }
32562
33820
  if (Object.keys(effectList).length === 0) {
32563
33821
  delete spPr["a:effectLst"];
33822
+ } else {
33823
+ spPr["a:effectLst"] = reorderObjectKeys(effectList, EFFECT_LST_ORDER);
32564
33824
  }
32565
33825
  }
32566
33826
  }
@@ -32721,7 +33981,8 @@ var PptxHandlerRuntime30 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32721
33981
  );
32722
33982
  }
32723
33983
  if (el.textStyle?.hOverflow) {
32724
- bodyPr["@_hOverflow"] = el.textStyle.hOverflow;
33984
+ bodyPr["@_horzOverflow"] = el.textStyle.hOverflow;
33985
+ delete bodyPr["@_hOverflow"];
32725
33986
  }
32726
33987
  if (el.textStyle?.vertOverflow) {
32727
33988
  bodyPr["@_vertOverflow"] = el.textStyle.vertOverflow;
@@ -32952,7 +34213,10 @@ var PptxHandlerRuntime31 = class extends PptxHandlerRuntime30 {
32952
34213
  const elWithPaths = el;
32953
34214
  if (elWithPaths.customGeometryPaths && elWithPaths.customGeometryPaths.length > 0) {
32954
34215
  delete spPr["a:prstGeom"];
32955
- spPr["a:custGeom"] = customGeometryPathsToXml(elWithPaths.customGeometryPaths);
34216
+ spPr["a:custGeom"] = customGeometryPathsToXml(
34217
+ elWithPaths.customGeometryPaths,
34218
+ elWithPaths.customGeometryRawData
34219
+ );
32956
34220
  } else if (spPr["a:prstGeom"]) {
32957
34221
  const presetGeometry = el.type === "connector" ? this.normalizePresetGeometry(el.shapeType || "straightConnector1") : this.normalizePresetGeometry(el.shapeType);
32958
34222
  const prstGeom = spPr["a:prstGeom"];
@@ -33077,6 +34341,42 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33077
34341
  isGraphicFrameShape(shape) {
33078
34342
  return Boolean(shape["p:nvGraphicFramePr"] || shape["a:graphic"] && shape["p:xfrm"]);
33079
34343
  }
34344
+ /**
34345
+ * Reorder children of `p:spPr` to match CT_ShapeProperties (§20.1.2.2.35).
34346
+ * Also reorders any nested `a:blipFill` per CT_BlipFillProperties.
34347
+ * fast-xml-parser preserves insertion order; PowerPoint validates against
34348
+ * the schema's required order, so save-side mutations must be re-sorted.
34349
+ */
34350
+ finalizeSpPrSchemaOrder(shape) {
34351
+ const spPr = shape["p:spPr"];
34352
+ if (!spPr) {
34353
+ return;
34354
+ }
34355
+ const blipFill = spPr["a:blipFill"];
34356
+ if (blipFill) {
34357
+ this.reorderInPlace(blipFill, BLIP_FILL_ORDER);
34358
+ }
34359
+ this.reorderInPlace(spPr, SP_PR_ORDER);
34360
+ }
34361
+ /**
34362
+ * Reorder children of the picture-level `p:blipFill` (CT_BlipFillProperties).
34363
+ * Picture elements carry their blip data on the `p:pic` root, not under spPr.
34364
+ */
34365
+ finalizePictureBlipFillOrder(shape) {
34366
+ const pBlipFill = shape["p:blipFill"];
34367
+ if (pBlipFill) {
34368
+ this.reorderInPlace(pBlipFill, BLIP_FILL_ORDER);
34369
+ }
34370
+ }
34371
+ reorderInPlace(target, schemaOrder) {
34372
+ const reordered = reorderObjectKeys(target, schemaOrder);
34373
+ for (const key of Object.keys(target)) {
34374
+ delete target[key];
34375
+ }
34376
+ for (const key of Object.keys(reordered)) {
34377
+ target[key] = reordered[key];
34378
+ }
34379
+ }
33080
34380
  /** Whether an element ID indicates a template (layout/master) element. */
33081
34381
  isTemplateElementId(elementId) {
33082
34382
  return elementId.startsWith("layout-") || elementId.startsWith("master-");
@@ -33100,18 +34400,51 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33100
34400
  }
33101
34401
  return;
33102
34402
  }
34403
+ if (el.type === "contentPart") {
34404
+ if (shape) {
34405
+ this.elementTransformUpdater.applyTransform(shape, el, _PptxHandlerRuntime.EMU_PER_PX);
34406
+ collectors.contentParts.push(shape);
34407
+ } else {
34408
+ this.compatibilityService.reportWarning({
34409
+ code: "SAVE_ELEMENT_SKIPPED",
34410
+ message: `Content part '${el.id}' has no rawXml and was skipped during save.`,
34411
+ scope: "save",
34412
+ slideId: ctx.slide.id,
34413
+ elementId: el.id
34414
+ });
34415
+ }
34416
+ return;
34417
+ }
33103
34418
  if (!shape && (el.type === "text" || el.type === "shape")) {
33104
34419
  shape = this.createElementXml(el);
33105
34420
  }
33106
34421
  if (!shape && el.type === "connector") {
33107
34422
  shape = this.createConnectorXml(el);
33108
34423
  }
33109
- if (!shape && el.type === "ink") {
33110
- shape = this.createInkShapeXml(el);
34424
+ if (el.type === "ink") {
34425
+ if (!shape) {
34426
+ shape = this.createInkShapeXml(el);
34427
+ this.compatibilityService.reportWarning({
34428
+ code: "SAVE_INK_ENCODED_AS_CUSTGEOM",
34429
+ message: "SDK-created ink element serialized as custGeom shape; pressure/tool metadata not represented in OOXML aink format.",
34430
+ scope: "save",
34431
+ slideId: ctx.slide.id,
34432
+ elementId: el.id
34433
+ });
34434
+ }
33111
34435
  }
33112
34436
  if (!shape && el.type === "table") {
33113
34437
  shape = this.createTableGraphicFrameXml(el);
33114
34438
  }
34439
+ if (el.type === "ole") {
34440
+ const oleEl = el;
34441
+ if (shape) {
34442
+ this.applyOleTypedFieldUpdates(shape, oleEl);
34443
+ } else {
34444
+ const embedRid = this.resolveOleEmbedRelationshipId(ctx.slideRelationships, oleEl.oleTarget) || ctx.slideRelationshipRegistry.nextRelationshipId();
34445
+ shape = this.createOleGraphicFrameXml(oleEl, embedRid);
34446
+ }
34447
+ }
33115
34448
  if (!shape) {
33116
34449
  this.compatibilityService.reportWarning({
33117
34450
  code: "SAVE_ELEMENT_SKIPPED",
@@ -33124,11 +34457,14 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33124
34457
  }
33125
34458
  this.elementTransformUpdater.applyTransform(shape, el, _PptxHandlerRuntime.EMU_PER_PX);
33126
34459
  this.applyImageProperties(shape, el);
34460
+ this.finalizePictureBlipFillOrder(shape);
33127
34461
  this.applyGeometryUpdate(shape, el);
33128
34462
  if (hasShapeProperties(el) && el.shapeStyle && shape["p:spPr"]) {
33129
34463
  const spPr = shape["p:spPr"];
33130
34464
  this.applyFillAndStroke(spPr, el.shapeStyle);
33131
34465
  this.applyEffectsAndThreeD(spPr, el.shapeStyle);
34466
+ this.finalizeSpPrSchemaOrder(shape);
34467
+ this.applyShapeStyleRefs(shape, el.shapeStyle);
33132
34468
  }
33133
34469
  if (hasTextProperties(el)) {
33134
34470
  this.applyTextBodyContent(
@@ -33286,7 +34622,8 @@ var PptxHandlerRuntime33 = class extends PptxHandlerRuntime32 {
33286
34622
  connectors: [],
33287
34623
  graphicFrames: [],
33288
34624
  groups: [],
33289
- model3ds: []
34625
+ model3ds: [],
34626
+ contentParts: []
33290
34627
  };
33291
34628
  const ctx = {
33292
34629
  slide,
@@ -33318,6 +34655,12 @@ var PptxHandlerRuntime33 = class extends PptxHandlerRuntime32 {
33318
34655
  } else {
33319
34656
  delete spTree["p16:model3D"];
33320
34657
  }
34658
+ if (collectors.contentParts.length > 0) {
34659
+ spTree["p:contentPart"] = collectors.contentParts;
34660
+ } else {
34661
+ delete spTree["p:contentPart"];
34662
+ }
34663
+ this.reapplyAlternateContentEnvelopes(spTree, collectors);
33321
34664
  const reassigned = shapeIdValidator.validateAndDeduplicateIds(
33322
34665
  spTree,
33323
34666
  (v) => this.ensureArray(v)
@@ -33335,12 +34678,426 @@ var PptxHandlerRuntime33 = class extends PptxHandlerRuntime32 {
33335
34678
  this.zip.file(slideRelsPath, this.builder.build(slideRelsData));
33336
34679
  this.applySlideDrawingGuides(slideNode, slide);
33337
34680
  this.deduplicateExtensionLists(xmlObj);
34681
+ if (slideContainsA16Element(slideNode)) {
34682
+ ensureA16NamespaceOnSlideRoot(slideNode);
34683
+ }
33338
34684
  this.zip.file(slide.id, this.builder.build(xmlObj));
33339
34685
  }
34686
+ /**
34687
+ * Re-wrap selected children with their original `<mc:AlternateContent>`
34688
+ * envelope (CC-4).
34689
+ *
34690
+ * Parsing merged the selected branch (Choice when supported, otherwise
34691
+ * Fallback) into the spTree's tag arrays. Without re-wrapping, dirty
34692
+ * save would emit flat `<p:sp>`/`<p:pic>` etc. and drop the
34693
+ * `<mc:Fallback>` branch — losing legacy rendering for files originally
34694
+ * authored with newer-namespace features.
34695
+ *
34696
+ * Strategy: for each XmlObject in `collectors.*` that traces back to a
34697
+ * known AC block, group by block and:
34698
+ * 1. Remove the node from its flat collector / spTree array.
34699
+ * 2. Clone the original AC envelope.
34700
+ * 3. Replace the selected branch's `<{tag}>` children with the
34701
+ * live (possibly edited) nodes from the collectors.
34702
+ * 4. Leave the unselected branch verbatim.
34703
+ *
34704
+ * Final envelopes are appended to `spTree['mc:AlternateContent']`.
34705
+ */
34706
+ reapplyAlternateContentEnvelopes(spTree, collectors) {
34707
+ const TAG_TO_COLLECTOR = {
34708
+ "p:sp": collectors.shapes,
34709
+ "p:pic": collectors.pics,
34710
+ "p:cxnSp": collectors.connectors,
34711
+ "p:graphicFrame": collectors.graphicFrames,
34712
+ "p:grpSp": collectors.groups,
34713
+ "p:contentPart": collectors.contentParts,
34714
+ // `model3d` does not flow through SHAPE_TREE_ELEMENT_TAGS, but the
34715
+ // AC pathway in OpenXML decks frequently uses Choice = p16:model3D
34716
+ // + Fallback = p:pic, so map it for completeness.
34717
+ "p16:model3D": collectors.model3ds
34718
+ };
34719
+ const blockGroups = /* @__PURE__ */ new Map();
34720
+ for (const tag of Object.keys(TAG_TO_COLLECTOR)) {
34721
+ const collector = TAG_TO_COLLECTOR[tag];
34722
+ if (!collector) {
34723
+ continue;
34724
+ }
34725
+ for (const node of collector) {
34726
+ const block = this.alternateContentBlockByRawXml.get(node);
34727
+ if (!block) {
34728
+ continue;
34729
+ }
34730
+ let entries = blockGroups.get(block);
34731
+ if (!entries) {
34732
+ entries = [];
34733
+ blockGroups.set(block, entries);
34734
+ }
34735
+ entries.push({ tag, node, collector });
34736
+ }
34737
+ }
34738
+ if (blockGroups.size === 0) {
34739
+ return;
34740
+ }
34741
+ const envelopes = [];
34742
+ for (const [block, entries] of blockGroups) {
34743
+ for (const entry of entries) {
34744
+ const idx = entry.collector.indexOf(entry.node);
34745
+ if (idx !== -1) {
34746
+ entry.collector.splice(idx, 1);
34747
+ }
34748
+ }
34749
+ const clonedAc = { ...block.rawAc };
34750
+ const liveByTag = /* @__PURE__ */ new Map();
34751
+ for (const entry of entries) {
34752
+ let arr = liveByTag.get(entry.tag);
34753
+ if (!arr) {
34754
+ arr = [];
34755
+ liveByTag.set(entry.tag, arr);
34756
+ }
34757
+ arr.push(entry.node);
34758
+ }
34759
+ if (block.selectedBranch === "choice") {
34760
+ const choices = this.ensureArray(clonedAc["mc:Choice"]);
34761
+ const targetIdx = block.choiceIndex ?? 0;
34762
+ const original = choices[targetIdx];
34763
+ if (original) {
34764
+ const rebuilt = { ...original };
34765
+ for (const tag of SHAPE_TREE_ELEMENT_TAGS) {
34766
+ delete rebuilt[tag];
34767
+ }
34768
+ for (const [tag, nodes] of liveByTag) {
34769
+ rebuilt[tag] = nodes.length === 1 ? nodes[0] : nodes;
34770
+ }
34771
+ choices[targetIdx] = rebuilt;
34772
+ clonedAc["mc:Choice"] = choices.length === 1 ? choices[0] : choices;
34773
+ }
34774
+ } else {
34775
+ const fallback = clonedAc["mc:Fallback"];
34776
+ if (fallback) {
34777
+ const rebuilt = { ...fallback };
34778
+ for (const tag of SHAPE_TREE_ELEMENT_TAGS) {
34779
+ delete rebuilt[tag];
34780
+ }
34781
+ for (const [tag, nodes] of liveByTag) {
34782
+ rebuilt[tag] = nodes.length === 1 ? nodes[0] : nodes;
34783
+ }
34784
+ clonedAc["mc:Fallback"] = rebuilt;
34785
+ }
34786
+ }
34787
+ envelopes.push(clonedAc);
34788
+ }
34789
+ spTree["p:sp"] = collectors.shapes;
34790
+ spTree["p:pic"] = collectors.pics;
34791
+ spTree["p:cxnSp"] = collectors.connectors;
34792
+ spTree["p:graphicFrame"] = collectors.graphicFrames;
34793
+ if (collectors.groups.length > 0) {
34794
+ spTree["p:grpSp"] = collectors.groups;
34795
+ } else {
34796
+ delete spTree["p:grpSp"];
34797
+ }
34798
+ if (collectors.contentParts.length > 0) {
34799
+ spTree["p:contentPart"] = collectors.contentParts;
34800
+ } else {
34801
+ delete spTree["p:contentPart"];
34802
+ }
34803
+ if (collectors.model3ds.length > 0) {
34804
+ spTree["p16:model3D"] = collectors.model3ds;
34805
+ } else {
34806
+ delete spTree["p16:model3D"];
34807
+ }
34808
+ spTree["mc:AlternateContent"] = envelopes.length === 1 ? envelopes[0] : envelopes;
34809
+ }
34810
+ };
34811
+
34812
+ // src/core/core/runtime/PptxHandlerRuntimeSaveTheme.ts
34813
+ var PptxHandlerRuntime34 = class extends PptxHandlerRuntime33 {
34814
+ /**
34815
+ * Mark a theme path as dirty so the save pipeline will regenerate
34816
+ * the theme XML from in-memory state. Optional — without this the
34817
+ * original XML is preserved verbatim on save (C-H3).
34818
+ */
34819
+ markThemeDirty(themePath) {
34820
+ this.dirtyThemePaths.add(themePath);
34821
+ }
34822
+ /**
34823
+ * Mark all known theme paths dirty in one call.
34824
+ */
34825
+ markAllThemesDirty() {
34826
+ for (const themePath of this.originalThemeXmlByPath.keys()) {
34827
+ this.dirtyThemePaths.add(themePath);
34828
+ }
34829
+ for (const themePath of this.masterThemePaths.values()) {
34830
+ this.dirtyThemePaths.add(themePath);
34831
+ }
34832
+ }
34833
+ /**
34834
+ * Persist all theme parts during save. Called from the save pipeline
34835
+ * after master / layout XML have been flushed and before
34836
+ * presentation.xml is serialized.
34837
+ *
34838
+ * Order of operations per theme path:
34839
+ *
34840
+ * 1. If the path is *not* in {@link dirtyThemePaths}, the existing
34841
+ * ZIP entry is already correct — no-op. (Original XML was placed
34842
+ * into the ZIP at load time.)
34843
+ * 2. If the path is dirty, build a fresh `<a:theme>` document from
34844
+ * in-memory state and the captured raw subtrees, then overwrite
34845
+ * the ZIP entry.
34846
+ */
34847
+ async persistThemeParts() {
34848
+ const seenThemePaths = /* @__PURE__ */ new Set();
34849
+ for (const [masterPath, themePath] of this.masterThemePaths.entries()) {
34850
+ if (!themePath) {
34851
+ continue;
34852
+ }
34853
+ seenThemePaths.add(themePath);
34854
+ if (!this.dirtyThemePaths.has(themePath)) {
34855
+ continue;
34856
+ }
34857
+ const themeXml2 = this.buildThemeXml(themePath, masterPath);
34858
+ if (themeXml2) {
34859
+ this.zip.file(themePath, themeXml2);
34860
+ }
34861
+ }
34862
+ for (const [themePath] of this.originalThemeXmlByPath.entries()) {
34863
+ if (seenThemePaths.has(themePath)) {
34864
+ continue;
34865
+ }
34866
+ if (!this.dirtyThemePaths.has(themePath)) {
34867
+ continue;
34868
+ }
34869
+ const themeXml2 = this.buildThemeXml(themePath, void 0);
34870
+ if (themeXml2) {
34871
+ this.zip.file(themePath, themeXml2);
34872
+ }
34873
+ }
34874
+ }
34875
+ /**
34876
+ * Build a complete `<a:theme>` XML document from in-memory state.
34877
+ * Returns the serialized XML string (with XML prolog), or `undefined`
34878
+ * if there is no source data to emit.
34879
+ *
34880
+ * - Color scheme: built from per-master color map (or global fallback).
34881
+ * - Font scheme: built from per-master font map + per-script entries.
34882
+ * - Format scheme: re-emit the original XML subtree if available; else
34883
+ * build a minimal scheme from {@link themeFormatScheme}.
34884
+ * - objectDefaults / extraClrSchemeLst / custClrLst / extLst: re-emit
34885
+ * captured raw subtrees.
34886
+ */
34887
+ buildThemeXml(themePath, masterPath) {
34888
+ const colorMap = masterPath && this.masterThemeColorMaps.get(masterPath) || this.globalThemeColorMapSnapshot || this.themeColorMap;
34889
+ const fontMap = masterPath && this.masterThemeFontMaps.get(masterPath) || this.globalThemeFontMapSnapshot || this.themeFontMap;
34890
+ const themeName = this.masterThemeNames.get(themePath) || "Office Theme";
34891
+ const colorSchemeName = this.masterThemeColorSchemeNames.get(themePath) || themeName;
34892
+ const fontSchemeName = this.masterThemeFontSchemeNames.get(themePath) || themeName;
34893
+ const majorScripts = this.masterThemeMajorFontScripts.get(themePath) || {};
34894
+ const minorScripts = this.masterThemeMinorFontScripts.get(themePath) || {};
34895
+ const clrScheme = this.buildClrSchemeObject(colorSchemeName, colorMap);
34896
+ const fontScheme = this.buildFontSchemeObject(
34897
+ fontSchemeName,
34898
+ fontMap,
34899
+ majorScripts,
34900
+ minorScripts
34901
+ );
34902
+ const fmtScheme = this.extractRawSubtreeFromOriginal(themePath, [
34903
+ "a:theme",
34904
+ "a:themeElements",
34905
+ "a:fmtScheme"
34906
+ ]);
34907
+ const themeElements = {
34908
+ "a:clrScheme": clrScheme,
34909
+ "a:fontScheme": fontScheme
34910
+ };
34911
+ if (fmtScheme !== void 0) {
34912
+ themeElements["a:fmtScheme"] = fmtScheme;
34913
+ } else {
34914
+ themeElements["a:fmtScheme"] = this.buildMinimalFmtScheme(themeName);
34915
+ }
34916
+ const themeRoot = {
34917
+ "@_xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
34918
+ "@_name": themeName,
34919
+ "a:themeElements": themeElements
34920
+ };
34921
+ const objectDefaults = this.masterThemeObjectDefaults.get(themePath);
34922
+ if (objectDefaults && (objectDefaults.spDef || objectDefaults.lnDef || objectDefaults.txDef)) {
34923
+ const od = {};
34924
+ if (objectDefaults.spDef !== void 0) {
34925
+ od["a:spDef"] = objectDefaults.spDef;
34926
+ }
34927
+ if (objectDefaults.lnDef !== void 0) {
34928
+ od["a:lnDef"] = objectDefaults.lnDef;
34929
+ }
34930
+ if (objectDefaults.txDef !== void 0) {
34931
+ od["a:txDef"] = objectDefaults.txDef;
34932
+ }
34933
+ themeRoot["a:objectDefaults"] = od;
34934
+ } else {
34935
+ themeRoot["a:objectDefaults"] = {};
34936
+ }
34937
+ const extraClr = this.masterThemeExtraClrSchemeLst.get(themePath);
34938
+ themeRoot["a:extraClrSchemeLst"] = extraClr !== void 0 ? extraClr : {};
34939
+ const custClr = this.masterThemeCustClrLst.get(themePath);
34940
+ if (custClr !== void 0) {
34941
+ themeRoot["a:custClrLst"] = custClr;
34942
+ }
34943
+ const themeExt = this.masterThemeExtLst.get(themePath);
34944
+ if (themeExt !== void 0) {
34945
+ themeRoot["a:extLst"] = themeExt;
34946
+ }
34947
+ const doc = {
34948
+ "?xml": { "@_version": "1.0", "@_encoding": "UTF-8", "@_standalone": "yes" },
34949
+ "a:theme": themeRoot
34950
+ };
34951
+ try {
34952
+ return this.builder.build(doc);
34953
+ } catch (error) {
34954
+ console.warn(`Failed to build theme XML for ${themePath}:`, error);
34955
+ return void 0;
34956
+ }
34957
+ }
34958
+ /**
34959
+ * Build the `a:clrScheme` XmlObject from a colour map. Each slot
34960
+ * value is interpreted as either a `#RRGGBB` srgb hex or a known
34961
+ * sysClr token (currently always emitted as srgbClr — the in-memory
34962
+ * map is hex-typed; sysClr round-trip belongs to the broader C-H3
34963
+ * fix to preserve original color XML and is out of scope here).
34964
+ */
34965
+ buildClrSchemeObject(schemeName, colorMap) {
34966
+ const slot = (key) => {
34967
+ const hex = String(colorMap[key] || "").replace(/^#/, "");
34968
+ const srgb = hex.length === 6 ? hex.toUpperCase() : "000000";
34969
+ return { "a:srgbClr": { "@_val": srgb } };
34970
+ };
34971
+ return {
34972
+ "@_name": schemeName,
34973
+ "a:dk1": slot("dk1"),
34974
+ "a:lt1": slot("lt1"),
34975
+ "a:dk2": slot("dk2"),
34976
+ "a:lt2": slot("lt2"),
34977
+ "a:accent1": slot("accent1"),
34978
+ "a:accent2": slot("accent2"),
34979
+ "a:accent3": slot("accent3"),
34980
+ "a:accent4": slot("accent4"),
34981
+ "a:accent5": slot("accent5"),
34982
+ "a:accent6": slot("accent6"),
34983
+ "a:hlink": slot("hlink"),
34984
+ "a:folHlink": slot("folHlink")
34985
+ };
34986
+ }
34987
+ /**
34988
+ * Build the `a:fontScheme` XmlObject from a font map plus per-script
34989
+ * font tables.
34990
+ *
34991
+ * Phase 4 Stream A / M4.
34992
+ */
34993
+ buildFontSchemeObject(schemeName, fontMap, majorScripts, minorScripts) {
34994
+ const buildFontGroup = (latinKey, eaKey, csKey, scripts) => {
34995
+ const group = {
34996
+ "a:latin": { "@_typeface": fontMap[latinKey] || "Calibri" },
34997
+ "a:ea": { "@_typeface": fontMap[eaKey] || "" },
34998
+ "a:cs": { "@_typeface": fontMap[csKey] || "" }
34999
+ };
35000
+ const scriptKeys = Object.keys(scripts);
35001
+ if (scriptKeys.length > 0) {
35002
+ const fontEntries = scriptKeys.map((script) => ({
35003
+ "@_script": script,
35004
+ "@_typeface": scripts[script]
35005
+ }));
35006
+ group["a:font"] = fontEntries.length === 1 ? fontEntries[0] : fontEntries;
35007
+ }
35008
+ return group;
35009
+ };
35010
+ return {
35011
+ "@_name": schemeName,
35012
+ "a:majorFont": buildFontGroup("mj-lt", "mj-ea", "mj-cs", majorScripts),
35013
+ "a:minorFont": buildFontGroup("mn-lt", "mn-ea", "mn-cs", minorScripts)
35014
+ };
35015
+ }
35016
+ /**
35017
+ * Re-parse the original theme XML and pluck out a subtree by path,
35018
+ * returning the raw parser object. Returns `undefined` when the
35019
+ * original is missing or the path doesn't exist.
35020
+ *
35021
+ * Used to preserve `a:fmtScheme` byte-for-byte through a regenerate
35022
+ * round-trip, since the in-memory PptxThemeFormatScheme is lossy.
35023
+ */
35024
+ extractRawSubtreeFromOriginal(themePath, path) {
35025
+ const original = this.originalThemeXmlByPath.get(themePath);
35026
+ if (!original) {
35027
+ return void 0;
35028
+ }
35029
+ try {
35030
+ const parsed = this.parser.parse(original);
35031
+ let cursor = parsed;
35032
+ for (const segment of path) {
35033
+ if (cursor && typeof cursor === "object" && segment in cursor) {
35034
+ cursor = cursor[segment];
35035
+ } else {
35036
+ return void 0;
35037
+ }
35038
+ }
35039
+ return cursor;
35040
+ } catch {
35041
+ return void 0;
35042
+ }
35043
+ }
35044
+ /**
35045
+ * Last-resort minimal `<a:fmtScheme>` body. Mirrors the SDK new-deck
35046
+ * builder's output for new presentations, scaled down to the smallest
35047
+ * schema-valid form.
35048
+ */
35049
+ buildMinimalFmtScheme(name) {
35050
+ const phClrSolid = { "a:solidFill": { "a:schemeClr": { "@_val": "phClr" } } };
35051
+ return {
35052
+ "@_name": name,
35053
+ "a:fillStyleLst": {
35054
+ "a:solidFill": [{ "a:schemeClr": { "@_val": "phClr" } }],
35055
+ "a:gradFill": []
35056
+ },
35057
+ "a:lnStyleLst": {
35058
+ "a:ln": [
35059
+ {
35060
+ "@_w": "6350",
35061
+ "@_cap": "flat",
35062
+ "@_cmpd": "sng",
35063
+ "@_algn": "ctr",
35064
+ ...phClrSolid,
35065
+ "a:prstDash": { "@_val": "solid" },
35066
+ "a:miter": { "@_lim": "800000" }
35067
+ },
35068
+ {
35069
+ "@_w": "12700",
35070
+ "@_cap": "flat",
35071
+ "@_cmpd": "sng",
35072
+ "@_algn": "ctr",
35073
+ ...phClrSolid,
35074
+ "a:prstDash": { "@_val": "solid" },
35075
+ "a:miter": { "@_lim": "800000" }
35076
+ },
35077
+ {
35078
+ "@_w": "19050",
35079
+ "@_cap": "flat",
35080
+ "@_cmpd": "sng",
35081
+ "@_algn": "ctr",
35082
+ ...phClrSolid,
35083
+ "a:prstDash": { "@_val": "solid" },
35084
+ "a:miter": { "@_lim": "800000" }
35085
+ }
35086
+ ]
35087
+ },
35088
+ "a:effectStyleLst": {
35089
+ "a:effectStyle": [{ "a:effectLst": {} }, { "a:effectLst": {} }, { "a:effectLst": {} }]
35090
+ },
35091
+ "a:bgFillStyleLst": {
35092
+ "a:solidFill": [{ "a:schemeClr": { "@_val": "phClr" } }],
35093
+ "a:gradFill": []
35094
+ }
35095
+ };
35096
+ }
33340
35097
  };
33341
35098
 
33342
35099
  // src/core/core/runtime/PptxHandlerRuntimeSavePipeline.ts
33343
- var PptxHandlerRuntime34 = class _PptxHandlerRuntime extends PptxHandlerRuntime33 {
35100
+ var PptxHandlerRuntime35 = class _PptxHandlerRuntime extends PptxHandlerRuntime34 {
33344
35101
  /**
33345
35102
  * Resolve the effective conformance class for this save operation.
33346
35103
  *
@@ -33427,6 +35184,7 @@ var PptxHandlerRuntime34 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33427
35184
  for (const [masterPath, masterXmlObj] of this.masterXmlMap.entries()) {
33428
35185
  this.zip.file(masterPath, this.builder.build(masterXmlObj));
33429
35186
  }
35187
+ await this.persistThemeParts();
33430
35188
  await this.applyEmbeddedFontPreservation(options?.embeddedFonts);
33431
35189
  if (this.presentationData) {
33432
35190
  this.presentationSaveBuilder.applySaveOptions({
@@ -33516,7 +35274,7 @@ var PptxHandlerRuntime34 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33516
35274
  };
33517
35275
 
33518
35276
  // src/core/core/runtime/PptxHandlerRuntimeElementParsing.ts
33519
- var PptxHandlerRuntime35 = class _PptxHandlerRuntime extends PptxHandlerRuntime34 {
35277
+ var PptxHandlerRuntime36 = class _PptxHandlerRuntime extends PptxHandlerRuntime35 {
33520
35278
  /**
33521
35279
  * Parse media data (video/audio path and MIME type) from graphic frame data.
33522
35280
  */
@@ -33738,7 +35496,7 @@ var PptxHandlerRuntime35 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
33738
35496
  };
33739
35497
 
33740
35498
  // src/core/core/runtime/PptxHandlerRuntimePlaceholderLookup.ts
33741
- var PptxHandlerRuntime36 = class extends PptxHandlerRuntime35 {
35499
+ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
33742
35500
  findPlaceholderInShapeTree(spTree, expected) {
33743
35501
  if (!spTree) {
33744
35502
  return void 0;
@@ -33891,7 +35649,7 @@ var PptxHandlerRuntime36 = class extends PptxHandlerRuntime35 {
33891
35649
  };
33892
35650
 
33893
35651
  // src/core/core/runtime/PptxHandlerRuntimeGeometryParsing.ts
33894
- var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
35652
+ var PptxHandlerRuntime38 = class extends PptxHandlerRuntime37 {
33895
35653
  parseGeometryAdjustments(prstGeom) {
33896
35654
  if (!prstGeom) {
33897
35655
  return void 0;
@@ -34000,6 +35758,103 @@ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
34000
35758
  }
34001
35759
  return handles.length > 0 ? handles : void 0;
34002
35760
  }
35761
+ /**
35762
+ * Extract `a:gdLst`/`a:ahLst`/`a:cxnLst`/`a:rect` raw XML from a `a:custGeom`
35763
+ * node so they can be re-emitted on save when the geometry is edited.
35764
+ * Returns `undefined` when none of these auxiliary children carry data.
35765
+ */
35766
+ extractCustomGeometryRawData(custGeom) {
35767
+ if (!custGeom) {
35768
+ return void 0;
35769
+ }
35770
+ const isNonEmpty = (node) => {
35771
+ if (node === void 0 || node === null) {
35772
+ return false;
35773
+ }
35774
+ if (typeof node !== "object") {
35775
+ return true;
35776
+ }
35777
+ return Object.keys(node).length > 0;
35778
+ };
35779
+ const result = {};
35780
+ const gdLst = custGeom["a:gdLst"];
35781
+ if (isNonEmpty(gdLst)) {
35782
+ result.gdLstXml = gdLst;
35783
+ }
35784
+ const ahLst = custGeom["a:ahLst"];
35785
+ if (isNonEmpty(ahLst)) {
35786
+ result.ahLstXml = ahLst;
35787
+ }
35788
+ const cxnLst = custGeom["a:cxnLst"];
35789
+ if (isNonEmpty(cxnLst)) {
35790
+ result.cxnLstXml = cxnLst;
35791
+ }
35792
+ const rect = custGeom["a:rect"];
35793
+ if (isNonEmpty(rect)) {
35794
+ result.rectXml = rect;
35795
+ }
35796
+ return Object.keys(result).length > 0 ? result : void 0;
35797
+ }
35798
+ /**
35799
+ * Build structured `CustomGeometryPath[]` from a parsed `a:custGeom` node,
35800
+ * including per-path `@fill`/`@stroke`/`@extrusionOk` attributes so they
35801
+ * survive a round-trip when the path list is later regenerated.
35802
+ *
35803
+ * Falls back to SVG → structured-path conversion when no structured path
35804
+ * info is otherwise available.
35805
+ */
35806
+ buildStructuredCustomGeometryPaths(custGeom, pathData, pathWidth, pathHeight) {
35807
+ if (!custGeom) {
35808
+ return void 0;
35809
+ }
35810
+ const pathLst = custGeom["a:pathLst"];
35811
+ if (!pathLst) {
35812
+ return void 0;
35813
+ }
35814
+ const pathNodes = this.ensureArray(pathLst["a:path"]);
35815
+ if (pathNodes.length === 0) {
35816
+ return void 0;
35817
+ }
35818
+ const segments = svgToCustomGeometryPaths(pathData, pathWidth, pathHeight);
35819
+ if (segments.length === 0) {
35820
+ return void 0;
35821
+ }
35822
+ const validFillModes = /* @__PURE__ */ new Set([
35823
+ "norm",
35824
+ "lighten",
35825
+ "lightenLess",
35826
+ "darken",
35827
+ "darkenLess",
35828
+ "none"
35829
+ ]);
35830
+ const parseBoolAttr2 = (value) => {
35831
+ if (value === void 0 || value === null || value === "") {
35832
+ return void 0;
35833
+ }
35834
+ if (value === "1" || value === "true" || value === true) {
35835
+ return true;
35836
+ }
35837
+ if (value === "0" || value === "false" || value === false) {
35838
+ return false;
35839
+ }
35840
+ return void 0;
35841
+ };
35842
+ const target = segments[0];
35843
+ const firstNode = pathNodes[0];
35844
+ const fillAttr = String(firstNode["@_fill"] ?? "").trim();
35845
+ if (validFillModes.has(fillAttr)) {
35846
+ target.fillMode = fillAttr;
35847
+ }
35848
+ const strokeAttr = parseBoolAttr2(firstNode["@_stroke"]);
35849
+ if (strokeAttr !== void 0) {
35850
+ target.stroke = strokeAttr;
35851
+ }
35852
+ const extrusionAttr = parseBoolAttr2(firstNode["@_extrusionOk"]);
35853
+ if (extrusionAttr !== void 0) {
35854
+ target.extrusionOk = extrusionAttr;
35855
+ }
35856
+ return segments;
35857
+ }
34003
35858
  parseCustomGeometry(custGeom, shapeWidth, shapeHeight) {
34004
35859
  if (!custGeom || !custGeom["a:pathLst"] || !custGeom["a:pathLst"]?.["a:path"]) {
34005
35860
  return null;
@@ -34068,7 +35923,7 @@ var PptxHandlerRuntime37 = class extends PptxHandlerRuntime36 {
34068
35923
  };
34069
35924
 
34070
35925
  // src/core/core/runtime/PptxHandlerRuntimeShapeImageFill.ts
34071
- var PptxHandlerRuntime38 = class _PptxHandlerRuntime extends PptxHandlerRuntime37 {
35926
+ var PptxHandlerRuntime39 = class _PptxHandlerRuntime extends PptxHandlerRuntime38 {
34072
35927
  /**
34073
35928
  * Parse a shape that has an image fill (a:blipFill inside spPr)
34074
35929
  * This handles shapes like rectangles filled with images (e.g., wood texture backgrounds)
@@ -34268,7 +36123,7 @@ var PptxHandlerRuntime38 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
34268
36123
  };
34269
36124
 
34270
36125
  // src/core/core/runtime/PptxHandlerRuntimeTextDefaults.ts
34271
- var PptxHandlerRuntime39 = class extends PptxHandlerRuntime38 {
36126
+ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34272
36127
  /**
34273
36128
  * Apply {@link PlaceholderDefaults} body-level properties to a
34274
36129
  * {@link TextStyle} as fallback values (only sets fields that are
@@ -34392,7 +36247,7 @@ var PptxHandlerRuntime39 = class extends PptxHandlerRuntime38 {
34392
36247
  };
34393
36248
 
34394
36249
  // src/core/core/runtime/PptxHandlerRuntimeBulletParsing.ts
34395
- var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
36250
+ var PptxHandlerRuntime41 = class extends PptxHandlerRuntime40 {
34396
36251
  resolveParagraphBulletInfo(paragraph, paragraphIndex, txBody, inheritedTxBody, isBodyPlaceholder = false, slidePath) {
34397
36252
  if (!paragraph) {
34398
36253
  return null;
@@ -34423,7 +36278,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34423
36278
  if (candidate["a:buNone"]) {
34424
36279
  return { none: true };
34425
36280
  }
34426
- if (candidate["a:buChar"] || candidate["a:buAutoNum"] || candidate["a:buBlip"]) {
36281
+ 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) {
34427
36282
  resolvedBulletProps = candidate;
34428
36283
  break;
34429
36284
  }
@@ -34437,6 +36292,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34437
36292
  }
34438
36293
  const buFont = resolvedBulletProps["a:buFont"];
34439
36294
  const fontFamily = buFont?.["@_typeface"] ? String(buFont["@_typeface"]) : void 0;
36295
+ const fontInherit = resolvedBulletProps["a:buFontTx"] !== void 0;
34440
36296
  const buSzPct = resolvedBulletProps["a:buSzPct"];
34441
36297
  let sizePercent;
34442
36298
  if (buSzPct?.["@_val"] !== void 0) {
@@ -34453,6 +36309,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34453
36309
  sizePts = ptsRaw / 100;
34454
36310
  }
34455
36311
  }
36312
+ const sizeInherit = resolvedBulletProps["a:buSzTx"] !== void 0;
34456
36313
  const buClr = resolvedBulletProps["a:buClr"];
34457
36314
  let color;
34458
36315
  if (buClr) {
@@ -34461,6 +36318,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34461
36318
  color = String(srgb["@_val"]);
34462
36319
  }
34463
36320
  }
36321
+ const colorInherit = resolvedBulletProps["a:buClrTx"] !== void 0;
34464
36322
  const bulletChar = String(
34465
36323
  resolvedBulletProps["a:buChar"]?.["@_char"] || ""
34466
36324
  );
@@ -34470,7 +36328,10 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34470
36328
  fontFamily,
34471
36329
  sizePercent,
34472
36330
  sizePts,
34473
- color
36331
+ color,
36332
+ ...fontInherit ? { fontInherit: true } : {},
36333
+ ...colorInherit ? { colorInherit: true } : {},
36334
+ ...sizeInherit ? { sizeInherit: true } : {}
34474
36335
  };
34475
36336
  }
34476
36337
  const autoNum = resolvedBulletProps["a:buAutoNum"];
@@ -34485,7 +36346,10 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34485
36346
  fontFamily,
34486
36347
  sizePercent,
34487
36348
  sizePts,
34488
- color
36349
+ color,
36350
+ ...fontInherit ? { fontInherit: true } : {},
36351
+ ...colorInherit ? { colorInherit: true } : {},
36352
+ ...sizeInherit ? { sizeInherit: true } : {}
34489
36353
  };
34490
36354
  }
34491
36355
  const buBlip = resolvedBulletProps["a:buBlip"];
@@ -34597,7 +36461,7 @@ var PptxHandlerRuntime40 = class extends PptxHandlerRuntime39 {
34597
36461
  };
34598
36462
 
34599
36463
  // src/core/core/runtime/PptxHandlerRuntimeShapeBodyParsing.ts
34600
- var PptxHandlerRuntime41 = class _PptxHandlerRuntime extends PptxHandlerRuntime40 {
36464
+ var PptxHandlerRuntime42 = class _PptxHandlerRuntime extends PptxHandlerRuntime41 {
34601
36465
  /**
34602
36466
  * Parse `a:spLocks` attributes into a structured {@link PptxShapeLocks} object.
34603
36467
  * Returns `undefined` when the node is absent or contains no lock attributes.
@@ -34692,7 +36556,8 @@ var PptxHandlerRuntime41 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
34692
36556
  if (Number.isFinite(spcColRaw) && spcColRaw > 0) {
34693
36557
  textStyle.columnSpacing = spcColRaw / _PptxHandlerRuntime.EMU_PER_PX;
34694
36558
  }
34695
- const hOverflow = String(bodyPr["@_hOverflow"] || "").trim();
36559
+ const hOverflowRaw = bodyPr["@_horzOverflow"] ?? bodyPr["@_hOverflow"];
36560
+ const hOverflow = String(hOverflowRaw || "").trim();
34696
36561
  if (hOverflow === "overflow" || hOverflow === "clip") {
34697
36562
  textStyle.hOverflow = hOverflow;
34698
36563
  }
@@ -34875,7 +36740,7 @@ var PptxHandlerRuntime41 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
34875
36740
  };
34876
36741
 
34877
36742
  // src/core/core/runtime/PptxHandlerRuntimeShapeTextParsing.ts
34878
- var PptxHandlerRuntime42 = class _PptxHandlerRuntime extends PptxHandlerRuntime41 {
36743
+ var PptxHandlerRuntime43 = class _PptxHandlerRuntime extends PptxHandlerRuntime42 {
34879
36744
  /**
34880
36745
  * Resolve paragraph-level styles (alignment, spacing, margins, tabs,
34881
36746
  * level styles) for a single paragraph. Modifies `textStyle` in place
@@ -35057,7 +36922,7 @@ var PptxHandlerRuntime42 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35057
36922
  };
35058
36923
 
35059
36924
  // src/core/core/runtime/PptxHandlerRuntimeShapeParagraphContentParsing.ts
35060
- var PptxHandlerRuntime43 = class extends PptxHandlerRuntime42 {
36925
+ var PptxHandlerRuntime44 = class extends PptxHandlerRuntime43 {
35061
36926
  /**
35062
36927
  * Collect text content (runs, fields, equations, bullets) for a single
35063
36928
  * paragraph and return text parts + segments. The returned `seedStyle`
@@ -35240,6 +37105,23 @@ var PptxHandlerRuntime43 = class extends PptxHandlerRuntime42 {
35240
37105
  parts.push("\n");
35241
37106
  segments.push({ text: "\n", style: { ...mergedDefaultRunStyle } });
35242
37107
  }
37108
+ const firstSegmentIndex = segments.length === 0 ? -1 : 0;
37109
+ if (firstSegmentIndex >= 0) {
37110
+ const pPrRaw = p["a:pPr"];
37111
+ const lvlRaw = pPrRaw?.["@_lvl"];
37112
+ if (lvlRaw !== void 0) {
37113
+ const lvlParsed = Number.parseInt(String(lvlRaw), 10);
37114
+ if (Number.isFinite(lvlParsed) && lvlParsed > 0) {
37115
+ segments[firstSegmentIndex].paragraphLevel = Math.min(Math.max(lvlParsed, 0), 8);
37116
+ }
37117
+ }
37118
+ const endParaRPrRaw = p["a:endParaRPr"];
37119
+ if (endParaRPrRaw && typeof endParaRPrRaw === "object") {
37120
+ segments[firstSegmentIndex].endParaRunProperties = {
37121
+ ...endParaRPrRaw
37122
+ };
37123
+ }
37124
+ }
35243
37125
  return { parts, segments, seedStyle };
35244
37126
  }
35245
37127
  /**
@@ -35349,7 +37231,7 @@ var PptxHandlerRuntime43 = class extends PptxHandlerRuntime42 {
35349
37231
  };
35350
37232
 
35351
37233
  // src/core/core/runtime/PptxHandlerRuntimeShapeParsing.ts
35352
- var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime43 {
37234
+ var PptxHandlerRuntime45 = class _PptxHandlerRuntime extends PptxHandlerRuntime44 {
35353
37235
  parseShape(shape, id, slidePath) {
35354
37236
  try {
35355
37237
  const spPr = shape["p:spPr"];
@@ -35385,6 +37267,7 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35385
37267
  let pathData;
35386
37268
  let pathWidth;
35387
37269
  let pathHeight;
37270
+ let customGeometryRawData;
35388
37271
  const custGeom = effectiveSpPr?.["a:custGeom"];
35389
37272
  if (custGeom) {
35390
37273
  const customPath = this.parseCustomGeometry(
@@ -35397,6 +37280,7 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35397
37280
  pathData = customPath.pathData;
35398
37281
  pathWidth = customPath.pathWidth;
35399
37282
  pathHeight = customPath.pathHeight;
37283
+ customGeometryRawData = this.extractCustomGeometryRawData(custGeom);
35400
37284
  }
35401
37285
  }
35402
37286
  const geomNode = custGeom ?? effectiveSpPr?.["a:prstGeom"];
@@ -35554,7 +37438,8 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35554
37438
  type: "shape",
35555
37439
  pathData,
35556
37440
  pathWidth,
35557
- pathHeight
37441
+ pathHeight,
37442
+ customGeometryRawData
35558
37443
  };
35559
37444
  } catch (e) {
35560
37445
  console.warn(`[pptx] Skipping shape element (${id}):`, e);
@@ -35564,7 +37449,7 @@ var PptxHandlerRuntime44 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35564
37449
  };
35565
37450
 
35566
37451
  // src/core/core/runtime/PptxHandlerRuntimePictureParsing.ts
35567
- var PptxHandlerRuntime45 = class _PptxHandlerRuntime extends PptxHandlerRuntime44 {
37452
+ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime45 {
35568
37453
  async parsePicture(pic, id, slidePath) {
35569
37454
  try {
35570
37455
  const spPr = pic["p:spPr"];
@@ -35803,7 +37688,7 @@ var PptxHandlerRuntime45 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
35803
37688
  };
35804
37689
 
35805
37690
  // src/core/core/runtime/PptxHandlerRuntimeSpTreeParsing.ts
35806
- var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime45 {
37691
+ var PptxHandlerRuntime47 = class _PptxHandlerRuntime extends PptxHandlerRuntime46 {
35807
37692
  /**
35808
37693
  * Known element tag names that appear as direct children of `p:spTree`
35809
37694
  * (or `p:grpSp`) and represent renderable shapes/objects.
@@ -36148,9 +38033,18 @@ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
36148
38033
  * Unwrap mc:AlternateContent elements within a shape tree (or group),
36149
38034
  * merging selected branch children into the parent element arrays.
36150
38035
  * Delegates to the standalone alternate-content utility.
38036
+ *
38037
+ * Records each consumed AC envelope in {@link alternateContentBlockByRawXml}
38038
+ * so the save layer can re-emit the original `<mc:Choice>` /
38039
+ * `<mc:Fallback>` shape on dirty save (CC-4).
36151
38040
  */
36152
38041
  unwrapAlternateContent(container) {
36153
- unwrapAlternateContent(container);
38042
+ const blocks = unwrapAlternateContent(container);
38043
+ for (const block of blocks) {
38044
+ for (const ref of block.childRefs) {
38045
+ this.alternateContentBlockByRawXml.set(ref.node, block);
38046
+ }
38047
+ }
36154
38048
  }
36155
38049
  /**
36156
38050
  * Forward declaration – implemented in PptxHandlerRuntimeGroupParsing.
@@ -36161,7 +38055,7 @@ var PptxHandlerRuntime46 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
36161
38055
  };
36162
38056
 
36163
38057
  // src/core/core/runtime/PptxHandlerRuntimeGroupParsing.ts
36164
- var PptxHandlerRuntime47 = class _PptxHandlerRuntime extends PptxHandlerRuntime46 {
38058
+ var PptxHandlerRuntime48 = class _PptxHandlerRuntime extends PptxHandlerRuntime47 {
36165
38059
  async parseGroupShape(group, baseId, slidePath, rawXmlStr) {
36166
38060
  const grpSpPr = group["p:grpSpPr"];
36167
38061
  const xfrm = grpSpPr?.["a:xfrm"];
@@ -36334,7 +38228,7 @@ var PptxHandlerRuntime47 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
36334
38228
  };
36335
38229
 
36336
38230
  // src/core/core/runtime/PptxHandlerRuntimeSlideParsing.ts
36337
- var PptxHandlerRuntime48 = class extends PptxHandlerRuntime47 {
38231
+ var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
36338
38232
  /**
36339
38233
  * Parse text body from a connector shape (p:cxnSp > p:txBody).
36340
38234
  * Uses the same text run extraction logic as regular shapes but
@@ -36446,7 +38340,7 @@ var PptxHandlerRuntime48 = class extends PptxHandlerRuntime47 {
36446
38340
  };
36447
38341
 
36448
38342
  // src/core/core/runtime/PptxHandlerRuntimeColorAndEffects.ts
36449
- var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
38343
+ var PptxHandlerRuntime50 = class extends PptxHandlerRuntime49 {
36450
38344
  /**
36451
38345
  * Forward declaration – implemented in PptxHandlerRuntimeThemeProcessing.
36452
38346
  * Re-resolves gradient stops by substituting `phClr` with the given colour.
@@ -36487,8 +38381,9 @@ var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
36487
38381
  return void 0;
36488
38382
  }
36489
38383
  const resolvedKey = normalized === "phclr" ? "accent1" : normalized;
36490
- if (this.currentSlideClrMapOverride) {
36491
- const remapped = this.currentSlideClrMapOverride[resolvedKey];
38384
+ const overrideMap = this.currentSlideClrMapOverride ?? this.currentMasterClrMap;
38385
+ if (overrideMap) {
38386
+ const remapped = overrideMap[resolvedKey];
36492
38387
  if (remapped) {
36493
38388
  return this.themeColorMap[remapped] || this.getDefaultSchemeColorMap()[remapped];
36494
38389
  }
@@ -36571,7 +38466,7 @@ var PptxHandlerRuntime49 = class extends PptxHandlerRuntime48 {
36571
38466
  };
36572
38467
 
36573
38468
  // src/core/core/runtime/PptxHandlerRuntimeBackgroundParsing.ts
36574
- var PptxHandlerRuntime50 = class extends PptxHandlerRuntime49 {
38469
+ var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
36575
38470
  async extractBackgroundImage(slideXml2, slidePath, rootElement = "p:sld") {
36576
38471
  try {
36577
38472
  const bg = slideXml2[rootElement]?.["p:cSld"]?.["p:bg"];
@@ -36782,7 +38677,7 @@ var PptxHandlerRuntime50 = class extends PptxHandlerRuntime49 {
36782
38677
  };
36783
38678
 
36784
38679
  // src/core/core/runtime/PptxHandlerRuntimeSlideUtils.ts
36785
- var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
38680
+ var PptxHandlerRuntime52 = class extends PptxHandlerRuntime51 {
36786
38681
  /**
36787
38682
  * Retrieve the background gradient from a layout, falling back to master.
36788
38683
  */
@@ -36853,6 +38748,64 @@ var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
36853
38748
  }
36854
38749
  return void 0;
36855
38750
  }
38751
+ /**
38752
+ * Find the master file path referenced by a layout via its relationships.
38753
+ */
38754
+ findMasterPathForLayoutBase(layoutPath) {
38755
+ const layoutRels = this.slideRelsMap.get(layoutPath);
38756
+ if (!layoutRels) {
38757
+ return void 0;
38758
+ }
38759
+ for (const [, target] of layoutRels.entries()) {
38760
+ if (target.includes("slideMaster")) {
38761
+ const layoutDir = layoutPath.substring(0, layoutPath.lastIndexOf("/") + 1);
38762
+ return target.startsWith("..") ? this.resolvePath(layoutDir, target) : `ppt/${target.replace("../", "")}`;
38763
+ }
38764
+ }
38765
+ return void 0;
38766
+ }
38767
+ /**
38768
+ * Switch the active master state (clrMap + theme color/font/format
38769
+ * scheme) so that scheme-colour resolution for the slide currently
38770
+ * being parsed walks through the correct master.
38771
+ *
38772
+ * Multi-master decks must resolve scheme colours against each slide's
38773
+ * own master rather than always against `masterFiles[0]`.
38774
+ *
38775
+ * Phase 2 Stream B / C-H4.
38776
+ */
38777
+ async setActiveMasterForSlide(slidePath) {
38778
+ const layoutPath = this.findLayoutPathForSlide(slidePath);
38779
+ if (!layoutPath) {
38780
+ this.currentMasterClrMap = null;
38781
+ this.themeColorMap = { ...this.globalThemeColorMapSnapshot };
38782
+ this.themeFontMap = { ...this.globalThemeFontMapSnapshot };
38783
+ this.themeFormatScheme = this.globalThemeFormatSchemeSnapshot;
38784
+ return;
38785
+ }
38786
+ if (!this.slideRelsMap.has(layoutPath)) {
38787
+ const layoutRelsPath = `${layoutPath.replace("slideLayouts/", "slideLayouts/_rels/")}.rels`;
38788
+ try {
38789
+ await this.loadSlideRelationships(layoutPath, layoutRelsPath);
38790
+ } catch {
38791
+ }
38792
+ }
38793
+ const masterPath = this.findMasterPathForLayoutBase(layoutPath);
38794
+ if (!masterPath) {
38795
+ this.currentMasterClrMap = null;
38796
+ this.themeColorMap = { ...this.globalThemeColorMapSnapshot };
38797
+ this.themeFontMap = { ...this.globalThemeFontMapSnapshot };
38798
+ this.themeFormatScheme = this.globalThemeFormatSchemeSnapshot;
38799
+ return;
38800
+ }
38801
+ this.currentMasterClrMap = this.masterClrMaps.get(masterPath) ?? null;
38802
+ const masterColorMap = this.masterThemeColorMaps.get(masterPath);
38803
+ this.themeColorMap = masterColorMap ? { ...masterColorMap } : { ...this.globalThemeColorMapSnapshot };
38804
+ const masterFontMap = this.masterThemeFontMaps.get(masterPath);
38805
+ this.themeFontMap = masterFontMap ? { ...masterFontMap } : { ...this.globalThemeFontMapSnapshot };
38806
+ const masterFormatScheme = this.masterThemeFormatSchemes.get(masterPath);
38807
+ this.themeFormatScheme = masterFormatScheme ?? this.globalThemeFormatSchemeSnapshot;
38808
+ }
36856
38809
  /**
36857
38810
  * Extract the `p:bg/@showAnimation` flag from a slide's XML.
36858
38811
  * Returns `true` when the background should animate, `false` when
@@ -36993,7 +38946,7 @@ var PptxHandlerRuntime51 = class extends PptxHandlerRuntime50 {
36993
38946
  };
36994
38947
 
36995
38948
  // src/core/core/runtime/PptxHandlerRuntimePlaceholderStyles.ts
36996
- var PptxHandlerRuntime52 = class _PptxHandlerRuntime extends PptxHandlerRuntime51 {
38949
+ var PptxHandlerRuntime53 = class _PptxHandlerRuntime extends PptxHandlerRuntime52 {
36997
38950
  /**
36998
38951
  * Parse a single `a:lvlXpPr` node into a structured
36999
38952
  * {@link PlaceholderTextLevelStyle}.
@@ -37114,7 +39067,7 @@ var PptxHandlerRuntime52 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
37114
39067
  };
37115
39068
 
37116
39069
  // src/core/core/runtime/PptxHandlerRuntimePlaceholderDefaults.ts
37117
- var PptxHandlerRuntime53 = class _PptxHandlerRuntime extends PptxHandlerRuntime52 {
39070
+ var PptxHandlerRuntime54 = class _PptxHandlerRuntime extends PptxHandlerRuntime53 {
37118
39071
  /**
37119
39072
  * Extract structured {@link PlaceholderDefaults} from a layout or master
37120
39073
  * shape that carries a `p:ph` element.
@@ -37257,7 +39210,118 @@ var PptxHandlerRuntime53 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
37257
39210
  };
37258
39211
 
37259
39212
  // src/core/core/runtime/PptxHandlerRuntimeMasterElements.ts
37260
- var PptxHandlerRuntime54 = class extends PptxHandlerRuntime53 {
39213
+ function parseHeaderFooterFlags(hf) {
39214
+ if (!hf) {
39215
+ return void 0;
39216
+ }
39217
+ const result = {};
39218
+ if (hf["@_hdr"] !== void 0) {
39219
+ result.hasHeader = String(hf["@_hdr"]) !== "0";
39220
+ }
39221
+ if (hf["@_ftr"] !== void 0) {
39222
+ result.hasFooter = String(hf["@_ftr"]) !== "0";
39223
+ }
39224
+ if (hf["@_dt"] !== void 0) {
39225
+ result.hasDateTime = String(hf["@_dt"]) !== "0";
39226
+ }
39227
+ if (hf["@_sldNum"] !== void 0) {
39228
+ result.hasSlideNumber = String(hf["@_sldNum"]) !== "0";
39229
+ }
39230
+ return Object.keys(result).length > 0 ? result : void 0;
39231
+ }
39232
+ var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
39233
+ /**
39234
+ * Parse a `CT_TextListStyle` node (`a:defPPr` + `a:lvl1pPr` … `a:lvl9pPr`)
39235
+ * into a level-keyed style map. Used for `<p:txStyles>` children
39236
+ * (`p:titleStyle`, `p:bodyStyle`, `p:otherStyle`) — see ECMA-376 §19.3.1.52.
39237
+ */
39238
+ parseTextListStyle(node) {
39239
+ if (!node) {
39240
+ return void 0;
39241
+ }
39242
+ const levels = {};
39243
+ const defParsed = this.parsePlaceholderLevelStyle(node["a:defPPr"]);
39244
+ if (defParsed) {
39245
+ levels[-1] = defParsed;
39246
+ }
39247
+ for (let lvl = 1; lvl <= 9; lvl++) {
39248
+ const parsed = this.parsePlaceholderLevelStyle(
39249
+ node[`a:lvl${lvl}pPr`]
39250
+ );
39251
+ if (parsed) {
39252
+ levels[lvl - 1] = parsed;
39253
+ }
39254
+ }
39255
+ return Object.keys(levels).length > 0 ? levels : void 0;
39256
+ }
39257
+ /**
39258
+ * Parse `<p:txStyles>` from a slide-master XML object into a structured
39259
+ * {@link PptxMasterTextStyles}. Used to populate `PptxSlideMaster.txStyles`
39260
+ * so the title/body/other text-style cascade (P-H1) is visible on the
39261
+ * typed model.
39262
+ */
39263
+ parseMasterTxStyles(masterXml) {
39264
+ const txStyles = masterXml?.["p:txStyles"];
39265
+ if (!txStyles) {
39266
+ return void 0;
39267
+ }
39268
+ const titleStyle = this.parseTextListStyle(txStyles["p:titleStyle"]);
39269
+ const bodyStyle = this.parseTextListStyle(txStyles["p:bodyStyle"]);
39270
+ const otherStyle = this.parseTextListStyle(txStyles["p:otherStyle"]);
39271
+ if (!titleStyle && !bodyStyle && !otherStyle) {
39272
+ return void 0;
39273
+ }
39274
+ const result = {};
39275
+ if (titleStyle) {
39276
+ result.titleStyle = titleStyle;
39277
+ }
39278
+ if (bodyStyle) {
39279
+ result.bodyStyle = bodyStyle;
39280
+ }
39281
+ if (otherStyle) {
39282
+ result.otherStyle = otherStyle;
39283
+ }
39284
+ return result;
39285
+ }
39286
+ /**
39287
+ * Enrich an array of {@link PptxSlideMaster} entries (already produced by
39288
+ * `parseSlideMasters`) with parsed `<p:txStyles>`. Loads each master's XML
39289
+ * once, parses, and caches it in `masterXmlMap` for downstream consumers.
39290
+ *
39291
+ * Also stores the parsed result on the per-master cache so that the
39292
+ * inheritance chain in `applyMasterTextStyleCascade` can find it without
39293
+ * re-parsing.
39294
+ */
39295
+ async enrichSlideMastersWithTxStyles(slideMasters) {
39296
+ for (const master of slideMasters) {
39297
+ try {
39298
+ let masterXmlObj = this.masterXmlMap.get(master.path);
39299
+ if (!masterXmlObj) {
39300
+ const xmlStr = await this.zip.file(master.path)?.async("string");
39301
+ if (!xmlStr) {
39302
+ continue;
39303
+ }
39304
+ masterXmlObj = this.parser.parse(xmlStr);
39305
+ this.masterXmlMap.set(master.path, masterXmlObj);
39306
+ }
39307
+ const sldMaster = masterXmlObj["p:sldMaster"];
39308
+ if (!sldMaster) {
39309
+ continue;
39310
+ }
39311
+ const parsed = this.parseMasterTxStyles(sldMaster);
39312
+ if (parsed) {
39313
+ master.txStyles = parsed;
39314
+ this.masterTxStylesCache.set(master.path, parsed);
39315
+ }
39316
+ const hf = parseHeaderFooterFlags(sldMaster["p:hf"]);
39317
+ if (hf) {
39318
+ master.headerFooter = hf;
39319
+ }
39320
+ } catch (e) {
39321
+ console.warn("Failed to parse master txStyles:", e);
39322
+ }
39323
+ }
39324
+ }
37261
39325
  parsePresentationDefaultTextStyle() {
37262
39326
  const presentation = this.presentationData?.["p:presentation"];
37263
39327
  const defaultTextStyle = presentation?.["p:defaultTextStyle"];
@@ -37413,7 +39477,7 @@ var PptxHandlerRuntime54 = class extends PptxHandlerRuntime53 {
37413
39477
  };
37414
39478
 
37415
39479
  // src/core/core/runtime/PptxHandlerRuntimeLayoutElements.ts
37416
- var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
39480
+ var PptxHandlerRuntime56 = class extends PptxHandlerRuntime55 {
37417
39481
  async getLayoutElements(slidePath) {
37418
39482
  const slideRels = this.slideRelsMap.get(slidePath);
37419
39483
  if (!slideRels) {
@@ -37537,10 +39601,10 @@ var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
37537
39601
  }
37538
39602
  }
37539
39603
  }
37540
- this.currentSlideClrMapOverride = prevClrMapOverride;
37541
39604
  const layoutShowMasterSp = layoutXmlObj["p:sldLayout"]?.["@_showMasterSp"];
37542
39605
  const showMasterSp = layoutShowMasterSp === void 0 || String(layoutShowMasterSp).trim().toLowerCase() !== "0" && String(layoutShowMasterSp).trim().toLowerCase() !== "false";
37543
39606
  const masterElements = showMasterSp ? await this.getMasterElements(layoutPath) : [];
39607
+ this.currentSlideClrMapOverride = prevClrMapOverride;
37544
39608
  const allElements = [...masterElements, ...elements];
37545
39609
  this.layoutCache.set(layoutPath, allElements);
37546
39610
  return allElements;
@@ -37552,7 +39616,7 @@ var PptxHandlerRuntime55 = class extends PptxHandlerRuntime54 {
37552
39616
  };
37553
39617
 
37554
39618
  // src/core/core/runtime/PptxHandlerRuntimeThemeFormatScheme.ts
37555
- var PptxHandlerRuntime56 = class _PptxHandlerRuntime extends PptxHandlerRuntime55 {
39619
+ var PptxHandlerRuntime57 = class _PptxHandlerRuntime extends PptxHandlerRuntime56 {
37556
39620
  /**
37557
39621
  * Collect fill-style children from a style list node, preserving
37558
39622
  * document order. Handles `a:solidFill`, `a:gradFill`, `a:pattFill`,
@@ -37794,7 +39858,7 @@ var PptxHandlerRuntime56 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
37794
39858
  };
37795
39859
 
37796
39860
  // src/core/core/runtime/PptxHandlerRuntimeThemeOverrides.ts
37797
- var PptxHandlerRuntime57 = class extends PptxHandlerRuntime56 {
39861
+ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
37798
39862
  /**
37799
39863
  * Parse the `a:fmtScheme` element from the theme into a structured
37800
39864
  * {@link PptxThemeFormatScheme}. Each sub-list (fillStyleLst, lnStyleLst,
@@ -37991,8 +40055,10 @@ var PptxHandlerRuntime57 = class extends PptxHandlerRuntime56 {
37991
40055
  }
37992
40056
  const fontScheme = root["a:fontScheme"];
37993
40057
  if (fontScheme) {
37994
- const majorLatin = fontScheme["a:majorFont"]?.["a:latin"];
37995
- const minorLatin = fontScheme["a:minorFont"]?.["a:latin"];
40058
+ const majorFontNode = fontScheme["a:majorFont"];
40059
+ const minorFontNode = fontScheme["a:minorFont"];
40060
+ const majorLatin = majorFontNode?.["a:latin"];
40061
+ const minorLatin = minorFontNode?.["a:latin"];
37996
40062
  const majorFont = this.normalizeTypefaceToken(String(majorLatin?.["@_typeface"] || ""));
37997
40063
  const minorFont = this.normalizeTypefaceToken(String(minorLatin?.["@_typeface"] || ""));
37998
40064
  if (!result.colorOverrides) {
@@ -38015,13 +40081,46 @@ var PptxHandlerRuntime57 = class extends PptxHandlerRuntime56 {
38015
40081
  };
38016
40082
 
38017
40083
  // src/core/core/runtime/PptxHandlerRuntimeThemeRefResolution.ts
38018
- var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
40084
+ var COLOR_CHOICE_KEYS2 = [
40085
+ "a:scrgbClr",
40086
+ "a:srgbClr",
40087
+ "a:hslClr",
40088
+ "a:sysClr",
40089
+ "a:schemeClr",
40090
+ "a:prstClr"
40091
+ ];
40092
+ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
40093
+ /**
40094
+ * Pull the verbatim colour-choice child out of a style-matrix-reference
40095
+ * element (`a:lnRef`/`a:fillRef`/`a:effectRef`/`a:fontRef`). Returns the
40096
+ * full child object so it can be round-tripped at save time, preserving
40097
+ * any contained colour transforms (`a:lumMod`, `a:tint`, etc.).
40098
+ */
40099
+ extractRefColorXml(refNode) {
40100
+ if (!refNode) {
40101
+ return void 0;
40102
+ }
40103
+ for (const key of COLOR_CHOICE_KEYS2) {
40104
+ const child = refNode[key];
40105
+ if (child !== void 0) {
40106
+ return { [key]: child };
40107
+ }
40108
+ }
40109
+ return void 0;
40110
+ }
38019
40111
  /**
38020
40112
  * Resolve a `a:effectRef` element into concrete effect properties
38021
40113
  * by looking up `@_idx` in the theme format scheme's effect style list.
38022
40114
  */
38023
40115
  resolveThemeEffectRef(refNode, style) {
38024
40116
  const idx = parseInt(String(refNode["@_idx"] || "0"), 10);
40117
+ if (Number.isFinite(idx) && idx > 0) {
40118
+ style.effectRefIdx = idx;
40119
+ }
40120
+ const overrideColorXml = this.extractRefColorXml(refNode);
40121
+ if (overrideColorXml) {
40122
+ style.effectRefColorXml = overrideColorXml;
40123
+ }
38025
40124
  if (!Number.isFinite(idx) || idx <= 0 || !this.themeFormatScheme || idx > this.themeFormatScheme.effectStyles.length) {
38026
40125
  return;
38027
40126
  }
@@ -38074,6 +40173,13 @@ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
38074
40173
  resolveThemeLineRef(refNode, style) {
38075
40174
  const idx = parseInt(String(refNode["@_idx"] || "0"), 10);
38076
40175
  const overrideColor = this.parseColor(refNode);
40176
+ if (Number.isFinite(idx) && idx > 0) {
40177
+ style.lnRefIdx = idx;
40178
+ }
40179
+ const overrideColorXml = this.extractRefColorXml(refNode);
40180
+ if (overrideColorXml) {
40181
+ style.lnRefColorXml = overrideColorXml;
40182
+ }
38077
40183
  if (!Number.isFinite(idx) || idx <= 0 || !this.themeFormatScheme || idx > this.themeFormatScheme.lineStyles.length) {
38078
40184
  style.strokeColor = overrideColor;
38079
40185
  if (overrideColor) {
@@ -38145,6 +40251,13 @@ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
38145
40251
  */
38146
40252
  resolveThemeFillRef(refNode, style) {
38147
40253
  const idx = parseInt(String(refNode["@_idx"] || "0"), 10);
40254
+ if (Number.isFinite(idx) && idx > 0) {
40255
+ style.fillRefIdx = idx;
40256
+ }
40257
+ const overrideColorXml = this.extractRefColorXml(refNode);
40258
+ if (overrideColorXml) {
40259
+ style.fillRefColorXml = overrideColorXml;
40260
+ }
38148
40261
  if (!Number.isFinite(idx) || idx <= 0 || !this.themeFormatScheme) {
38149
40262
  style.fillMode = "theme";
38150
40263
  style.fillColor = this.parseColor(refNode);
@@ -38210,7 +40323,7 @@ var PptxHandlerRuntime58 = class extends PptxHandlerRuntime57 {
38210
40323
  };
38211
40324
 
38212
40325
  // src/core/core/runtime/PptxHandlerRuntimeThemeLoading.ts
38213
- var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
40326
+ var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
38214
40327
  async resolvePrimaryThemePath() {
38215
40328
  const masterFiles = this.zip.file(/^ppt\/slideMasters\/slideMaster\d+\.xml$/);
38216
40329
  if (!masterFiles || masterFiles.length === 0) {
@@ -38320,62 +40433,97 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
38320
40433
  formatScheme: this.themeFormatScheme
38321
40434
  };
38322
40435
  }
38323
- async applySlideMasterColorMap(defaultMap) {
40436
+ /**
40437
+ * Parse every slide master's `<p:clrMap>` element and store the alias
40438
+ * dictionaries on {@link masterClrMaps}. Do *not* mutate
40439
+ * {@link themeColorMap} — alias resolution happens at colour-lookup
40440
+ * time so that:
40441
+ *
40442
+ * 1. The raw theme scheme stays the source of truth (clrMap is a
40443
+ * routing layer, not a colour table).
40444
+ * 2. Multi-master decks resolve each slide against its own master's
40445
+ * clrMap rather than always against `masterFiles[0]`.
40446
+ * 3. Layout `clrMapOvr` semantics work correctly when a slide's master
40447
+ * differs from the deck's first master.
40448
+ *
40449
+ * Phase 2 Stream B / C-H4.
40450
+ */
40451
+ async applySlideMasterColorMap(_defaultMap) {
38324
40452
  const masterFiles = this.zip.file(/^ppt\/slideMasters\/slideMaster\d+\.xml$/);
38325
40453
  if (!masterFiles || masterFiles.length === 0) {
38326
40454
  return;
38327
40455
  }
38328
- try {
38329
- const masterXml = await masterFiles[0].async("string");
38330
- const masterData = this.parser.parse(masterXml);
38331
- const clrMap = masterData?.["p:sldMaster"]?.["p:clrMap"];
38332
- if (!clrMap) {
38333
- return;
38334
- }
38335
- const aliasKeys = [
38336
- "bg1",
38337
- "tx1",
38338
- "bg2",
38339
- "tx2",
38340
- "accent1",
38341
- "accent2",
38342
- "accent3",
38343
- "accent4",
38344
- "accent5",
38345
- "accent6",
38346
- "hlink",
38347
- "folHlink"
38348
- ];
38349
- for (const aliasKey of aliasKeys) {
38350
- const mappedKey = String(clrMap[`@_${aliasKey}`] || "").trim().toLowerCase();
38351
- if (!mappedKey) {
40456
+ const aliasKeys = [
40457
+ "bg1",
40458
+ "tx1",
40459
+ "bg2",
40460
+ "tx2",
40461
+ "accent1",
40462
+ "accent2",
40463
+ "accent3",
40464
+ "accent4",
40465
+ "accent5",
40466
+ "accent6",
40467
+ "hlink",
40468
+ "folHlink"
40469
+ ];
40470
+ for (const file of masterFiles) {
40471
+ try {
40472
+ const masterXml = await file.async("string");
40473
+ const masterData = this.parser.parse(masterXml);
40474
+ const clrMap = masterData?.["p:sldMaster"]?.["p:clrMap"];
40475
+ if (!clrMap) {
38352
40476
  continue;
38353
40477
  }
38354
- const mappedColor = this.themeColorMap[mappedKey] || defaultMap[mappedKey];
38355
- if (mappedColor) {
38356
- this.themeColorMap[aliasKey] = mappedColor;
40478
+ const aliasMap = {};
40479
+ for (const aliasKey of aliasKeys) {
40480
+ const mappedKey = String(clrMap[`@_${aliasKey}`] || "").trim().toLowerCase();
40481
+ if (mappedKey) {
40482
+ aliasMap[aliasKey] = mappedKey;
40483
+ }
40484
+ }
40485
+ if (Object.keys(aliasMap).length > 0) {
40486
+ this.masterClrMaps.set(file.name, aliasMap);
38357
40487
  }
40488
+ } catch (error) {
40489
+ console.warn(`Failed to parse slide master color map for ${file.name}:`, error);
38358
40490
  }
38359
- } catch (error) {
38360
- console.warn("Failed to parse slide master color map:", error);
38361
40491
  }
38362
40492
  }
38363
- async loadThemeData() {
38364
- const themeFiles = this.zip.file(/^ppt\/theme\/theme\d+\.xml$/);
38365
- if (!themeFiles || themeFiles.length === 0) {
38366
- return;
40493
+ /**
40494
+ * Parse a single theme part into structured colour, font, and format
40495
+ * scheme dictionaries. Used both for the global default theme and for
40496
+ * each master's per-master theme (multi-master support).
40497
+ *
40498
+ * Phase 2 Stream B / C-H4.
40499
+ */
40500
+ async parseThemePart(themePath) {
40501
+ const themeFile = this.zip.file(themePath);
40502
+ if (!themeFile) {
40503
+ return null;
38367
40504
  }
38368
- const preferredThemePath = await this.resolvePrimaryThemePath();
38369
- const preferredThemeFile = preferredThemePath ? themeFiles.find((file) => file.name === preferredThemePath) : void 0;
38370
- const themeFile = preferredThemeFile ?? themeFiles[0];
38371
40505
  const themeXml2 = await themeFile.async("string");
40506
+ this.originalThemeXmlByPath.set(themePath, themeXml2);
38372
40507
  const themeData = this.parser.parse(themeXml2);
38373
40508
  const themeRoot = themeData["a:theme"];
38374
40509
  const themeElements = themeRoot?.["a:themeElements"];
38375
40510
  const colorScheme = themeElements?.["a:clrScheme"];
38376
40511
  const fontScheme = themeElements?.["a:fontScheme"];
40512
+ const fmtScheme = themeElements?.["a:fmtScheme"];
40513
+ const themeName = String(themeRoot?.["@_name"] || "").trim();
40514
+ if (themeName) {
40515
+ this.masterThemeNames.set(themePath, themeName);
40516
+ }
40517
+ const colorSchemeName = String(colorScheme?.["@_name"] || "").trim();
40518
+ if (colorSchemeName) {
40519
+ this.masterThemeColorSchemeNames.set(themePath, colorSchemeName);
40520
+ }
40521
+ const fontSchemeName = String(fontScheme?.["@_name"] || "").trim();
40522
+ if (fontSchemeName) {
40523
+ this.masterThemeFontSchemeNames.set(themePath, fontSchemeName);
40524
+ }
38377
40525
  const defaultMap = this.getDefaultSchemeColorMap();
38378
- this.themeColorMap = { ...defaultMap };
40526
+ const colorMap = { ...defaultMap };
38379
40527
  if (colorScheme) {
38380
40528
  const schemeKeys = [
38381
40529
  "dk1",
@@ -38395,39 +40543,196 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
38395
40543
  const colorNode = colorScheme[`a:${key}`];
38396
40544
  const parsed = this.parseColorChoice(colorNode);
38397
40545
  if (parsed) {
38398
- this.themeColorMap[key] = parsed;
40546
+ colorMap[key] = parsed;
38399
40547
  }
38400
40548
  }
38401
40549
  }
38402
- this.themeColorMap["tx1"] = this.themeColorMap["dk1"] || defaultMap["dk1"];
38403
- this.themeColorMap["bg1"] = this.themeColorMap["lt1"] || defaultMap["lt1"];
38404
- this.themeColorMap["tx2"] = this.themeColorMap["dk2"] || defaultMap["dk2"];
38405
- this.themeColorMap["bg2"] = this.themeColorMap["lt2"] || defaultMap["lt2"];
38406
- await this.applySlideMasterColorMap(defaultMap);
38407
- const majorLatin = fontScheme?.["a:majorFont"]?.["a:latin"];
38408
- const minorLatin = fontScheme?.["a:minorFont"]?.["a:latin"];
40550
+ colorMap["tx1"] = colorMap["dk1"] || defaultMap["dk1"];
40551
+ colorMap["bg1"] = colorMap["lt1"] || defaultMap["lt1"];
40552
+ colorMap["tx2"] = colorMap["dk2"] || defaultMap["dk2"];
40553
+ colorMap["bg2"] = colorMap["lt2"] || defaultMap["lt2"];
40554
+ const majorFontNode = fontScheme?.["a:majorFont"];
40555
+ const minorFontNode = fontScheme?.["a:minorFont"];
40556
+ const majorLatin = majorFontNode?.["a:latin"];
40557
+ const minorLatin = minorFontNode?.["a:latin"];
38409
40558
  const majorFont = this.normalizeTypefaceToken(String(majorLatin?.["@_typeface"] || ""));
38410
40559
  const minorFont = this.normalizeTypefaceToken(String(minorLatin?.["@_typeface"] || ""));
38411
- this.themeFontMap = {};
40560
+ const fontMap = {};
38412
40561
  if (majorFont) {
38413
- this.themeFontMap["mj-lt"] = majorFont;
38414
- this.themeFontMap["mj-ea"] = majorFont;
38415
- this.themeFontMap["mj-cs"] = majorFont;
40562
+ fontMap["mj-lt"] = majorFont;
40563
+ fontMap["mj-ea"] = majorFont;
40564
+ fontMap["mj-cs"] = majorFont;
38416
40565
  }
38417
40566
  if (minorFont) {
38418
- this.themeFontMap["mn-lt"] = minorFont;
38419
- this.themeFontMap["mn-ea"] = minorFont;
38420
- this.themeFontMap["mn-cs"] = minorFont;
40567
+ fontMap["mn-lt"] = minorFont;
40568
+ fontMap["mn-ea"] = minorFont;
40569
+ fontMap["mn-cs"] = minorFont;
38421
40570
  }
38422
- const fmtScheme = themeElements?.["a:fmtScheme"];
38423
- if (fmtScheme) {
38424
- this.themeFormatScheme = this.parseFormatScheme(fmtScheme);
40571
+ const majorEa = this.normalizeTypefaceToken(
40572
+ String(majorFontNode?.["a:ea"]?.["@_typeface"] || "")
40573
+ );
40574
+ if (majorEa) {
40575
+ fontMap["mj-ea"] = majorEa;
40576
+ }
40577
+ const majorCs = this.normalizeTypefaceToken(
40578
+ String(majorFontNode?.["a:cs"]?.["@_typeface"] || "")
40579
+ );
40580
+ if (majorCs) {
40581
+ fontMap["mj-cs"] = majorCs;
40582
+ }
40583
+ const minorEa = this.normalizeTypefaceToken(
40584
+ String(minorFontNode?.["a:ea"]?.["@_typeface"] || "")
40585
+ );
40586
+ if (minorEa) {
40587
+ fontMap["mn-ea"] = minorEa;
40588
+ }
40589
+ const minorCs = this.normalizeTypefaceToken(
40590
+ String(minorFontNode?.["a:cs"]?.["@_typeface"] || "")
40591
+ );
40592
+ if (minorCs) {
40593
+ fontMap["mn-cs"] = minorCs;
40594
+ }
40595
+ const majorScripts = this.collectFontScriptOverrides(majorFontNode);
40596
+ if (Object.keys(majorScripts).length > 0) {
40597
+ this.masterThemeMajorFontScripts.set(themePath, majorScripts);
40598
+ }
40599
+ const minorScripts = this.collectFontScriptOverrides(minorFontNode);
40600
+ if (Object.keys(minorScripts).length > 0) {
40601
+ this.masterThemeMinorFontScripts.set(themePath, minorScripts);
40602
+ }
40603
+ const objectDefaultsNode = themeRoot?.["a:objectDefaults"];
40604
+ if (objectDefaultsNode) {
40605
+ const od = {
40606
+ spDef: objectDefaultsNode["a:spDef"],
40607
+ lnDef: objectDefaultsNode["a:lnDef"],
40608
+ txDef: objectDefaultsNode["a:txDef"]
40609
+ };
40610
+ if (od.spDef !== void 0 || od.lnDef !== void 0 || od.txDef !== void 0) {
40611
+ this.masterThemeObjectDefaults.set(themePath, od);
40612
+ }
40613
+ }
40614
+ const extraClrSchemeLst = themeRoot?.["a:extraClrSchemeLst"];
40615
+ if (extraClrSchemeLst !== void 0) {
40616
+ this.masterThemeExtraClrSchemeLst.set(themePath, extraClrSchemeLst);
40617
+ }
40618
+ const custClrLst = themeRoot?.["a:custClrLst"];
40619
+ if (custClrLst !== void 0) {
40620
+ this.masterThemeCustClrLst.set(themePath, custClrLst);
40621
+ }
40622
+ const themeExtLst = themeRoot?.["a:extLst"];
40623
+ if (themeExtLst !== void 0) {
40624
+ this.masterThemeExtLst.set(themePath, themeExtLst);
40625
+ }
40626
+ const formatScheme = fmtScheme ? this.parseFormatScheme(fmtScheme) : void 0;
40627
+ return { colorMap, fontMap, formatScheme };
40628
+ }
40629
+ /**
40630
+ * Parse `<a:font script="…" typeface="…"/>` children of a major or
40631
+ * minor font node into a `script -> typeface` dictionary.
40632
+ *
40633
+ * fast-xml-parser collapses repeated tags into arrays, so iterate
40634
+ * over the array form regardless of how many siblings are present.
40635
+ *
40636
+ * Phase 4 Stream A / M4.
40637
+ */
40638
+ collectFontScriptOverrides(fontNode) {
40639
+ const overrides = {};
40640
+ if (!fontNode) {
40641
+ return overrides;
40642
+ }
40643
+ const fontEntries = this.ensureArray(fontNode["a:font"]);
40644
+ for (const entry of fontEntries) {
40645
+ const script = String(entry?.["@_script"] || "").trim();
40646
+ const typeface = this.normalizeTypefaceToken(String(entry?.["@_typeface"] || ""));
40647
+ if (script && typeface) {
40648
+ overrides[script] = typeface;
40649
+ }
40650
+ }
40651
+ return overrides;
40652
+ }
40653
+ /**
40654
+ * Resolve the theme file path referenced by a given master's `.rels`.
40655
+ * Returns `undefined` when the master has no theme relationship.
40656
+ */
40657
+ async resolveThemePathForMaster(masterPath) {
40658
+ const relsPath = masterPath.replace(
40659
+ /ppt\/slideMasters\/(slideMaster\d+)\.xml/,
40660
+ "ppt/slideMasters/_rels/$1.xml.rels"
40661
+ );
40662
+ const relsXml = this.zip.file(relsPath);
40663
+ if (!relsXml) {
40664
+ return void 0;
40665
+ }
40666
+ const relsData = this.parser.parse(await relsXml.async("string"));
40667
+ const relNodes = this.ensureArray(relsData?.Relationships?.Relationship);
40668
+ for (const rel of relNodes) {
40669
+ const target = String(rel["@_Target"] || "");
40670
+ if (!target.includes("theme")) {
40671
+ continue;
40672
+ }
40673
+ const themePath = target.startsWith("..") ? this.resolvePath(masterPath.substring(0, masterPath.lastIndexOf("/") + 1), target) : target.startsWith("/") ? target.slice(1) : `ppt/${target.replace(/^\.?\//, "")}`;
40674
+ if (themePath.startsWith("ppt/theme/")) {
40675
+ return themePath;
40676
+ }
40677
+ }
40678
+ return void 0;
40679
+ }
40680
+ /**
40681
+ * Populate {@link masterThemeColorMaps}, {@link masterThemeFontMaps},
40682
+ * and {@link masterThemeFormatSchemes} for every slide master in the
40683
+ * deck. Multi-master support — Phase 2 Stream B / C-H4.
40684
+ */
40685
+ async loadPerMasterThemes() {
40686
+ const masterFiles = this.zip.file(/^ppt\/slideMasters\/slideMaster\d+\.xml$/);
40687
+ if (!masterFiles || masterFiles.length === 0) {
40688
+ return;
40689
+ }
40690
+ for (const file of masterFiles) {
40691
+ try {
40692
+ const themePath = await this.resolveThemePathForMaster(file.name);
40693
+ if (!themePath) {
40694
+ continue;
40695
+ }
40696
+ this.masterThemePaths.set(file.name, themePath);
40697
+ const parsed = await this.parseThemePart(themePath);
40698
+ if (!parsed) {
40699
+ continue;
40700
+ }
40701
+ this.masterThemeColorMaps.set(file.name, parsed.colorMap);
40702
+ this.masterThemeFontMaps.set(file.name, parsed.fontMap);
40703
+ if (parsed.formatScheme) {
40704
+ this.masterThemeFormatSchemes.set(file.name, parsed.formatScheme);
40705
+ }
40706
+ } catch (error) {
40707
+ console.warn(`Failed to load per-master theme for ${file.name}:`, error);
40708
+ }
40709
+ }
40710
+ }
40711
+ async loadThemeData() {
40712
+ const themeFiles = this.zip.file(/^ppt\/theme\/theme\d+\.xml$/);
40713
+ if (!themeFiles || themeFiles.length === 0) {
40714
+ return;
38425
40715
  }
40716
+ const preferredThemePath = await this.resolvePrimaryThemePath();
40717
+ const themeFile = preferredThemePath ? themeFiles.find((file) => file.name === preferredThemePath) ?? themeFiles[0] : themeFiles[0];
40718
+ const parsed = await this.parseThemePart(themeFile.name);
40719
+ if (parsed) {
40720
+ this.themeColorMap = parsed.colorMap;
40721
+ this.themeFontMap = parsed.fontMap;
40722
+ if (parsed.formatScheme) {
40723
+ this.themeFormatScheme = parsed.formatScheme;
40724
+ }
40725
+ }
40726
+ await this.applySlideMasterColorMap(this.getDefaultSchemeColorMap());
40727
+ await this.loadPerMasterThemes();
40728
+ this.globalThemeColorMapSnapshot = { ...this.themeColorMap };
40729
+ this.globalThemeFontMapSnapshot = { ...this.themeFontMap };
40730
+ this.globalThemeFormatSchemeSnapshot = this.themeFormatScheme;
38426
40731
  }
38427
40732
  };
38428
40733
 
38429
40734
  // src/core/core/runtime/PptxHandlerRuntimeThemeProcessing.ts
38430
- var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
40735
+ var PptxHandlerRuntime61 = class extends PptxHandlerRuntime60 {
38431
40736
  // ---------------------------------------------------------------------------
38432
40737
  // Theme editing — update colour scheme, font scheme, and name in the zip
38433
40738
  // ---------------------------------------------------------------------------
@@ -38577,7 +40882,7 @@ var PptxHandlerRuntime60 = class extends PptxHandlerRuntime59 {
38577
40882
  };
38578
40883
 
38579
40884
  // src/core/core/runtime/PptxHandlerRuntimeComments.ts
38580
- var PptxHandlerRuntime61 = class _PptxHandlerRuntime extends PptxHandlerRuntime60 {
40885
+ var PptxHandlerRuntime62 = class _PptxHandlerRuntime extends PptxHandlerRuntime61 {
38581
40886
  /**
38582
40887
  * Parse modern threaded comments (PowerPoint 2019+ / Office 365).
38583
40888
  * Modern comments use `p188:cmLst`/`p15:cmLst` roots within
@@ -38810,7 +41115,7 @@ var PptxHandlerRuntime61 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
38810
41115
  };
38811
41116
 
38812
41117
  // src/core/core/runtime/PptxHandlerRuntimeSmartArtXmlUtils.ts
38813
- var PptxHandlerRuntime62 = class extends PptxHandlerRuntime61 {
41118
+ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
38814
41119
  async readXmlPartByRelationshipId(slidePath, relationshipId) {
38815
41120
  const normalizedRelationshipId = String(relationshipId || "").trim();
38816
41121
  if (normalizedRelationshipId.length === 0) {
@@ -38965,7 +41270,7 @@ var PptxHandlerRuntime62 = class extends PptxHandlerRuntime61 {
38965
41270
  };
38966
41271
 
38967
41272
  // src/core/core/runtime/PptxHandlerRuntimeSmartArtParsing.ts
38968
- var PptxHandlerRuntime63 = class _PptxHandlerRuntime extends PptxHandlerRuntime62 {
41273
+ var PptxHandlerRuntime64 = class _PptxHandlerRuntime extends PptxHandlerRuntime63 {
38969
41274
  /**
38970
41275
  * Parse quick style from `ppt/diagrams/quickStyles*.xml`.
38971
41276
  */
@@ -39124,7 +41429,7 @@ var PptxHandlerRuntime63 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
39124
41429
  };
39125
41430
 
39126
41431
  // src/core/core/runtime/PptxHandlerRuntimeSmartArt.ts
39127
- var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
41432
+ var PptxHandlerRuntime65 = class _PptxHandlerRuntime extends PptxHandlerRuntime64 {
39128
41433
  async getSmartArtDataForGraphicFrame(slidePath, graphicFrame) {
39129
41434
  const graphicData = this.xmlLookupService.getChildByLocalName(
39130
41435
  this.xmlLookupService.getChildByLocalName(graphicFrame, "graphic"),
@@ -39175,10 +41480,14 @@ var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
39175
41480
  const layoutPart = layoutRelationshipId.length > 0 ? await this.readXmlPartByRelationshipId(slidePath, layoutRelationshipId) : void 0;
39176
41481
  const layoutType = layoutPart?.partPath?.split("/").pop()?.replace(/\.[^.]+$/, "") || void 0;
39177
41482
  const chrome = this.parseSmartArtChrome(dataModel);
39178
- const drawingRelationshipId = String(relationshipIds["@_r:cs"] || "").trim();
39179
- const drawingShapes = await this.parseSmartArtDrawingShapes(slidePath, drawingRelationshipId);
39180
41483
  const colorsRelationshipId = String(relationshipIds["@_r:cs"] || "").trim();
39181
41484
  const colorTransform = await this.parseSmartArtColorTransform(slidePath, colorsRelationshipId);
41485
+ const drawingResolution = await this.resolveSmartArtDrawingPart(
41486
+ slidePath,
41487
+ diagramDataRelationshipId
41488
+ );
41489
+ const drawingShapes = drawingResolution ? await this.parseSmartArtDrawingShapesFromPath(drawingResolution.path) : [];
41490
+ const drawingRelationshipId = drawingResolution?.relId;
39182
41491
  const styleRelationshipId = String(relationshipIds["@_r:qs"] || "").trim();
39183
41492
  const quickStyle = await this.parseSmartArtQuickStyle(slidePath, styleRelationshipId);
39184
41493
  return {
@@ -39190,11 +41499,87 @@ var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
39190
41499
  colorTransform,
39191
41500
  quickStyle,
39192
41501
  dataRelId: diagramDataRelationshipId,
39193
- drawingRelId: drawingRelationshipId.length > 0 ? drawingRelationshipId : void 0,
41502
+ drawingRelId: drawingRelationshipId && drawingRelationshipId.length > 0 ? drawingRelationshipId : void 0,
39194
41503
  colorsRelId: colorsRelationshipId.length > 0 ? colorsRelationshipId : void 0,
39195
41504
  styleRelId: styleRelationshipId.length > 0 ? styleRelationshipId : void 0
39196
41505
  };
39197
41506
  }
41507
+ /**
41508
+ * Resolve the SmartArt drawing-shapes part path + relationship id.
41509
+ *
41510
+ * Strategy:
41511
+ * 1. Locate the data-model part's rels file
41512
+ * (`ppt/diagrams/_rels/data*.xml.rels`) via `slideRelsMap`.
41513
+ * 2. Find a relationship whose `Type` matches the `…/diagramDrawing`
41514
+ * URI. PowerPoint emits this for any deck that has had its
41515
+ * SmartArt rendered to drawing shapes.
41516
+ * 3. Return the matched part path (so the caller can load it
41517
+ * directly) and the relationship id (for round-trip preservation).
41518
+ */
41519
+ async resolveSmartArtDrawingPart(slidePath, diagramDataRelationshipId) {
41520
+ if (diagramDataRelationshipId.length === 0) {
41521
+ return void 0;
41522
+ }
41523
+ const slideRels = this.slideRelsMap.get(slidePath);
41524
+ const dataTarget = slideRels?.get(diagramDataRelationshipId);
41525
+ if (!dataTarget) {
41526
+ return void 0;
41527
+ }
41528
+ const dataPath = this.resolveImagePath(slidePath, dataTarget);
41529
+ const dataDir = dataPath.replace(/\/[^/]+$/, "");
41530
+ const dataFile = dataPath.split("/").pop() ?? "";
41531
+ const dataRelsPath = `${dataDir}/_rels/${dataFile}.rels`;
41532
+ const relsXml = await this.zip.file(dataRelsPath)?.async("string");
41533
+ if (!relsXml) {
41534
+ return void 0;
41535
+ }
41536
+ try {
41537
+ const parsed = this.parser.parse(relsXml);
41538
+ const relsRoot = parsed["Relationships"];
41539
+ if (!relsRoot) {
41540
+ return void 0;
41541
+ }
41542
+ const rels = this.ensureArray(relsRoot["Relationship"]);
41543
+ const drawingRel = rels.find(
41544
+ (rel) => String(rel?.["@_Type"] || "").endsWith("/diagramDrawing")
41545
+ );
41546
+ const id = String(drawingRel?.["@_Id"] || "").trim();
41547
+ const target = String(drawingRel?.["@_Target"] || "").trim();
41548
+ if (id.length === 0 || target.length === 0) {
41549
+ return void 0;
41550
+ }
41551
+ const drawingPath = this.resolveImagePath(dataPath, target);
41552
+ return { relId: id, path: drawingPath };
41553
+ } catch {
41554
+ return void 0;
41555
+ }
41556
+ }
41557
+ /**
41558
+ * Parse SmartArt drawing shapes given an absolute part path.
41559
+ *
41560
+ * Wraps `parseSmartArtDrawingShapes` (which expects a slide-relative
41561
+ * relationship id) with a path-based lookup so the resolution layer
41562
+ * can pull the part from anywhere in the package.
41563
+ */
41564
+ async parseSmartArtDrawingShapesFromPath(drawingPath) {
41565
+ const xmlString = await this.zip.file(drawingPath)?.async("string");
41566
+ if (!xmlString) {
41567
+ return [];
41568
+ }
41569
+ try {
41570
+ const xml = this.parser.parse(xmlString);
41571
+ const drawing = this.xmlLookupService.getChildByLocalName(xml, "drawing");
41572
+ const spTree = this.xmlLookupService.getChildByLocalName(drawing || xml, "spTree");
41573
+ if (!spTree) {
41574
+ return [];
41575
+ }
41576
+ const shapes = this.xmlLookupService.getChildrenArrayByLocalName(spTree, "sp");
41577
+ const emuPerPx = _PptxHandlerRuntime.EMU_PER_PX;
41578
+ return shapes.map((sp, index) => this.parseDrawingShape(sp, index, emuPerPx)).filter((entry) => entry !== null);
41579
+ } catch {
41580
+ return [];
41581
+ }
41582
+ }
39198
41583
  parseSmartArtConnections(dataModel) {
39199
41584
  const connectionList = this.xmlLookupService.getChildByLocalName(dataModel, "cxnLst");
39200
41585
  const rawConnections = this.xmlLookupService.getChildrenArrayByLocalName(connectionList, "cxn");
@@ -39225,7 +41610,7 @@ var PptxHandlerRuntime64 = class extends PptxHandlerRuntime63 {
39225
41610
  };
39226
41611
 
39227
41612
  // src/core/core/runtime/PptxHandlerRuntimeChartDetection.ts
39228
- var PptxHandlerRuntime65 = class extends PptxHandlerRuntime64 {
41613
+ var PptxHandlerRuntime66 = class extends PptxHandlerRuntime65 {
39229
41614
  detectChartType(plotArea) {
39230
41615
  if (!plotArea) {
39231
41616
  return "unknown";
@@ -39334,7 +41719,7 @@ var PptxHandlerRuntime65 = class extends PptxHandlerRuntime64 {
39334
41719
  };
39335
41720
 
39336
41721
  // src/core/core/runtime/PptxHandlerRuntimeChartParsingHelpers.ts
39337
- var PptxHandlerRuntime66 = class extends PptxHandlerRuntime65 {
41722
+ var PptxHandlerRuntime67 = class extends PptxHandlerRuntime66 {
39338
41723
  /**
39339
41724
  * Parse `c:plotVisOnly` from the chart root element.
39340
41725
  *
@@ -39395,7 +41780,7 @@ var PptxHandlerRuntime66 = class extends PptxHandlerRuntime65 {
39395
41780
  };
39396
41781
 
39397
41782
  // src/core/core/runtime/PptxHandlerRuntimeChartExternalData.ts
39398
- var PptxHandlerRuntime67 = class extends PptxHandlerRuntime66 {
41783
+ var PptxHandlerRuntime68 = class extends PptxHandlerRuntime67 {
39399
41784
  /**
39400
41785
  * Parse `c:externalData` from the chart's `c:chartSpace` and resolve
39401
41786
  * the external relationship target from the chart part's .rels file.
@@ -39511,7 +41896,7 @@ var PptxHandlerRuntime67 = class extends PptxHandlerRuntime66 {
39511
41896
  };
39512
41897
 
39513
41898
  // src/core/core/runtime/PptxHandlerRuntimeChartColorStyle.ts
39514
- var PptxHandlerRuntime68 = class extends PptxHandlerRuntime67 {
41899
+ var PptxHandlerRuntime69 = class extends PptxHandlerRuntime68 {
39515
41900
  /**
39516
41901
  * Parse the Office 2013+ chart color style part (`chartColorStyle*.xml`)
39517
41902
  * referenced from the chart's relationships.
@@ -39618,7 +42003,7 @@ var PptxHandlerRuntime68 = class extends PptxHandlerRuntime67 {
39618
42003
  };
39619
42004
 
39620
42005
  // src/core/core/runtime/PptxHandlerRuntimeChartParsing.ts
39621
- var PptxHandlerRuntime69 = class extends PptxHandlerRuntime68 {
42006
+ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
39622
42007
  /**
39623
42008
  * Parse chart data from a graphic frame element on a slide.
39624
42009
  *
@@ -39865,7 +42250,7 @@ var PptxHandlerRuntime69 = class extends PptxHandlerRuntime68 {
39865
42250
  };
39866
42251
 
39867
42252
  // src/core/core/runtime/PptxHandlerRuntimePresentationStructure.ts
39868
- var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
42253
+ var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
39869
42254
  parseEditorAnimations(slideXml2) {
39870
42255
  return this.editorAnimationService.parseEditorAnimations(slideXml2);
39871
42256
  }
@@ -40110,7 +42495,7 @@ var PptxHandlerRuntime70 = class extends PptxHandlerRuntime69 {
40110
42495
  };
40111
42496
 
40112
42497
  // src/core/core/runtime/PptxHandlerRuntimeEmbeddedFonts.ts
40113
- var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
42498
+ var PptxHandlerRuntime72 = class extends PptxHandlerRuntime71 {
40114
42499
  async getEmbeddedFonts() {
40115
42500
  const embeddedFontEntries = this.ensureArray(
40116
42501
  this.presentationData?.["p:presentation"]?.["p:embeddedFontLst"]?.["p:embeddedFont"]
@@ -40282,7 +42667,7 @@ var PptxHandlerRuntime71 = class extends PptxHandlerRuntime70 {
40282
42667
  };
40283
42668
 
40284
42669
  // src/core/core/runtime/PptxHandlerRuntimeLoadSession.ts
40285
- var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime71 {
42670
+ var PptxHandlerRuntime73 = class _PptxHandlerRuntime extends PptxHandlerRuntime72 {
40286
42671
  isZipContainer(data) {
40287
42672
  const bytes = new Uint8Array(data);
40288
42673
  if (bytes.byteLength < 4) {
@@ -40325,6 +42710,23 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40325
42710
  this.imageDataCache.clear();
40326
42711
  this.themeColorMap = {};
40327
42712
  this.themeFontMap = {};
42713
+ this.masterClrMaps.clear();
42714
+ this.masterThemeColorMaps.clear();
42715
+ this.masterThemeFontMaps.clear();
42716
+ this.masterThemeFormatSchemes.clear();
42717
+ this.masterThemePaths.clear();
42718
+ this.masterThemeMajorFontScripts.clear();
42719
+ this.masterThemeMinorFontScripts.clear();
42720
+ this.masterThemeNames.clear();
42721
+ this.masterThemeFontSchemeNames.clear();
42722
+ this.masterThemeColorSchemeNames.clear();
42723
+ this.originalThemeXmlByPath.clear();
42724
+ this.dirtyThemePaths.clear();
42725
+ this.masterThemeObjectDefaults.clear();
42726
+ this.masterThemeExtraClrSchemeLst.clear();
42727
+ this.masterThemeCustClrLst.clear();
42728
+ this.masterThemeExtLst.clear();
42729
+ this.currentMasterClrMap = null;
40328
42730
  this.presentationDefaultTextStyle = void 0;
40329
42731
  this.commentAuthorMap.clear();
40330
42732
  this.commentAuthorDetails.clear();
@@ -40479,6 +42881,7 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40479
42881
  setCurrentSlideClrMapOverride: (override) => {
40480
42882
  this.currentSlideClrMapOverride = override;
40481
42883
  },
42884
+ setActiveMasterForSlide: (slidePath) => this.setActiveMasterForSlide(slidePath),
40482
42885
  findLayoutPathForSlide: (slidePath) => this.findLayoutPathForSlide(slidePath),
40483
42886
  loadThemeOverride: (partBasePath) => this.loadThemeOverride(partBasePath),
40484
42887
  applyThemeOverrideState: (override) => this.applyThemeOverrideState(override),
@@ -40509,7 +42912,7 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40509
42912
  };
40510
42913
 
40511
42914
  // src/core/core/runtime/PptxHandlerRuntimeLoadPipeline.ts
40512
- var PptxHandlerRuntime73 = class extends PptxHandlerRuntime72 {
42915
+ var PptxHandlerRuntime74 = class extends PptxHandlerRuntime73 {
40513
42916
  async buildLoadData(presentationState, slidesWithWarnings) {
40514
42917
  const headerFooter = this.extractHeaderFooter();
40515
42918
  const presentationProperties = await this.parsePresentationProperties();
@@ -40521,6 +42924,7 @@ var PptxHandlerRuntime73 = class extends PptxHandlerRuntime72 {
40521
42924
  const notesMaster = await this.parseNotesMaster();
40522
42925
  const handoutMaster = await this.parseHandoutMaster();
40523
42926
  const slideMasters = await this.parseSlideMasters();
42927
+ await this.enrichSlideMastersWithTxStyles(slideMasters);
40524
42928
  const tags = await this.parseTags();
40525
42929
  const customProperties = await this.parseCustomProperties();
40526
42930
  const coreProperties = await this.parseCoreProperties();
@@ -40855,7 +43259,7 @@ var PptxHandlerRuntime73 = class extends PptxHandlerRuntime72 {
40855
43259
  };
40856
43260
 
40857
43261
  // src/core/core/runtime/PptxHandlerRuntimeImplementation.ts
40858
- var PptxHandlerRuntime74 = class _PptxHandlerRuntime extends PptxHandlerRuntime73 {
43262
+ var PptxHandlerRuntime75 = class _PptxHandlerRuntime extends PptxHandlerRuntime74 {
40859
43263
  constructor(dependencyFactory = new PptxRuntimeDependencyFactory()) {
40860
43264
  super();
40861
43265
  this.dependencyFactory = dependencyFactory;
@@ -40903,6 +43307,9 @@ var PptxHandlerRuntime74 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40903
43307
  extractGradientPathType: (gradFill) => this.colorStyleCodec.extractGradientPathType(gradFill),
40904
43308
  extractGradientFocalPoint: (gradFill) => this.colorStyleCodec.extractGradientFocalPoint(gradFill),
40905
43309
  extractGradientFillToRect: (gradFill) => this.colorStyleCodec.extractGradientFillToRect(gradFill),
43310
+ extractGradientFlip: (gradFill) => this.colorStyleCodec.extractGradientFlip(gradFill),
43311
+ extractGradientRotWithShape: (gradFill) => this.colorStyleCodec.extractGradientRotWithShape(gradFill),
43312
+ extractGradientScaled: (gradFill) => this.colorStyleCodec.extractGradientScaled(gradFill),
40906
43313
  normalizeStrokeDashType: (value) => this.normalizeStrokeDashType(value),
40907
43314
  normalizeConnectorArrowType: (value) => this.normalizeConnectorArrowType(value),
40908
43315
  ensureArray: (value) => this.ensureArray(value),
@@ -40976,7 +43383,7 @@ var PptxHandlerRuntime74 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
40976
43383
  };
40977
43384
 
40978
43385
  // src/core/core/PptxHandlerRuntime.ts
40979
- var PptxHandlerRuntime75 = class extends PptxHandlerRuntime74 {
43386
+ var PptxHandlerRuntime76 = class extends PptxHandlerRuntime75 {
40980
43387
  };
40981
43388
 
40982
43389
  // src/core/core/PptxHandlerRuntimeFactory.ts
@@ -40987,10 +43394,10 @@ var PptxHandlerRuntimeFactory = class {
40987
43394
  * @returns A freshly constructed runtime ready for loading a PPTX file.
40988
43395
  */
40989
43396
  createRuntime() {
40990
- return new PptxHandlerRuntime75();
43397
+ return new PptxHandlerRuntime76();
40991
43398
  }
40992
43399
  };
40993
- var createDefaultPptxHandlerRuntime = () => new PptxHandlerRuntime75();
43400
+ var createDefaultPptxHandlerRuntime = () => new PptxHandlerRuntime76();
40994
43401
 
40995
43402
  // src/core/PptxHandlerCore.ts
40996
43403
  var PptxHandlerCore = class {
@@ -42360,10 +44767,12 @@ function getConnectorPathGeometry(element) {
42360
44767
  const height = Math.max(element.height, 1);
42361
44768
  const normalizedType = (element.shapeType || "").toLowerCase();
42362
44769
  const point = (x, y) => `${Math.round(x)} ${Math.round(y)}`;
42363
- const startX = 0;
42364
- const startY = 0;
42365
- const endX = width;
42366
- const endY = height;
44770
+ const flipH = Boolean(element.flipHorizontal);
44771
+ const flipV = Boolean(element.flipVertical);
44772
+ const startX = flipH ? width : 0;
44773
+ const startY = flipV ? height : 0;
44774
+ const endX = flipH ? 0 : width;
44775
+ const endY = flipV ? 0 : height;
42367
44776
  if (normalizedType.includes("bentconnector5")) {
42368
44777
  const adj1 = getConnectorAdjustment(element, "adj1", 0.5);
42369
44778
  const adj2 = getConnectorAdjustment(element, "adj2", 0.5);
@@ -42376,7 +44785,7 @@ function getConnectorPathGeometry(element) {
42376
44785
  startY,
42377
44786
  endX,
42378
44787
  endY,
42379
- 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)}`
44788
+ 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)}`
42380
44789
  };
42381
44790
  }
42382
44791
  if (normalizedType.includes("bentconnector4")) {
@@ -42389,7 +44798,7 @@ function getConnectorPathGeometry(element) {
42389
44798
  startY,
42390
44799
  endX,
42391
44800
  endY,
42392
- pathData: `M ${point(0, 0)} L ${point(midX, 0)} L ${point(midX, midY)} L ${point(width, midY)} L ${point(width, height)}`
44801
+ pathData: `M ${point(startX, startY)} L ${point(midX, startY)} L ${point(midX, midY)} L ${point(endX, midY)} L ${point(endX, endY)}`
42393
44802
  };
42394
44803
  }
42395
44804
  if (normalizedType.includes("bentconnector3")) {
@@ -42400,7 +44809,7 @@ function getConnectorPathGeometry(element) {
42400
44809
  startY,
42401
44810
  endX,
42402
44811
  endY,
42403
- pathData: `M ${point(0, 0)} L ${point(midX, 0)} L ${point(midX, height)} L ${point(width, height)}`
44812
+ pathData: `M ${point(startX, startY)} L ${point(midX, startY)} L ${point(midX, endY)} L ${point(endX, endY)}`
42404
44813
  };
42405
44814
  }
42406
44815
  if (normalizedType.includes("bentconnector2")) {
@@ -42409,7 +44818,7 @@ function getConnectorPathGeometry(element) {
42409
44818
  startY,
42410
44819
  endX,
42411
44820
  endY,
42412
- pathData: `M ${point(0, 0)} L ${point(width, 0)} L ${point(width, height)}`
44821
+ pathData: `M ${point(startX, startY)} L ${point(endX, startY)} L ${point(endX, endY)}`
42413
44822
  };
42414
44823
  }
42415
44824
  if (normalizedType.includes("curvedconnector5")) {
@@ -42419,12 +44828,14 @@ function getConnectorPathGeometry(element) {
42419
44828
  const x1 = width * adj1;
42420
44829
  const yMid = height * adj2;
42421
44830
  const x2 = width * adj3;
44831
+ const yQuarter = startY + (yMid - startY) * 0.5;
44832
+ const yThreeQ = yMid + (endY - yMid) * 0.5;
42422
44833
  return {
42423
44834
  startX,
42424
44835
  startY,
42425
44836
  endX,
42426
44837
  endY,
42427
- 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)}`
44838
+ 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)}`
42428
44839
  };
42429
44840
  }
42430
44841
  if (normalizedType.includes("curvedconnector4")) {
@@ -42432,12 +44843,13 @@ function getConnectorPathGeometry(element) {
42432
44843
  const adj2 = getConnectorAdjustment(element, "adj2", 0.5);
42433
44844
  const midX = width * adj1;
42434
44845
  const midY = height * adj2;
44846
+ const yQuarter = startY + (midY - startY) * 0.5;
42435
44847
  return {
42436
44848
  startX,
42437
44849
  startY,
42438
44850
  endX,
42439
44851
  endY,
42440
- 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)}`
44852
+ 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)}`
42441
44853
  };
42442
44854
  }
42443
44855
  if (normalizedType.includes("curvedconnector3")) {
@@ -42449,7 +44861,7 @@ function getConnectorPathGeometry(element) {
42449
44861
  startY,
42450
44862
  endX,
42451
44863
  endY,
42452
- 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)}`
44864
+ 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)}`
42453
44865
  };
42454
44866
  }
42455
44867
  if (normalizedType.includes("curvedconnector2")) {
@@ -42458,7 +44870,7 @@ function getConnectorPathGeometry(element) {
42458
44870
  startY,
42459
44871
  endX,
42460
44872
  endY,
42461
- pathData: `M ${point(0, 0)} Q ${point(width, 0)} ${point(width, height)}`
44873
+ pathData: `M ${point(startX, startY)} Q ${point(endX, startY)} ${point(endX, endY)}`
42462
44874
  };
42463
44875
  }
42464
44876
  return {
@@ -42466,7 +44878,7 @@ function getConnectorPathGeometry(element) {
42466
44878
  startY,
42467
44879
  endX,
42468
44880
  endY,
42469
- pathData: `M ${point(0, 0)} L ${point(width, height)}`
44881
+ pathData: `M ${point(startX, startY)} L ${point(endX, endY)}`
42470
44882
  };
42471
44883
  }
42472
44884
 
@@ -50628,6 +53040,7 @@ var SvgExporter = class _SvgExporter {
50628
53040
  };
50629
53041
 
50630
53042
  exports.ALL_ANIMATION_PRESETS = ALL_ANIMATION_PRESETS;
53043
+ exports.BLIP_FILL_ORDER = BLIP_FILL_ORDER;
50631
53044
  exports.COLOR_MAP_ALIAS_KEYS = COLOR_MAP_ALIAS_KEYS;
50632
53045
  exports.CONNECTOR_ARROW_OPTIONS = CONNECTOR_ARROW_OPTIONS;
50633
53046
  exports.CONNECTOR_GEOMETRY_OPTIONS = CONNECTOR_GEOMETRY_OPTIONS;
@@ -50649,6 +53062,7 @@ exports.DIGITAL_SIGNATURE_ORIGIN_REL_TYPE = DIGITAL_SIGNATURE_ORIGIN_REL_TYPE;
50649
53062
  exports.DIGITAL_SIGNATURE_REL_TYPE = DIGITAL_SIGNATURE_REL_TYPE;
50650
53063
  exports.DataIntegrityError = DataIntegrityError;
50651
53064
  exports.DocumentConverter = DocumentConverter;
53065
+ exports.EFFECT_LST_ORDER = EFFECT_LST_ORDER;
50652
53066
  exports.EMPHASIS_PRESETS = EMPHASIS_PRESETS;
50653
53067
  exports.EMU_PER_INCH = EMU_PER_INCH;
50654
53068
  exports.EMU_PER_PIXEL = EMU_PER_PIXEL2;
@@ -50701,7 +53115,7 @@ exports.PptxElementTransformUpdater = PptxElementTransformUpdater;
50701
53115
  exports.PptxElementXmlBuilder = PptxElementXmlBuilder;
50702
53116
  exports.PptxGraphicFrameParser = PptxGraphicFrameParser;
50703
53117
  exports.PptxHandler = PptxHandler;
50704
- exports.PptxHandlerRuntime = PptxHandlerRuntime75;
53118
+ exports.PptxHandlerRuntime = PptxHandlerRuntime76;
50705
53119
  exports.PptxHandlerRuntimeFactory = PptxHandlerRuntimeFactory;
50706
53120
  exports.PptxLoadDataBuilder = PptxLoadDataBuilder;
50707
53121
  exports.PptxMarkdownConverter = PptxMarkdownConverter;
@@ -50736,6 +53150,7 @@ exports.PptxXmlLookupService = PptxXmlLookupService;
50736
53150
  exports.Presentation = Presentation;
50737
53151
  exports.PresentationBuilder = PresentationBuilder;
50738
53152
  exports.SHAPE_TREE_ELEMENT_TAGS = SHAPE_TREE_ELEMENT_TAGS;
53153
+ exports.SP_PR_ORDER = SP_PR_ORDER;
50739
53154
  exports.STROKE_DASH_OPTIONS = STROKE_DASH_OPTIONS;
50740
53155
  exports.SUPPORTED_XML_CANON_TRANSFORMS = SUPPORTED_XML_CANON_TRANSFORMS;
50741
53156
  exports.SWITCHABLE_LAYOUT_TYPES = SWITCHABLE_LAYOUT_TYPES;
@@ -50745,6 +53160,7 @@ exports.SlideBuilder = SlideBuilder;
50745
53160
  exports.SlideProcessor = SlideProcessor;
50746
53161
  exports.SlideSizes = SlideSizes;
50747
53162
  exports.SvgExporter = SvgExporter;
53163
+ exports.TC_PR_BORDERS_ORDER = TC_PR_BORDERS_ORDER;
50748
53164
  exports.THEME_COLOR_SCHEME_KEYS = THEME_COLOR_SCHEME_KEYS;
50749
53165
  exports.THEME_PRESETS = THEME_PRESETS;
50750
53166
  exports.TRANSITION_VALID_DIRECTIONS = TRANSITION_VALID_DIRECTIONS;
@@ -50772,6 +53188,7 @@ exports.buildGuideListExtension = buildGuideListExtension;
50772
53188
  exports.buildLinkedTextBoxChains = buildLinkedTextBoxChains;
50773
53189
  exports.buildOle2 = buildOle2;
50774
53190
  exports.buildSingleEffectNode = buildSingleEffectNode;
53191
+ exports.buildSrgbColorChoice = buildSrgbColorChoice;
50775
53192
  exports.buildThemeColorMap = buildThemeColorMap;
50776
53193
  exports.catmullRomToBezier = catmullRomToBezier;
50777
53194
  exports.chartDataAddCategory = chartDataAddCategory;
@@ -50798,6 +53215,7 @@ exports.cloneXmlObject = cloneXmlObject;
50798
53215
  exports.cm = cm;
50799
53216
  exports.cmToEmu = cmToEmu;
50800
53217
  exports.colorWithOpacity = colorWithOpacity;
53218
+ exports.colorsEqual = colorsEqual;
50801
53219
  exports.combineShapes = combineShapes;
50802
53220
  exports.computeContrastRatio = computeContrastRatio;
50803
53221
  exports.computeCycleLayout = computeCycleLayout;
@@ -50860,6 +53278,7 @@ exports.estimateTextBoxCapacity = estimateTextBoxCapacity;
50860
53278
  exports.evaluateGeometryPaths = evaluateGeometryPaths;
50861
53279
  exports.evaluateGuides = evaluateGuides;
50862
53280
  exports.extractAllTagText = extractAllTagText;
53281
+ exports.extractColorChoiceXml = extractColorChoiceXml;
50863
53282
  exports.extractFirstTagText = extractFirstTagText;
50864
53283
  exports.extractGuidFromPartName = extractGuidFromPartName;
50865
53284
  exports.extractModel3DTransform = extractModel3DTransform;
@@ -51009,6 +53428,7 @@ exports.removeChartCategory = removeChartCategory;
51009
53428
  exports.removeChartSeries = removeChartSeries;
51010
53429
  exports.removeSection = removeSection;
51011
53430
  exports.removeSmartArtNode = removeSmartArtNode;
53431
+ exports.reorderObjectKeys = reorderObjectKeys;
51012
53432
  exports.reorderSections = reorderSections;
51013
53433
  exports.reorderSmartArtNode = reorderSmartArtNode;
51014
53434
  exports.reorderSmartArtNodeToIndex = reorderSmartArtNodeToIndex;
@@ -51029,6 +53449,7 @@ exports.resolveReferenceUriToPart = resolveReferenceUriToPart;
51029
53449
  exports.resolveTableCellStyle = resolveTableCellStyle;
51030
53450
  exports.rgbToHsl = rgbToHsl;
51031
53451
  exports.selectAlternateContentBranch = selectAlternateContentBranch;
53452
+ exports.serializeColorChoice = serializeColorChoice;
51032
53453
  exports.serializeCondition = serializeCondition;
51033
53454
  exports.serializeConditionList = serializeConditionList;
51034
53455
  exports.serializeSvgPath = serializeSvgPath;