pptx-viewer-core 1.6.8 → 1.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2594,6 +2594,7 @@ var TextShapeXmlFactory = class {
2594
2594
  createXmlElement(init) {
2595
2595
  const { element } = init;
2596
2596
  const isText = element.type === "text";
2597
+ const isTextBox = element.locks?.txBox ?? isText;
2597
2598
  const name = isText ? "TextBox" : "Rectangle";
2598
2599
  const geometry = this.context.normalizePresetGeometry(element.shapeType);
2599
2600
  const adjustmentEntries = Object.entries(element.shapeAdjustments || {}).filter(
@@ -2613,7 +2614,7 @@ var TextShapeXmlFactory = class {
2613
2614
  "@_name": `${name} ${elementId}`
2614
2615
  },
2615
2616
  "p:cNvSpPr": {
2616
- "@_txBox": isText ? "1" : "0"
2617
+ "@_txBox": isTextBox ? "1" : "0"
2617
2618
  },
2618
2619
  "p:nvPr": {}
2619
2620
  },
@@ -3239,6 +3240,21 @@ function cloneXmlObject(value) {
3239
3240
 
3240
3241
  // src/core/utils/presentation-collections.ts
3241
3242
  var SECTION_EXTENSION_URI = "{521415D9-36F7-43E2-AB2F-B90AF26B5E84}";
3243
+ function remapReferenceList(references, mapping, removed) {
3244
+ const result = [];
3245
+ for (const reference of references) {
3246
+ const mapped = mapping.get(reference);
3247
+ if (mapped !== void 0) {
3248
+ result.push(mapped);
3249
+ continue;
3250
+ }
3251
+ if (removed.has(reference)) {
3252
+ continue;
3253
+ }
3254
+ result.push(reference);
3255
+ }
3256
+ return result;
3257
+ }
3242
3258
  function localName4(key) {
3243
3259
  return key.split(":").pop() ?? key;
3244
3260
  }
@@ -3305,7 +3321,7 @@ function updateCustomShow(show, existing) {
3305
3321
  replaceChildren(node, "sldLst", slideList, "p:sldLst");
3306
3322
  return node;
3307
3323
  }
3308
- function applyCustomShows(presentation, shows, lookup) {
3324
+ function applyCustomShows(presentation, shows, lookup, remap) {
3309
3325
  if (shows === void 0) {
3310
3326
  return;
3311
3327
  }
@@ -3319,14 +3335,18 @@ function applyCustomShows(presentation, shows, lookup) {
3319
3335
  const oldList = key ? presentation[key] : void 0;
3320
3336
  const list = cloneXmlObject(oldList) ?? {};
3321
3337
  const oldShows = lookup.getChildrenArrayByLocalName(oldList, "custShow");
3322
- const updated = shows.map(
3323
- (show) => updateCustomShow(
3324
- show,
3338
+ const updated = shows.map((show) => {
3339
+ const effective = remap && remap.changed ? {
3340
+ ...show,
3341
+ slideRIds: remapReferenceList(show.slideRIds, remap.rIdByOldRId, remap.removedRIds)
3342
+ } : show;
3343
+ return updateCustomShow(
3344
+ effective,
3325
3345
  oldShows.find(
3326
3346
  (node) => String(node[attributeKey(node, "id") ?? ""]) === show.id || String(node[attributeKey(node, "name") ?? ""]) === show.name
3327
3347
  )
3328
- )
3329
- );
3348
+ );
3349
+ });
3330
3350
  replaceChildren(list, "custShow", updated, "p:custShow");
3331
3351
  presentation[key ?? "p:custShowLst"] = list;
3332
3352
  }
@@ -3375,7 +3395,7 @@ function updateSection(section) {
3375
3395
  }
3376
3396
  return node;
3377
3397
  }
3378
- function applySections(presentation, sections, lookup) {
3398
+ function applySections(presentation, sections, lookup, remap) {
3379
3399
  if (sections === void 0) {
3380
3400
  return;
3381
3401
  }
@@ -3397,7 +3417,15 @@ function applySections(presentation, sections, lookup) {
3397
3417
  location = { parent: ext, key: "p14:sectionLst", list: ext["p14:sectionLst"] };
3398
3418
  }
3399
3419
  const list = cloneXmlObject(location.list) ?? {};
3400
- replaceChildren(list, "section", sections.map(updateSection), "p14:section");
3420
+ const effectiveSections = remap && remap.changed ? sections.map((section) => ({
3421
+ ...section,
3422
+ slideIds: remapReferenceList(
3423
+ section.slideIds,
3424
+ remap.sldIdByOldSldId,
3425
+ remap.removedSldIds
3426
+ )
3427
+ })) : sections;
3428
+ replaceChildren(list, "section", effectiveSections.map(updateSection), "p14:section");
3401
3429
  location.parent[location.key] = list;
3402
3430
  }
3403
3431
 
@@ -3418,8 +3446,18 @@ var PptxPresentationSaveBuilder = class {
3418
3446
  init.rawSlideHeightEmu,
3419
3447
  init.rawSlideSizeType
3420
3448
  );
3421
- applyCustomShows(presentation, init.options?.customShows, init.xmlLookupService);
3422
- applySections(presentation, init.options?.sections, init.xmlLookupService);
3449
+ applyCustomShows(
3450
+ presentation,
3451
+ init.options?.customShows,
3452
+ init.xmlLookupService,
3453
+ init.slideReferenceRemap
3454
+ );
3455
+ applySections(
3456
+ presentation,
3457
+ init.options?.sections,
3458
+ init.xmlLookupService,
3459
+ init.slideReferenceRemap
3460
+ );
3423
3461
  this.applyPhotoAlbum(presentation, init.options?.photoAlbum);
3424
3462
  presentation = this.applyKinsoku(presentation, init.options?.kinsoku);
3425
3463
  this.applyModifyVerifier(presentation, init.options?.modifyVerifier);
@@ -3514,6 +3552,53 @@ var PptxPresentationSaveBuilder = class {
3514
3552
  }
3515
3553
  };
3516
3554
 
3555
+ // src/core/core/builders/slide-reference-remap.ts
3556
+ function buildSlideReferenceRemap(init) {
3557
+ const pathToNewRId = /* @__PURE__ */ new Map();
3558
+ for (const slide of init.slides) {
3559
+ pathToNewRId.set(slide.id, slide.rId);
3560
+ }
3561
+ const newRIdToNumeric = /* @__PURE__ */ new Map();
3562
+ for (const entry of init.rebuiltSlideIds) {
3563
+ const relationshipId2 = String(entry?.["@_r:id"] ?? "");
3564
+ const numericSlideId = String(entry?.["@_id"] ?? "");
3565
+ if (relationshipId2.length > 0 && numericSlideId.length > 0) {
3566
+ newRIdToNumeric.set(relationshipId2, numericSlideId);
3567
+ }
3568
+ }
3569
+ const rIdByOldRId = /* @__PURE__ */ new Map();
3570
+ const removedRIds = /* @__PURE__ */ new Set();
3571
+ let changed = false;
3572
+ for (const [oldRId, path] of init.originalRIdToPath.entries()) {
3573
+ const newRId = pathToNewRId.get(path);
3574
+ if (newRId === void 0) {
3575
+ removedRIds.add(oldRId);
3576
+ changed = true;
3577
+ continue;
3578
+ }
3579
+ rIdByOldRId.set(oldRId, newRId);
3580
+ if (newRId !== oldRId) {
3581
+ changed = true;
3582
+ }
3583
+ }
3584
+ const sldIdByOldSldId = /* @__PURE__ */ new Map();
3585
+ const removedSldIds = /* @__PURE__ */ new Set();
3586
+ for (const [oldSldId, path] of init.originalSldIdToPath.entries()) {
3587
+ const newRId = pathToNewRId.get(path);
3588
+ const newSldId = newRId === void 0 ? void 0 : newRIdToNumeric.get(newRId);
3589
+ if (newSldId === void 0) {
3590
+ removedSldIds.add(oldSldId);
3591
+ changed = true;
3592
+ continue;
3593
+ }
3594
+ sldIdByOldSldId.set(oldSldId, newSldId);
3595
+ if (newSldId !== oldSldId) {
3596
+ changed = true;
3597
+ }
3598
+ }
3599
+ return { rIdByOldRId, sldIdByOldSldId, removedRIds, removedSldIds, changed };
3600
+ }
3601
+
3517
3602
  // src/core/core/builders/PptxPresentationSlidesReconciler.ts
3518
3603
  var PptxPresentationSlidesReconciler = class {
3519
3604
  async reconcile(input) {
@@ -3559,6 +3644,10 @@ var PptxPresentationSlidesReconciler = class {
3559
3644
  const existingSlideIds = slideIdList ? this.ensureArray(slideIdList["p:sldId"]) : [];
3560
3645
  const slideIdByRid = /* @__PURE__ */ new Map();
3561
3646
  let maxNumericSlideId = 255;
3647
+ const originalRIdToPath = /* @__PURE__ */ new Map();
3648
+ for (const [relationshipId2, target] of slideTargetByRid.entries()) {
3649
+ originalRIdToPath.set(relationshipId2, input.toSlidePathFromTarget(target));
3650
+ }
3562
3651
  for (const slideIdEntry of existingSlideIds) {
3563
3652
  const relationshipId2 = slideIdEntry?.["@_r:id"];
3564
3653
  if (typeof relationshipId2 === "string" && relationshipId2.length > 0) {
@@ -3569,6 +3658,15 @@ var PptxPresentationSlidesReconciler = class {
3569
3658
  maxNumericSlideId = Math.max(maxNumericSlideId, numericSlideId);
3570
3659
  }
3571
3660
  }
3661
+ const originalSldIdToPath = /* @__PURE__ */ new Map();
3662
+ for (const slideIdEntry of existingSlideIds) {
3663
+ const relationshipId2 = String(slideIdEntry?.["@_r:id"] ?? "");
3664
+ const numericSlideId = String(slideIdEntry?.["@_id"] ?? "");
3665
+ const slidePath = originalRIdToPath.get(relationshipId2);
3666
+ if (numericSlideId.length > 0 && slidePath !== void 0) {
3667
+ originalSldIdToPath.set(numericSlideId, slidePath);
3668
+ }
3669
+ }
3572
3670
  for (let index = 0; index < input.slides.length; index++) {
3573
3671
  const slide = input.slides[index];
3574
3672
  slide.slideNumber = index + 1;
@@ -3605,6 +3703,7 @@ var PptxPresentationSlidesReconciler = class {
3605
3703
  ];
3606
3704
  presentationRelsData["Relationships"] = relRoot;
3607
3705
  input.zip.file("ppt/_rels/presentation.xml.rels", input.xmlBuilder.build(presentationRelsData));
3706
+ const rebuiltSlideIds = [];
3608
3707
  if (presentation && slideIdList && input.presentationData) {
3609
3708
  slideIdList["p:sldId"] = input.slides.map((slide) => {
3610
3709
  const existing = slideIdByRid.get(slide.rId);
@@ -3617,11 +3716,18 @@ var PptxPresentationSlidesReconciler = class {
3617
3716
  "@_r:id": slide.rId
3618
3717
  };
3619
3718
  });
3719
+ rebuiltSlideIds.push(...slideIdList["p:sldId"]);
3620
3720
  input.presentationData["p:presentation"] = this.insertSlideIdListInOrder(
3621
3721
  presentation,
3622
3722
  slideIdList
3623
3723
  );
3624
3724
  }
3725
+ return buildSlideReferenceRemap({
3726
+ slides: input.slides,
3727
+ originalRIdToPath,
3728
+ originalSldIdToPath,
3729
+ rebuiltSlideIds
3730
+ });
3625
3731
  }
3626
3732
  /**
3627
3733
  * Return a new presentation XML object whose `p:sldIdLst` child sits in the
@@ -4283,7 +4389,7 @@ var SHAPE_STYLE_ORDER = [
4283
4389
 
4284
4390
  // src/core/core/builders/PptxSlideBackgroundBuilder.ts
4285
4391
  var PptxSlideBackgroundBuilder = class {
4286
- applyBackground(init) {
4392
+ async applyBackground(init) {
4287
4393
  const hasBackgroundColor = typeof init.slide.backgroundColor === "string" && init.slide.backgroundColor.length > 0 && init.slide.backgroundColor !== "transparent";
4288
4394
  const rawBackgroundImage = typeof init.slide.backgroundImage === "string" ? init.slide.backgroundImage : "";
4289
4395
  const hasBackgroundImage = rawBackgroundImage.length > 0;
@@ -4304,8 +4410,8 @@ var PptxSlideBackgroundBuilder = class {
4304
4410
  return;
4305
4411
  }
4306
4412
  const backgroundProperties = {};
4307
- if (hasDataUrlBackgroundImage) {
4308
- const parsedBackgroundImage = init.parseDataUrlToBytes(rawBackgroundImage);
4413
+ if (hasBackgroundImage) {
4414
+ const parsedBackgroundImage = await init.resolveImageToBytes(rawBackgroundImage);
4309
4415
  if (parsedBackgroundImage) {
4310
4416
  const backgroundImagePath = init.saveState.nextMediaPath(parsedBackgroundImage.extension);
4311
4417
  init.zip.file(backgroundImagePath, parsedBackgroundImage.bytes);
@@ -4323,8 +4429,11 @@ var PptxSlideBackgroundBuilder = class {
4323
4429
  },
4324
4430
  BLIP_FILL_ORDER
4325
4431
  );
4432
+ } else {
4433
+ init.reportUnsupportedBackground?.(rawBackgroundImage);
4326
4434
  }
4327
- } else if (hasBackgroundColor && init.slide.backgroundColor) {
4435
+ }
4436
+ if (backgroundProperties["a:blipFill"] === void 0 && hasBackgroundColor && init.slide.backgroundColor) {
4328
4437
  backgroundProperties["a:solidFill"] = {
4329
4438
  "a:srgbClr": {
4330
4439
  "@_val": init.slide.backgroundColor.replace("#", "").toUpperCase()
@@ -4341,6 +4450,11 @@ var PptxSlideBackgroundBuilder = class {
4341
4450
  backgroundProperties["@_shadeToTitle"] = "0";
4342
4451
  }
4343
4452
  if (!hasFillChild) {
4453
+ if (existingBg !== void 0) {
4454
+ this.reorderCSldBgFirst(cSld, existingBg);
4455
+ init.slideNode["p:cSld"] = cSld;
4456
+ return;
4457
+ }
4344
4458
  delete cSld["p:bg"];
4345
4459
  init.slideNode["p:cSld"] = cSld;
4346
4460
  return;
@@ -4414,6 +4528,11 @@ function parseDrawingPercent(value) {
4414
4528
  }
4415
4529
  return clampUnitInterval(parsed / 1e5);
4416
4530
  }
4531
+ function scrgbLinearToSrgb8(linear) {
4532
+ const l = Math.min(1, Math.max(0, linear));
4533
+ const companded = l <= 31308e-7 ? 12.92 * l : 1.055 * l ** (1 / 2.4) - 0.055;
4534
+ return Math.min(255, Math.max(0, Math.round(companded * 255)));
4535
+ }
4417
4536
  function toHex(value) {
4418
4537
  return Math.min(255, Math.max(0, Math.round(value))).toString(16).padStart(2, "0").toUpperCase();
4419
4538
  }
@@ -4967,11 +5086,15 @@ var PptxColorTransformCodec = class {
4967
5086
  }
4968
5087
  if (colorChoice["a:scrgbClr"]) {
4969
5088
  const scrgb = colorChoice["a:scrgbClr"];
4970
- const red = this.percentAttrToUnit(scrgb["@_r"]);
4971
- const green = this.percentAttrToUnit(scrgb["@_g"]);
4972
- const blue = this.percentAttrToUnit(scrgb["@_b"]);
5089
+ const red = parseDrawingFraction(scrgb["@_r"]);
5090
+ const green = parseDrawingFraction(scrgb["@_g"]);
5091
+ const blue = parseDrawingFraction(scrgb["@_b"]);
4973
5092
  if (red !== void 0 && green !== void 0 && blue !== void 0) {
4974
- const base = this.rgbToHex(red * 255, green * 255, blue * 255);
5093
+ const base = this.rgbToHex(
5094
+ scrgbLinearToSrgb8(red),
5095
+ scrgbLinearToSrgb8(green),
5096
+ scrgbLinearToSrgb8(blue)
5097
+ );
4975
5098
  return this.applyColorTransforms(base, scrgb);
4976
5099
  }
4977
5100
  }
@@ -5062,8 +5185,8 @@ var PptxColorTransformCodec = class {
5062
5185
  };
5063
5186
  }
5064
5187
  rgbToHex(r, g, b) {
5065
- const toHex3 = (channelValue) => this.clampColorChannel(channelValue).toString(16).padStart(2, "0").toUpperCase();
5066
- return `#${toHex3(r)}${toHex3(g)}${toHex3(b)}`;
5188
+ const toHex4 = (channelValue) => this.clampColorChannel(channelValue).toString(16).padStart(2, "0").toUpperCase();
5189
+ return `#${toHex4(r)}${toHex4(g)}${toHex4(b)}`;
5067
5190
  }
5068
5191
  applyColorTransforms(baseColor, colorNode) {
5069
5192
  return applyDrawingColorTransforms(baseColor, colorNode);
@@ -5151,6 +5274,22 @@ function mergeDrawingFillXml(original, generated, modeledChildren, childOrder2)
5151
5274
  }
5152
5275
 
5153
5276
  // src/core/core/builders/PptxGradientStyleCodec.ts
5277
+ function extractGradientTileRect(gradFill) {
5278
+ const tileRect = drawingChild(gradFill, "tileRect");
5279
+ if (!tileRect) {
5280
+ return void 0;
5281
+ }
5282
+ const toFraction = (raw) => {
5283
+ const parsed = Number.parseInt(String(raw ?? "0"), 10);
5284
+ return Number.isFinite(parsed) ? parsed / 1e5 : 0;
5285
+ };
5286
+ return {
5287
+ l: toFraction(tileRect["@_l"]),
5288
+ t: toFraction(tileRect["@_t"]),
5289
+ r: toFraction(tileRect["@_r"]),
5290
+ b: toFraction(tileRect["@_b"])
5291
+ };
5292
+ }
5154
5293
  var PptxGradientStyleCodec = class {
5155
5294
  context;
5156
5295
  constructor(context) {
@@ -5261,6 +5400,9 @@ var PptxGradientStyleCodec = class {
5261
5400
  b: Number.isFinite(b) ? this.context.clampUnitInterval(b / 1e5) : 0
5262
5401
  };
5263
5402
  }
5403
+ extractGradientTileRect(gradFill) {
5404
+ return extractGradientTileRect(gradFill);
5405
+ }
5264
5406
  extractGradientFlip(gradFill) {
5265
5407
  const flipRaw = String(gradFill["@_flip"] || "").trim().toLowerCase();
5266
5408
  if (flipRaw === "x" || flipRaw === "y" || flipRaw === "xy" || flipRaw === "none") {
@@ -5432,6 +5574,15 @@ var PptxGradientStyleCodec = class {
5432
5574
  }
5433
5575
  gradientXml["a:lin"] = linNode;
5434
5576
  }
5577
+ if (shapeStyle.fillGradientTileRect) {
5578
+ const tr = shapeStyle.fillGradientTileRect;
5579
+ gradientXml["a:tileRect"] = {
5580
+ "@_l": String(Math.round(tr.l * 1e5)),
5581
+ "@_t": String(Math.round(tr.t * 1e5)),
5582
+ "@_r": String(Math.round(tr.r * 1e5)),
5583
+ "@_b": String(Math.round(tr.b * 1e5))
5584
+ };
5585
+ }
5435
5586
  return mergeDrawingFillXml(
5436
5587
  shapeStyle.fillGradientXml,
5437
5588
  gradientXml,
@@ -6965,7 +7116,7 @@ var PptxColorStyleCodec = class {
6965
7116
  const alphaMod = this.percentAttrToUnit(
6966
7117
  choiceNode["a:alphaMod"]?.["@_val"]
6967
7118
  );
6968
- const alphaOff = this.percentAttrToUnit(
7119
+ const alphaOff = this.signedPercentToUnit(
6969
7120
  choiceNode["a:alphaOff"]?.["@_val"]
6970
7121
  );
6971
7122
  if (alpha === void 0 && alphaMod === void 0 && alphaOff === void 0) {
@@ -6980,6 +7131,18 @@ var PptxColorStyleCodec = class {
6980
7131
  }
6981
7132
  return this.clampUnitInterval(opacity2);
6982
7133
  }
7134
+ /**
7135
+ * Parse an OOXML percentage (thousandths, `100000` = 100%) into a fraction
7136
+ * WITHOUT clamping to [0, 1]. Used for additive offsets like `a:alphaOff`
7137
+ * that legitimately carry negative values.
7138
+ */
7139
+ signedPercentToUnit(value) {
7140
+ const parsed = Number.parseFloat(String(value ?? "").trim());
7141
+ if (!Number.isFinite(parsed)) {
7142
+ return void 0;
7143
+ }
7144
+ return parsed / 1e5;
7145
+ }
6983
7146
  colorWithOpacity(color2, opacity2) {
6984
7147
  if (opacity2 === void 0) {
6985
7148
  return color2;
@@ -7088,26 +7251,49 @@ function applyScene3dStyle(shapeProps, style) {
7088
7251
  const camera = scene3dNode["a:camera"];
7089
7252
  const lightRig = scene3dNode["a:lightRig"];
7090
7253
  const cameraRot = camera?.["a:rot"];
7254
+ const lightRigRot = lightRig?.["a:rot"];
7091
7255
  style.scene3d = {
7092
7256
  cameraPreset: String(camera?.["@_prst"] || "").trim() || void 0,
7093
- cameraRotX: cameraRot?.["@_lat"] !== void 0 ? parseInt(String(cameraRot["@_lat"]), 10) : void 0,
7094
- cameraRotY: cameraRot?.["@_lon"] !== void 0 ? parseInt(String(cameraRot["@_lon"]), 10) : void 0,
7095
- cameraRotZ: cameraRot?.["@_rev"] !== void 0 ? parseInt(String(cameraRot["@_rev"]), 10) : void 0,
7257
+ cameraFieldOfView: intAttr(camera?.["@_fov"]),
7258
+ cameraZoom: floatAttr(camera?.["@_zoom"]),
7259
+ cameraRotX: intAttr(cameraRot?.["@_lat"]),
7260
+ cameraRotY: intAttr(cameraRot?.["@_lon"]),
7261
+ cameraRotZ: intAttr(cameraRot?.["@_rev"]),
7096
7262
  lightRigType: String(lightRig?.["@_rig"] || "").trim() || void 0,
7097
- lightRigDirection: String(lightRig?.["@_dir"] || "").trim() || void 0
7263
+ lightRigDirection: String(lightRig?.["@_dir"] || "").trim() || void 0,
7264
+ lightRigRotX: intAttr(lightRigRot?.["@_lat"]),
7265
+ lightRigRotY: intAttr(lightRigRot?.["@_lon"]),
7266
+ lightRigRotZ: intAttr(lightRigRot?.["@_rev"])
7098
7267
  };
7099
7268
  const backdrop = scene3dNode["a:backdrop"];
7100
7269
  if (backdrop) {
7101
7270
  style.scene3d.hasBackdrop = true;
7102
7271
  const anchor = backdrop["a:anchor"];
7103
- const anchorAttrs = anchor;
7104
- if (anchorAttrs) {
7105
- style.scene3d.backdropAnchorX = parseInt(String(anchorAttrs["@_x"] || "0"), 10);
7106
- style.scene3d.backdropAnchorY = parseInt(String(anchorAttrs["@_y"] || "0"), 10);
7107
- style.scene3d.backdropAnchorZ = parseInt(String(anchorAttrs["@_z"] || "0"), 10);
7272
+ if (anchor) {
7273
+ style.scene3d.backdropAnchorX = intAttr(anchor["@_x"]) ?? 0;
7274
+ style.scene3d.backdropAnchorY = intAttr(anchor["@_y"]) ?? 0;
7275
+ style.scene3d.backdropAnchorZ = intAttr(anchor["@_z"]) ?? 0;
7276
+ }
7277
+ const norm = backdrop["a:norm"];
7278
+ if (norm) {
7279
+ style.scene3d.backdropNormalX = intAttr(norm["@_dx"]) ?? 0;
7280
+ style.scene3d.backdropNormalY = intAttr(norm["@_dy"]) ?? 0;
7281
+ style.scene3d.backdropNormalZ = intAttr(norm["@_dz"]) ?? 0;
7282
+ }
7283
+ const up = backdrop["a:up"];
7284
+ if (up) {
7285
+ style.scene3d.backdropUpX = intAttr(up["@_dx"]) ?? 0;
7286
+ style.scene3d.backdropUpY = intAttr(up["@_dy"]) ?? 0;
7287
+ style.scene3d.backdropUpZ = intAttr(up["@_dz"]) ?? 0;
7108
7288
  }
7109
7289
  }
7110
7290
  }
7291
+ function intAttr(value) {
7292
+ return value !== void 0 ? parseInt(String(value), 10) : void 0;
7293
+ }
7294
+ function floatAttr(value) {
7295
+ return value !== void 0 ? parseFloat(String(value)) : void 0;
7296
+ }
7111
7297
  function applyShape3dStyle(shapeProps, style, context) {
7112
7298
  const shape3dNode = shapeProps["a:sp3d"];
7113
7299
  if (!shape3dNode) {
@@ -7140,10 +7326,12 @@ function applyLineProperties(lineNode, shapeProps, style, context, resolveHidden
7140
7326
  }
7141
7327
  const hiddenLineFill = hiddenLineProps["a:solidFill"];
7142
7328
  if (hiddenLineFill) {
7329
+ style.strokeFillMode = "solid";
7143
7330
  style.strokeColor = context.parseColor(hiddenLineFill);
7144
7331
  style.strokeOpacity = context.extractColorOpacity(hiddenLineFill);
7145
7332
  }
7146
7333
  } else {
7334
+ style.strokeFillMode = "none";
7147
7335
  style.strokeWidth = 0;
7148
7336
  style.strokeColor = "transparent";
7149
7337
  }
@@ -7161,6 +7349,7 @@ function applyLineProperties(lineNode, shapeProps, style, context, resolveHidden
7161
7349
  }
7162
7350
  function applyStrokeColor(lineNode, style, context) {
7163
7351
  if (lineNode["a:solidFill"]) {
7352
+ style.strokeFillMode = "solid";
7164
7353
  const lineFill = lineNode["a:solidFill"];
7165
7354
  style.strokeColor = context.parseColor(lineFill);
7166
7355
  style.strokeOpacity = context.extractColorOpacity(lineFill);
@@ -7169,10 +7358,15 @@ function applyStrokeColor(lineNode, style, context) {
7169
7358
  style.strokeColorXml = strokeColorXml;
7170
7359
  }
7171
7360
  } else if (lineNode["a:gradFill"]) {
7172
- style.strokeColor = context.extractGradientFillColor(lineNode["a:gradFill"]);
7173
- style.strokeOpacity = context.extractGradientOpacity(lineNode["a:gradFill"]);
7361
+ style.strokeFillMode = "gradient";
7362
+ const lineGradFill = lineNode["a:gradFill"];
7363
+ style.strokeGradientXml = lineGradFill;
7364
+ style.strokeColor = context.extractGradientFillColor(lineGradFill);
7365
+ style.strokeOpacity = context.extractGradientOpacity(lineGradFill);
7174
7366
  } else if (lineNode["a:pattFill"]) {
7367
+ style.strokeFillMode = "pattern";
7175
7368
  const linePatternFill = lineNode["a:pattFill"];
7369
+ style.strokePatternXml = linePatternFill;
7176
7370
  style.strokeColor = context.parseColor(linePatternFill["a:fgClr"]) || context.parseColor(linePatternFill["a:bgClr"]);
7177
7371
  style.strokeOpacity = context.extractColorOpacity(linePatternFill["a:fgClr"]) || context.extractColorOpacity(linePatternFill["a:bgClr"]);
7178
7372
  }
@@ -7301,6 +7495,10 @@ var PptxShapeStyleExtractor = class {
7301
7495
  style.fillGradientPathType = this.context.extractGradientPathType(gradFill);
7302
7496
  style.fillGradientFocalPoint = this.context.extractGradientFocalPoint(gradFill);
7303
7497
  style.fillGradientFillToRect = this.context.extractGradientFillToRect(gradFill);
7498
+ const gradTileRect = extractGradientTileRect(gradFill);
7499
+ if (gradTileRect) {
7500
+ style.fillGradientTileRect = gradTileRect;
7501
+ }
7304
7502
  const gradFlip = this.context.extractGradientFlip(gradFill);
7305
7503
  if (gradFlip) {
7306
7504
  style.fillGradientFlip = gradFlip;
@@ -7989,7 +8187,7 @@ var MEDIA_REFERENCE_NAMES = [
7989
8187
  "videoFile",
7990
8188
  "quickTimeFile"
7991
8189
  ];
7992
- function parseDrawingMediaReference(container) {
8190
+ function parseDrawingMediaReference(container, externalRelIds) {
7993
8191
  if (!container) {
7994
8192
  return void 0;
7995
8193
  }
@@ -7998,11 +8196,17 @@ function parseDrawingMediaReference(container) {
7998
8196
  if (!node) {
7999
8197
  continue;
8000
8198
  }
8199
+ const linkId = String(attribute2(node, "link") ?? "").trim() || void 0;
8200
+ const embedId = String(attribute2(node, "embed") ?? "").trim() || void 0;
8001
8201
  return {
8002
8202
  kind,
8003
8203
  mediaType: kind === "videoFile" || kind === "quickTimeFile" ? "video" : "audio",
8004
- relationshipId: String(attribute2(node, "link") ?? attribute2(node, "embed") ?? "").trim() || void 0,
8005
- isLinked: attribute2(node, "link") !== void 0,
8204
+ relationshipId: linkId ?? embedId,
8205
+ // Embedded media legitimately uses r:link pointing at an INTERNAL
8206
+ // media part, so link presence alone does not imply a linked clip.
8207
+ // It is only truly linked when the referenced relationship is
8208
+ // external (TargetMode="External"), mirroring the OLE parser.
8209
+ isLinked: linkId !== void 0 && externalRelIds?.has(linkId) === true,
8006
8210
  name: kind === "wavAudioFile" ? String(attribute2(node, "name") ?? "") || void 0 : void 0,
8007
8211
  contentType: kind === "audioFile" ? String(attribute2(node, "contentType") ?? "") || void 0 : void 0,
8008
8212
  audioCdStart: kind === "audioCd" ? parseAudioCdPosition(child2(node, "st")) : void 0,
@@ -8133,7 +8337,10 @@ var PptxMediaDataParser = class {
8133
8337
  parseMediaData(graphicData, slidePath) {
8134
8338
  const result = {};
8135
8339
  try {
8136
- const reference = parseDrawingMediaReference(graphicData);
8340
+ const reference = parseDrawingMediaReference(
8341
+ graphicData,
8342
+ this.context.externalRelsMap.get(slidePath)
8343
+ );
8137
8344
  if (reference) {
8138
8345
  result.mediaType = reference.mediaType;
8139
8346
  result.mediaReferenceKind = reference.kind;
@@ -8744,6 +8951,7 @@ var PptxLoadDataBuilder = class {
8744
8951
  layoutOptions = [];
8745
8952
  headerFooter;
8746
8953
  presentationProperties;
8954
+ viewProperties;
8747
8955
  customShows;
8748
8956
  sections;
8749
8957
  warnings = [];
@@ -8803,6 +9011,10 @@ var PptxLoadDataBuilder = class {
8803
9011
  this.presentationProperties = presentationProperties;
8804
9012
  return this;
8805
9013
  }
9014
+ withViewProperties(viewProperties) {
9015
+ this.viewProperties = viewProperties;
9016
+ return this;
9017
+ }
8806
9018
  withCustomShows(customShows) {
8807
9019
  this.customShows = customShows;
8808
9020
  return this;
@@ -8940,6 +9152,7 @@ var PptxLoadDataBuilder = class {
8940
9152
  layoutOptions: this.layoutOptions,
8941
9153
  headerFooter: this.headerFooter,
8942
9154
  presentationProperties: this.presentationProperties,
9155
+ viewProperties: this.viewProperties,
8943
9156
  customShows: this.customShows,
8944
9157
  sections: this.sections,
8945
9158
  warnings: this.warnings,
@@ -9322,7 +9535,7 @@ var PptxSlideCommentsXmlFactory = class {
9322
9535
  const createdAtIso = this.resolveCreatedAt(comment.createdAt);
9323
9536
  const x = init.saveState.toEmu(comment.x, 0);
9324
9537
  const y = init.saveState.toEmu(comment.y, 0);
9325
- return {
9538
+ const node = {
9326
9539
  ...withoutChildrenByLocalName(comment.rawXml ?? {}, /* @__PURE__ */ new Set(["pos", "text"])),
9327
9540
  "@_authorId": authorId,
9328
9541
  "@_dt": createdAtIso,
@@ -9333,6 +9546,28 @@ var PptxSlideCommentsXmlFactory = class {
9333
9546
  },
9334
9547
  "p:text": String(comment.text || "")
9335
9548
  };
9549
+ this.applyResolvedState(node, comment);
9550
+ return node;
9551
+ }
9552
+ /**
9553
+ * Reflect the (possibly edited) `resolved` flag onto the legacy comment
9554
+ * node. PowerPoint's legacy comment schema has no standard resolved marker,
9555
+ * but the parser reads a non-standard `@_done` / `@_resolved` attribute, so
9556
+ * we re-emit the current state rather than leaving the stale value carried
9557
+ * over from `rawXml`. The original attribute name is preserved when present.
9558
+ */
9559
+ applyResolvedState(node, comment) {
9560
+ const raw = comment.rawXml;
9561
+ const hadResolvedAttr = raw?.["@_resolved"] !== void 0;
9562
+ const hadDoneAttr = raw?.["@_done"] !== void 0;
9563
+ const key = hadResolvedAttr && !hadDoneAttr ? "@_resolved" : "@_done";
9564
+ delete node["@_done"];
9565
+ delete node["@_resolved"];
9566
+ if (comment.resolved === true) {
9567
+ node[key] = "1";
9568
+ } else if (hadResolvedAttr || hadDoneAttr) {
9569
+ node[key] = "0";
9570
+ }
9336
9571
  }
9337
9572
  resolveCreatedAt(createdAt) {
9338
9573
  const candidate = String(createdAt || "").trim();
@@ -10645,6 +10880,226 @@ var PptxCompatibilityService = class {
10645
10880
  }
10646
10881
  };
10647
10882
 
10883
+ // src/core/utils/xml-access.ts
10884
+ var ATTR_PREFIX = "@_";
10885
+ var TEXT_KEY = "#text";
10886
+ function isXmlObject(value) {
10887
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10888
+ }
10889
+ function coerceString(value) {
10890
+ if (typeof value === "string") {
10891
+ return value;
10892
+ }
10893
+ if (typeof value === "number" || typeof value === "boolean") {
10894
+ return String(value);
10895
+ }
10896
+ return void 0;
10897
+ }
10898
+ function xmlChild(node, key) {
10899
+ if (!isXmlObject(node)) {
10900
+ return void 0;
10901
+ }
10902
+ const value = node[key];
10903
+ if (Array.isArray(value)) {
10904
+ const first = value[0];
10905
+ return isXmlObject(first) ? first : void 0;
10906
+ }
10907
+ return isXmlObject(value) ? value : void 0;
10908
+ }
10909
+ function xmlChildren(node, key) {
10910
+ if (!isXmlObject(node)) {
10911
+ return [];
10912
+ }
10913
+ const value = node[key];
10914
+ if (value === void 0 || value === null) {
10915
+ return [];
10916
+ }
10917
+ if (Array.isArray(value)) {
10918
+ return value.filter(isXmlObject);
10919
+ }
10920
+ return isXmlObject(value) ? [value] : [];
10921
+ }
10922
+ function xmlHasChild(node, key) {
10923
+ return isXmlObject(node) && Object.hasOwn(node, key);
10924
+ }
10925
+ function xmlAttr(node, name) {
10926
+ if (!isXmlObject(node)) {
10927
+ return void 0;
10928
+ }
10929
+ return coerceString(node[ATTR_PREFIX + name]);
10930
+ }
10931
+ function xmlAttrNumber(node, name) {
10932
+ const raw = xmlAttr(node, name);
10933
+ if (raw === void 0) {
10934
+ return void 0;
10935
+ }
10936
+ const parsed = Number(raw);
10937
+ return Number.isFinite(parsed) ? parsed : void 0;
10938
+ }
10939
+ function xmlAttrBool(node, name) {
10940
+ const raw = xmlAttr(node, name);
10941
+ if (raw === void 0) {
10942
+ return void 0;
10943
+ }
10944
+ const normalized = raw.trim().toLowerCase();
10945
+ if (normalized === "1" || normalized === "true") {
10946
+ return true;
10947
+ }
10948
+ if (normalized === "0" || normalized === "false") {
10949
+ return false;
10950
+ }
10951
+ return void 0;
10952
+ }
10953
+ function xmlText(node) {
10954
+ if (typeof node === "string") {
10955
+ return node;
10956
+ }
10957
+ if (!isXmlObject(node)) {
10958
+ return void 0;
10959
+ }
10960
+ return coerceString(node[TEXT_KEY]);
10961
+ }
10962
+ function xmlPath(node, ...keys) {
10963
+ let current = isXmlObject(node) ? node : void 0;
10964
+ for (const key of keys) {
10965
+ if (!current) {
10966
+ return void 0;
10967
+ }
10968
+ current = xmlChild(current, key);
10969
+ }
10970
+ return current;
10971
+ }
10972
+ function isXmlNode(value) {
10973
+ return isXmlObject(value);
10974
+ }
10975
+
10976
+ // src/core/utils/app-properties-titles.ts
10977
+ var SLIDE_TITLES_NAME = "Slide Titles";
10978
+ function coerceText(value) {
10979
+ if (typeof value === "string") {
10980
+ return value;
10981
+ }
10982
+ if (typeof value === "number" || typeof value === "boolean") {
10983
+ return String(value);
10984
+ }
10985
+ if (isXmlNode(value)) {
10986
+ const text2 = value["#text"];
10987
+ return text2 === void 0 || text2 === null ? "" : String(text2);
10988
+ }
10989
+ return "";
10990
+ }
10991
+ function coerceCount(value) {
10992
+ const parsed = Number.parseInt(coerceText(value), 10);
10993
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
10994
+ }
10995
+ function readLpstrList(vector) {
10996
+ if (!vector) {
10997
+ return [];
10998
+ }
10999
+ const raw = vector["vt:lpstr"];
11000
+ if (raw === void 0 || raw === null) {
11001
+ return [];
11002
+ }
11003
+ return (Array.isArray(raw) ? raw : [raw]).map(coerceText);
11004
+ }
11005
+ function isSlideTitlesCategory(name) {
11006
+ const normalized = name.trim().toLowerCase();
11007
+ return normalized === "slide titles" || normalized.includes("slide") && normalized.includes("title");
11008
+ }
11009
+ function readCategories(headingPairs, titlesOfParts) {
11010
+ const variants = xmlChildren(xmlChild(headingPairs, "vt:vector"), "vt:variant");
11011
+ const entries = readLpstrList(xmlChild(titlesOfParts, "vt:vector"));
11012
+ const categories = [];
11013
+ let offset = 0;
11014
+ for (let i = 0; i + 1 < variants.length; i += 2) {
11015
+ const name = coerceText(variants[i]["vt:lpstr"]);
11016
+ const count = coerceCount(variants[i + 1]["vt:i4"]);
11017
+ categories.push({ name, entries: entries.slice(offset, offset + count) });
11018
+ offset += count;
11019
+ }
11020
+ return categories;
11021
+ }
11022
+ function writeHeadingPairs(appProps, categories) {
11023
+ const variants = [];
11024
+ for (const category of categories) {
11025
+ variants.push({ "vt:lpstr": category.name });
11026
+ variants.push({ "vt:i4": String(category.entries.length) });
11027
+ }
11028
+ appProps["HeadingPairs"] = {
11029
+ "vt:vector": {
11030
+ "@_size": String(variants.length),
11031
+ "@_baseType": "variant",
11032
+ "vt:variant": variants
11033
+ }
11034
+ };
11035
+ }
11036
+ function writeTitlesOfParts(appProps, categories) {
11037
+ const allEntries = categories.flatMap((category) => category.entries);
11038
+ const lpstr = allEntries.map((entry) => ({ "#text": entry }));
11039
+ appProps["TitlesOfParts"] = {
11040
+ "vt:vector": {
11041
+ "@_size": String(allEntries.length),
11042
+ "@_baseType": "lpstr",
11043
+ "vt:lpstr": lpstr
11044
+ }
11045
+ };
11046
+ }
11047
+ function applySlideTitlesToAppProps(appProps, titles) {
11048
+ const headingPairs = xmlChild(appProps, "HeadingPairs");
11049
+ if (!headingPairs) {
11050
+ return;
11051
+ }
11052
+ const titlesOfParts = xmlChild(appProps, "TitlesOfParts");
11053
+ const categories = readCategories(headingPairs, titlesOfParts);
11054
+ const slideCategory = categories.find((category) => isSlideTitlesCategory(category.name));
11055
+ if (slideCategory) {
11056
+ slideCategory.entries = titles;
11057
+ } else {
11058
+ categories.push({ name: SLIDE_TITLES_NAME, entries: titles });
11059
+ }
11060
+ writeHeadingPairs(appProps, categories);
11061
+ writeTitlesOfParts(appProps, categories);
11062
+ }
11063
+
11064
+ // src/core/utils/slide-title.ts
11065
+ var TITLE_PLACEHOLDER_TYPES = /* @__PURE__ */ new Set(["title", "ctrtitle"]);
11066
+ function getElementPlaceholderType(element) {
11067
+ const explicit = element.placeholderType;
11068
+ if (typeof explicit === "string" && explicit.trim().length > 0) {
11069
+ return explicit.trim().toLowerCase();
11070
+ }
11071
+ const ph = xmlPath(element.rawXml, "p:nvSpPr", "p:nvPr", "p:ph");
11072
+ const type = xmlAttr(ph, "type");
11073
+ return type ? type.trim().toLowerCase() : void 0;
11074
+ }
11075
+ function getElementPlainText(element) {
11076
+ const maybe = element;
11077
+ if (typeof maybe.text === "string" && maybe.text.trim().length > 0) {
11078
+ return maybe.text.trim();
11079
+ }
11080
+ if (Array.isArray(maybe.textSegments)) {
11081
+ const joined = maybe.textSegments.map((segment) => typeof segment?.text === "string" ? segment.text : "").join("");
11082
+ return joined.trim();
11083
+ }
11084
+ return "";
11085
+ }
11086
+ function deriveSlideTitle(slide) {
11087
+ const elements2 = slide.elements ?? [];
11088
+ for (const element of elements2) {
11089
+ const phType = getElementPlaceholderType(element);
11090
+ if (phType && TITLE_PLACEHOLDER_TYPES.has(phType)) {
11091
+ const text2 = getElementPlainText(element);
11092
+ if (text2) {
11093
+ return text2;
11094
+ }
11095
+ }
11096
+ }
11097
+ return "";
11098
+ }
11099
+ function deriveSlideTitles(slides) {
11100
+ return slides.map((slide) => deriveSlideTitle(slide));
11101
+ }
11102
+
10648
11103
  // src/core/services/PptxDocumentPropertiesUpdater.ts
10649
11104
  var PptxDocumentPropertiesUpdater = class {
10650
11105
  context;
@@ -10708,6 +11163,7 @@ var PptxDocumentPropertiesUpdater = class {
10708
11163
  appProps["Slides"] = String(slides.length);
10709
11164
  appProps["HiddenSlides"] = String(hiddenSlidesCount);
10710
11165
  appProps["Notes"] = String(notesCount);
11166
+ this.updateSlideTitleProperties(appProps, slides);
10711
11167
  appData["Properties"] = appProps;
10712
11168
  this.context.zip.file("docProps/app.xml", this.context.builder.build(appData));
10713
11169
  } catch (error) {
@@ -10750,6 +11206,15 @@ var PptxDocumentPropertiesUpdater = class {
10750
11206
  }
10751
11207
  }
10752
11208
  }
11209
+ /**
11210
+ * Recompute `TitlesOfParts` / `HeadingPairs` from the current slide set so
11211
+ * the per-slide title list in `app.xml` stays consistent after slides are
11212
+ * added, removed, or retitled. Delegates the vector rebuild to a pure
11213
+ * helper; here we only derive the ordered titles.
11214
+ */
11215
+ updateSlideTitleProperties(appProps, slides) {
11216
+ applySlideTitlesToAppProps(appProps, deriveSlideTitles(slides));
11217
+ }
10753
11218
  applyAppPropertiesOverrides(appProps, overrides10) {
10754
11219
  if (!overrides10) {
10755
11220
  return;
@@ -12578,6 +13043,16 @@ function extractChildKeyframes(childTnList) {
12578
13043
  }
12579
13044
  return void 0;
12580
13045
  }
13046
+ function parseTimingPercentFraction(raw) {
13047
+ if (raw === void 0 || raw === null) {
13048
+ return void 0;
13049
+ }
13050
+ const parsed = Number.parseInt(String(raw), 10);
13051
+ if (!Number.isFinite(parsed) || parsed <= 0) {
13052
+ return void 0;
13053
+ }
13054
+ return Math.min(1, parsed / 1e5);
13055
+ }
12581
13056
  function extractRepeatInfo(cTn) {
12582
13057
  let repeatCount;
12583
13058
  let autoReverse;
@@ -12721,11 +13196,11 @@ function ensureArray4(value) {
12721
13196
  return [];
12722
13197
  }
12723
13198
  if (!Array.isArray(value)) {
12724
- return isXmlObject(value) ? [value] : [];
13199
+ return isXmlObject2(value) ? [value] : [];
12725
13200
  }
12726
- return value.filter((entry) => isXmlObject(entry));
13201
+ return value.filter((entry) => isXmlObject2(entry));
12727
13202
  }
12728
- function isXmlObject(value) {
13203
+ function isXmlObject2(value) {
12729
13204
  return typeof value === "object" && value !== null && !Array.isArray(value);
12730
13205
  }
12731
13206
  var VALID_CONDITION_EVENTS = /* @__PURE__ */ new Set([
@@ -13090,8 +13565,11 @@ var PptxNativeAnimationService = class {
13090
13565
  const nodeType = String(cTn["@_nodeType"] || "");
13091
13566
  const presetClass = cTn["@_presetClass"];
13092
13567
  const presetId = cTn["@_presetID"] ? Number.parseInt(String(cTn["@_presetID"]), 10) : void 0;
13568
+ const presetSubtype = cTn["@_presetSubtype"] !== void 0 ? Number.parseInt(String(cTn["@_presetSubtype"]), 10) : void 0;
13093
13569
  const durationMs = cTn["@_dur"] ? Number.parseInt(String(cTn["@_dur"]), 10) : void 0;
13094
13570
  const delayMs = cTn["@_delay"] ? Number.parseInt(String(cTn["@_delay"]), 10) : void 0;
13571
+ const accel = parseTimingPercentFraction(cTn["@_accel"]);
13572
+ const decel = parseTimingPercentFraction(cTn["@_decel"]);
13095
13573
  let trigger = currentTrigger;
13096
13574
  if (nodeType === "afterPrevious" || nodeType === "afterPrev") {
13097
13575
  trigger = "afterPrevious";
@@ -13141,8 +13619,11 @@ var PptxNativeAnimationService = class {
13141
13619
  trigger,
13142
13620
  presetClass: validPresetClass,
13143
13621
  presetId,
13622
+ presetSubtype,
13144
13623
  durationMs,
13145
13624
  delayMs,
13625
+ accel,
13626
+ decel,
13146
13627
  triggerDelayMs: trigger === "afterDelay" ? delayMs : void 0,
13147
13628
  motionPath: childMotion.motionPath,
13148
13629
  motionOrigin: childMotion.motionOrigin,
@@ -13451,6 +13932,74 @@ function buildP14ExtLst(transitionType, direction, orient, pattern, rawExtLst, x
13451
13932
  return { "p:ext": transitionExt };
13452
13933
  }
13453
13934
 
13935
+ // src/core/services/p15-transition-parser.ts
13936
+ var P15_TRANSITION_PRESETS = /* @__PURE__ */ new Set([
13937
+ "fallOver",
13938
+ "drape",
13939
+ "curtains",
13940
+ "wind",
13941
+ "prestige",
13942
+ "fracture",
13943
+ "crush",
13944
+ "peelOff",
13945
+ "pageCurlDouble",
13946
+ "pageCurlSingle",
13947
+ "airplane",
13948
+ "origami"
13949
+ ]);
13950
+ var PRSTTRANS_EXT_URI = "{D42A27DB-BD31-4B8C-83A1-F6EECF244321}";
13951
+ function optionalBoolean(value) {
13952
+ const valueToken = value === void 0 || value === null ? "" : String(value).trim().toLowerCase();
13953
+ if (valueToken === "1" || valueToken === "true") {
13954
+ return true;
13955
+ }
13956
+ if (valueToken === "0" || valueToken === "false") {
13957
+ return false;
13958
+ }
13959
+ return void 0;
13960
+ }
13961
+ function parseP15FromExtLst(extLstNode, xmlLookupService, getXmlLocalName) {
13962
+ const extEntries = xmlLookupService.getChildrenArrayByLocalName(extLstNode, "ext");
13963
+ for (const ext of extEntries) {
13964
+ if (!ext) {
13965
+ continue;
13966
+ }
13967
+ for (const [key, value] of Object.entries(ext)) {
13968
+ if (key.startsWith("@_")) {
13969
+ continue;
13970
+ }
13971
+ if (getXmlLocalName(key) !== "prstTrans") {
13972
+ continue;
13973
+ }
13974
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
13975
+ continue;
13976
+ }
13977
+ const detail = value;
13978
+ const prst = String(detail["@_prst"] || "").trim();
13979
+ if (!P15_TRANSITION_PRESETS.has(prst)) {
13980
+ continue;
13981
+ }
13982
+ return {
13983
+ type: prst,
13984
+ invX: optionalBoolean(detail["@_invX"]),
13985
+ invY: optionalBoolean(detail["@_invY"])
13986
+ };
13987
+ }
13988
+ }
13989
+ return void 0;
13990
+ }
13991
+ function buildP15ExtLst(transitionType, invX, invY) {
13992
+ const prstTrans = {
13993
+ "@_xmlns:p15": "http://schemas.microsoft.com/office/powerpoint/2012/main",
13994
+ "@_prst": transitionType
13995
+ };
13996
+ const ext = {
13997
+ "@_uri": PRSTTRANS_EXT_URI,
13998
+ "p15:prstTrans": prstTrans
13999
+ };
14000
+ return { "p:ext": ext };
14001
+ }
14002
+
13454
14003
  // src/core/services/slide-transition-xml.ts
13455
14004
  var STANDARD_TRANSITION_TYPES = /* @__PURE__ */ new Set([
13456
14005
  "fade",
@@ -13516,7 +14065,7 @@ function parseTransitionDetails(node, localName22) {
13516
14065
  if (pattern) {
13517
14066
  result.pattern = pattern;
13518
14067
  }
13519
- const thruBlk = optionalBoolean(detail["@_thruBlk"]);
14068
+ const thruBlk = optionalBoolean2(detail["@_thruBlk"]);
13520
14069
  if (thruBlk !== void 0) {
13521
14070
  result.thruBlk = thruBlk;
13522
14071
  }
@@ -13527,7 +14076,7 @@ function parseTransitionAttributes(node) {
13527
14076
  const speedToken = token(node["@_spd"]);
13528
14077
  const speed = SPEEDS.has(speedToken) ? speedToken : void 0;
13529
14078
  const durationMs = unsignedInteger2(node["@_dur"] ?? node["@_p14:dur"], 1);
13530
- const advanceOnClick = optionalBoolean(node["@_advClick"]);
14079
+ const advanceOnClick = optionalBoolean2(node["@_advClick"]);
13531
14080
  const advanceAfterMs = unsignedInteger2(node["@_advTm"]);
13532
14081
  return { speed, durationMs, advanceOnClick, advanceAfterMs };
13533
14082
  }
@@ -13541,7 +14090,7 @@ function parseTransitionSound(raw, lookup, localName22) {
13541
14090
  return {
13542
14091
  soundRId: sound ? attributeByLocalName(sound, "embed", localName22) : void 0,
13543
14092
  soundName: sound ? attributeByLocalName(sound, "name", localName22) : void 0,
13544
- soundLoop: optionalBoolean(start["@_loop"])
14093
+ soundLoop: optionalBoolean2(start["@_loop"])
13545
14094
  };
13546
14095
  }
13547
14096
  const stopSound = Object.keys(raw).some(
@@ -13650,7 +14199,7 @@ function attributeByLocalName(node, name, localName22) {
13650
14199
  function token(value) {
13651
14200
  return value === void 0 || value === null ? "" : String(value).trim();
13652
14201
  }
13653
- function optionalBoolean(value) {
14202
+ function optionalBoolean2(value) {
13654
14203
  const valueToken = token(value).toLowerCase();
13655
14204
  if (!valueToken) {
13656
14205
  return void 0;
@@ -13696,6 +14245,7 @@ var PptxSlideTransitionService = class {
13696
14245
  const { spokes, thruBlk, rawSoundAction, rawExtLst } = details;
13697
14246
  if (rawExtLst && transitionType === "cut") {
13698
14247
  const p14Result = parseP14FromExtLst(rawExtLst, this.xmlLookupService, this.getXmlLocalName);
14248
+ const p15Result = p14Result ? void 0 : parseP15FromExtLst(rawExtLst, this.xmlLookupService, this.getXmlLocalName);
13699
14249
  if (p14Result) {
13700
14250
  transitionType = p14Result.type;
13701
14251
  if (p14Result.direction) {
@@ -13707,6 +14257,8 @@ var PptxSlideTransitionService = class {
13707
14257
  if (p14Result.pattern) {
13708
14258
  pattern = p14Result.pattern;
13709
14259
  }
14260
+ } else if (p15Result) {
14261
+ transitionType = p15Result.type;
13710
14262
  } else if (this.parseMorphFromExtLst(rawExtLst)) {
13711
14263
  transitionType = "morph";
13712
14264
  }
@@ -13788,6 +14340,7 @@ var PptxSlideTransitionService = class {
13788
14340
  }
13789
14341
  const transitionType = transition.type || "cut";
13790
14342
  const isP14Type = P14_TRANSITION_TYPES.has(transitionType);
14343
+ const isP15Type = P15_TRANSITION_PRESETS.has(transitionType);
13791
14344
  const isMorphType = transitionType === "morph";
13792
14345
  const node = createPreservedTransitionNode(transition.rawTransition, this.getXmlLocalName);
13793
14346
  if (isP14Type) {
@@ -13800,6 +14353,8 @@ var PptxSlideTransitionService = class {
13800
14353
  this.xmlLookupService,
13801
14354
  this.getXmlLocalName
13802
14355
  );
14356
+ } else if (isP15Type) {
14357
+ node["p:extLst"] = transition.rawExtLst ?? buildP15ExtLst(transitionType);
13803
14358
  } else if (isMorphType) {
13804
14359
  node["p:extLst"] = this.buildMorphExtLst(transition.rawExtLst);
13805
14360
  } else {
@@ -13810,7 +14365,7 @@ var PptxSlideTransitionService = class {
13810
14365
  if (soundAction) {
13811
14366
  node["p:sndAc"] = soundAction;
13812
14367
  }
13813
- if (transition.rawExtLst && !isP14Type && !isMorphType) {
14368
+ if (transition.rawExtLst && !isP14Type && !isP15Type && !isMorphType) {
13814
14369
  node["p:extLst"] = transition.rawExtLst;
13815
14370
  }
13816
14371
  return node;
@@ -14309,7 +14864,7 @@ function updateEffectNodeAttributes(cTn, anim, currentPresetClass) {
14309
14864
  if (stCondList && anim.delayMs !== void 0) {
14310
14865
  const conditions = ensureArray4(stCondList["p:cond"]);
14311
14866
  for (const cond of conditions) {
14312
- if (isXmlObject(cond)) {
14867
+ if (isXmlObject2(cond)) {
14313
14868
  cond["@_delay"] = String(anim.delayMs);
14314
14869
  }
14315
14870
  }
@@ -24400,7 +24955,7 @@ function getCalloutViewBoxBounds(width, height, geometry, padding = 2) {
24400
24955
  }
24401
24956
 
24402
24957
  // src/core/core/runtime/omml-sibling-order.ts
24403
- function isXmlObject2(value) {
24958
+ function isXmlObject3(value) {
24404
24959
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
24405
24960
  }
24406
24961
  function ensureItems(value) {
@@ -24503,7 +25058,7 @@ function collectParsedOmathNodes(root) {
24503
25058
  }
24504
25059
  if (localName9(key) === "oMath") {
24505
25060
  for (const item of ensureItems(value)) {
24506
- if (isXmlObject2(item)) {
25061
+ if (isXmlObject3(item)) {
24507
25062
  result.push(item);
24508
25063
  }
24509
25064
  }
@@ -24566,7 +25121,7 @@ function reorderContainer(node, rawInner) {
24566
25121
  occurrence.set(child20.tag, index + 1);
24567
25122
  const value = ensureItems(node[child20.tag])[index];
24568
25123
  resolved.push({ tag: child20.tag, value });
24569
- if (isXmlObject2(value) && child20.inner) {
25124
+ if (isXmlObject3(value) && child20.inner) {
24570
25125
  reorderContainer(value, child20.inner);
24571
25126
  }
24572
25127
  }
@@ -24610,7 +25165,7 @@ function localName10(name) {
24610
25165
  const colon = name.indexOf(":");
24611
25166
  return colon >= 0 ? name.slice(colon + 1) : name;
24612
25167
  }
24613
- function isXmlObject3(value) {
25168
+ function isXmlObject4(value) {
24614
25169
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
24615
25170
  }
24616
25171
  function collectParsedParagraphs(root) {
@@ -24635,7 +25190,7 @@ function collectParsedParagraphs(root) {
24635
25190
  continue;
24636
25191
  }
24637
25192
  paragraphs.push(
24638
- ...(Array.isArray(childValue) ? childValue : [childValue]).filter(isXmlObject3)
25193
+ ...(Array.isArray(childValue) ? childValue : [childValue]).filter(isXmlObject4)
24639
25194
  );
24640
25195
  }
24641
25196
  } else {
@@ -24682,7 +25237,7 @@ function directChildrenByLocalName(paragraphs, name) {
24682
25237
  return [];
24683
25238
  }
24684
25239
  const values = Array.isArray(value) ? value : [value];
24685
- return values.filter(isXmlObject3);
25240
+ return values.filter(isXmlObject4);
24686
25241
  })
24687
25242
  );
24688
25243
  }
@@ -26097,99 +26652,6 @@ function detectFontFormat(data) {
26097
26652
  return "truetype";
26098
26653
  }
26099
26654
 
26100
- // src/core/utils/xml-access.ts
26101
- var ATTR_PREFIX = "@_";
26102
- var TEXT_KEY = "#text";
26103
- function isXmlObject4(value) {
26104
- return typeof value === "object" && value !== null && !Array.isArray(value);
26105
- }
26106
- function coerceString(value) {
26107
- if (typeof value === "string") {
26108
- return value;
26109
- }
26110
- if (typeof value === "number" || typeof value === "boolean") {
26111
- return String(value);
26112
- }
26113
- return void 0;
26114
- }
26115
- function xmlChild(node, key) {
26116
- if (!isXmlObject4(node)) {
26117
- return void 0;
26118
- }
26119
- const value = node[key];
26120
- if (Array.isArray(value)) {
26121
- const first = value[0];
26122
- return isXmlObject4(first) ? first : void 0;
26123
- }
26124
- return isXmlObject4(value) ? value : void 0;
26125
- }
26126
- function xmlChildren(node, key) {
26127
- if (!isXmlObject4(node)) {
26128
- return [];
26129
- }
26130
- const value = node[key];
26131
- if (value === void 0 || value === null) {
26132
- return [];
26133
- }
26134
- if (Array.isArray(value)) {
26135
- return value.filter(isXmlObject4);
26136
- }
26137
- return isXmlObject4(value) ? [value] : [];
26138
- }
26139
- function xmlHasChild(node, key) {
26140
- return isXmlObject4(node) && Object.hasOwn(node, key);
26141
- }
26142
- function xmlAttr(node, name) {
26143
- if (!isXmlObject4(node)) {
26144
- return void 0;
26145
- }
26146
- return coerceString(node[ATTR_PREFIX + name]);
26147
- }
26148
- function xmlAttrNumber(node, name) {
26149
- const raw = xmlAttr(node, name);
26150
- if (raw === void 0) {
26151
- return void 0;
26152
- }
26153
- const parsed = Number(raw);
26154
- return Number.isFinite(parsed) ? parsed : void 0;
26155
- }
26156
- function xmlAttrBool(node, name) {
26157
- const raw = xmlAttr(node, name);
26158
- if (raw === void 0) {
26159
- return void 0;
26160
- }
26161
- const normalized = raw.trim().toLowerCase();
26162
- if (normalized === "1" || normalized === "true") {
26163
- return true;
26164
- }
26165
- if (normalized === "0" || normalized === "false") {
26166
- return false;
26167
- }
26168
- return void 0;
26169
- }
26170
- function xmlText(node) {
26171
- if (typeof node === "string") {
26172
- return node;
26173
- }
26174
- if (!isXmlObject4(node)) {
26175
- return void 0;
26176
- }
26177
- return coerceString(node[TEXT_KEY]);
26178
- }
26179
- function xmlPath(node, ...keys) {
26180
- let current = isXmlObject4(node) ? node : void 0;
26181
- for (const key of keys) {
26182
- if (!current) {
26183
- return void 0;
26184
- }
26185
- current = xmlChild(current, key);
26186
- }
26187
- return current;
26188
- }
26189
- function isXmlNode(value) {
26190
- return isXmlObject4(value);
26191
- }
26192
-
26193
26655
  // src/core/utils/presentation-section-parser.ts
26194
26656
  function findSectionList2(presentation, lookup) {
26195
26657
  const direct = lookup.getChildByLocalName(presentation, "sectionLst");
@@ -29525,6 +29987,7 @@ function getSvgStrokeDasharray(dashType, strokeWidth, customDashSegments) {
29525
29987
  // src/core/utils/element-xml-builders.ts
29526
29988
  function createTemplateShapeRawXml(element) {
29527
29989
  const isText = element.type === "text";
29990
+ const isTextBox = element.locks?.txBox ?? isText;
29528
29991
  const name = isText ? "TextBox" : "Rectangle";
29529
29992
  const geometry = element.shapeType === "cylinder" ? "can" : element.shapeType || "rect";
29530
29993
  const adjustmentEntries = Object.entries(element.shapeAdjustments || {}).filter(
@@ -29543,7 +30006,7 @@ function createTemplateShapeRawXml(element) {
29543
30006
  "@_name": `${name} ${Math.floor(Math.random() * 100)}`
29544
30007
  },
29545
30008
  "p:cNvSpPr": {
29546
- "@_txBox": isText ? "1" : "0"
30009
+ "@_txBox": isTextBox ? "1" : "0"
29547
30010
  },
29548
30011
  "p:nvPr": {}
29549
30012
  },
@@ -29820,36 +30283,200 @@ async function fetchUrlToBytes(url, options = {}) {
29820
30283
  }
29821
30284
  }
29822
30285
 
30286
+ // src/core/utils/inkml-trace-decode.ts
30287
+ function resolveChannelOrder(root) {
30288
+ const traceFormat = findFirstByLocalName(root, "traceFormat");
30289
+ if (!traceFormat) {
30290
+ return ["X", "Y"];
30291
+ }
30292
+ const channels = ensureArray5(nsGet(traceFormat, "channel"));
30293
+ const names = channels.map(
30294
+ (channel) => String(nsAttr(channel, "name") ?? "").trim().toUpperCase()
30295
+ ).filter((name) => name.length > 0);
30296
+ return names.length > 0 ? names : ["X", "Y"];
30297
+ }
30298
+ function decodeTracePoints(text2, channelOrder) {
30299
+ const points3 = [];
30300
+ const modes = channelOrder.map(() => "explicit");
30301
+ const lastValue = channelOrder.map(() => 0);
30302
+ const lastVelocity = channelOrder.map(() => 0);
30303
+ for (const rawPoint of text2.split(",")) {
30304
+ const tokens = rawPoint.trim().split(/\s+/u).filter((token2) => token2.length > 0);
30305
+ if (tokens.length === 0) {
30306
+ continue;
30307
+ }
30308
+ const decoded = [];
30309
+ for (let i = 0; i < tokens.length && i < channelOrder.length; i++) {
30310
+ const parsed = parseValueToken(tokens[i], modes[i]);
30311
+ if (parsed === void 0) {
30312
+ decoded.push(lastValue[i]);
30313
+ continue;
30314
+ }
30315
+ modes[i] = parsed.mode;
30316
+ const value = applyDiffMode(parsed, i, lastValue, lastVelocity);
30317
+ decoded.push(value);
30318
+ }
30319
+ if (decoded.length >= 2) {
30320
+ points3.push(decoded);
30321
+ }
30322
+ }
30323
+ return points3;
30324
+ }
30325
+ function parseValueToken(token2, currentMode) {
30326
+ let mode = currentMode;
30327
+ let body = token2;
30328
+ const prefix = token2[0];
30329
+ if (prefix === "!") {
30330
+ mode = "explicit";
30331
+ body = token2.slice(1);
30332
+ } else if (prefix === "'") {
30333
+ mode = "single";
30334
+ body = token2.slice(1);
30335
+ } else if (prefix === '"') {
30336
+ mode = "double";
30337
+ body = token2.slice(1);
30338
+ }
30339
+ if (body.length === 0) {
30340
+ return void 0;
30341
+ }
30342
+ const value = Number(body);
30343
+ return Number.isFinite(value) ? { value, mode } : void 0;
30344
+ }
30345
+ function applyDiffMode(parsed, index, lastValue, lastVelocity) {
30346
+ if (parsed.mode === "single") {
30347
+ lastVelocity[index] = parsed.value;
30348
+ lastValue[index] += parsed.value;
30349
+ } else if (parsed.mode === "double") {
30350
+ lastVelocity[index] += parsed.value;
30351
+ lastValue[index] += lastVelocity[index];
30352
+ } else {
30353
+ lastValue[index] = parsed.value;
30354
+ lastVelocity[index] = 0;
30355
+ }
30356
+ return lastValue[index];
30357
+ }
30358
+ function pointsToSvgPath(points3, channelOrder) {
30359
+ const xi = channelOrder.indexOf("X");
30360
+ const yi = channelOrder.indexOf("Y");
30361
+ const xIndex = xi >= 0 ? xi : 0;
30362
+ const yIndex = yi >= 0 ? yi : 1;
30363
+ const segments = [];
30364
+ for (const point of points3) {
30365
+ const x = point[xIndex];
30366
+ const y = point[yIndex];
30367
+ if (!Number.isFinite(x) || !Number.isFinite(y)) {
30368
+ continue;
30369
+ }
30370
+ segments.push(`${segments.length === 0 ? "M" : "L"} ${x} ${y}`);
30371
+ }
30372
+ return segments.join(" ");
30373
+ }
30374
+ function pointsToPressures(points3, channelOrder) {
30375
+ const fIndex = channelOrder.indexOf("F");
30376
+ if (fIndex < 0) {
30377
+ return [];
30378
+ }
30379
+ const pressures = [];
30380
+ for (const point of points3) {
30381
+ const raw = point[fIndex];
30382
+ if (Number.isFinite(raw)) {
30383
+ const normalised = raw > 1 ? raw / 32767 : raw;
30384
+ pressures.push(Math.max(0, Math.min(1, normalised)));
30385
+ }
30386
+ }
30387
+ return pressures;
30388
+ }
30389
+ function nsGet(obj, localName22) {
30390
+ if (localName22 in obj) {
30391
+ return obj[localName22];
30392
+ }
30393
+ for (const key of Object.keys(obj)) {
30394
+ if (localNameOf(key) === localName22 && !key.startsWith("@_")) {
30395
+ return obj[key];
30396
+ }
30397
+ }
30398
+ return void 0;
30399
+ }
30400
+ function nsAttr(obj, localName22) {
30401
+ const direct = obj[`@_${localName22}`];
30402
+ if (direct !== void 0) {
30403
+ return direct;
30404
+ }
30405
+ for (const key of Object.keys(obj)) {
30406
+ if (key.startsWith("@_") && localNameOf(key.slice(2)) === localName22) {
30407
+ return obj[key];
30408
+ }
30409
+ }
30410
+ return void 0;
30411
+ }
30412
+ function localNameOf(key) {
30413
+ const colon = key.indexOf(":");
30414
+ return colon >= 0 ? key.slice(colon + 1) : key;
30415
+ }
30416
+ function findFirstByLocalName(node, localName22) {
30417
+ const direct = nsGet(node, localName22);
30418
+ if (direct && typeof direct === "object") {
30419
+ return Array.isArray(direct) ? direct[0] : direct;
30420
+ }
30421
+ for (const key of Object.keys(node)) {
30422
+ if (key.startsWith("@_") || key === "#text") {
30423
+ continue;
30424
+ }
30425
+ for (const child20 of ensureArray5(node[key])) {
30426
+ if (typeof child20 !== "object") {
30427
+ continue;
30428
+ }
30429
+ const found = findFirstByLocalName(child20, localName22);
30430
+ if (found) {
30431
+ return found;
30432
+ }
30433
+ }
30434
+ }
30435
+ return void 0;
30436
+ }
30437
+ function ensureArray5(value) {
30438
+ if (value === void 0 || value === null) {
30439
+ return [];
30440
+ }
30441
+ return Array.isArray(value) ? value : [value];
30442
+ }
30443
+
29823
30444
  // src/core/utils/inkml-content-part.ts
29824
30445
  var INKML_NAMESPACE = "http://www.w3.org/2003/InkML";
29825
30446
  var METADATA_NAMESPACE = "https://pptx-viewer.dev/inkml/metadata";
29826
30447
  function parseInkMlContent(data) {
29827
- const root = data["ink:ink"] ?? data["ink"];
30448
+ const root = nsGet(data, "ink") ?? data["ink"];
29828
30449
  if (!root) {
29829
30450
  return { strokes: [], rawXml: data };
29830
30451
  }
29831
30452
  const brushes = /* @__PURE__ */ new Map();
29832
- for (const brush of ensureArray5(root["ink:brush"] ?? root["brush"])) {
29833
- const properties = ensureArray5(brush["ink:brushProperty"] ?? brush["brushProperty"]);
30453
+ for (const brush of ensureArray5(nsGet(root, "brush"))) {
30454
+ const properties = ensureArray5(nsGet(brush, "brushProperty"));
29834
30455
  const valueByName = new Map(
29835
- properties.map((property) => [String(property["@_name"] ?? ""), property["@_value"]])
30456
+ properties.map((property) => [
30457
+ String(nsAttr(property, "name") ?? ""),
30458
+ nsAttr(property, "value")
30459
+ ])
29836
30460
  );
29837
- brushes.set(String(brush["@_id"] ?? ""), {
30461
+ brushes.set(String(nsAttr(brush, "id") ?? ""), {
29838
30462
  color: String(valueByName.get("color") ?? "#000000"),
29839
30463
  width: finiteNumber(valueByName.get("width"), 1),
29840
30464
  opacity: finiteNumber(valueByName.get("opacity"), 1)
29841
30465
  });
29842
30466
  }
30467
+ const channelOrder = resolveChannelOrder(root);
29843
30468
  const strokes = [];
29844
- for (const trace of ensureArray5(root["ink:trace"] ?? root["trace"])) {
30469
+ for (const trace of ensureArray5(nsGet(root, "trace"))) {
29845
30470
  const text2 = typeof trace === "string" ? trace : String(trace["#text"] ?? "").trim();
29846
- const path = typeof trace === "string" ? text2 : String(trace["@_pva:path"] ?? "").trim() || text2;
30471
+ const authored = typeof trace === "string" ? "" : String(nsAttr(trace, "path") ?? "").trim();
30472
+ const points3 = authored ? [] : decodeTracePoints(text2, channelOrder);
30473
+ const path = authored || pointsToSvgPath(points3, channelOrder);
29847
30474
  if (!path) {
29848
30475
  continue;
29849
30476
  }
29850
- const brushRef = typeof trace === "string" ? "" : String(trace["@_brushRef"] ?? "").replace("#", "");
30477
+ const brushRef = typeof trace === "string" ? "" : String(nsAttr(trace, "brushRef") ?? "").replace("#", "");
29851
30478
  const brush = brushes.get(brushRef) ?? { color: "#000000", width: 1, opacity: 1 };
29852
- const pressures = tracePressures(text2);
30479
+ const pressures = authored ? tracePressures(text2) : pointsToPressures(points3, channelOrder);
29853
30480
  strokes.push({ ...brush, path, ...pressures.length > 0 ? { pressures } : {} });
29854
30481
  }
29855
30482
  return { strokes, rawXml: data };
@@ -29908,12 +30535,6 @@ function finiteNumber(value, fallback) {
29908
30535
  const parsed = Number(value);
29909
30536
  return Number.isFinite(parsed) ? parsed : fallback;
29910
30537
  }
29911
- function ensureArray5(value) {
29912
- if (value === void 0 || value === null) {
29913
- return [];
29914
- }
29915
- return Array.isArray(value) ? value : [value];
29916
- }
29917
30538
 
29918
30539
  // src/core/utils/smartart-helpers.ts
29919
30540
  var DEFAULT_ACCENT_COLORS = [
@@ -32576,6 +33197,122 @@ function applyNodeStylesToElements(elements2, nodes) {
32576
33197
  });
32577
33198
  }
32578
33199
 
33200
+ // src/core/utils/smartart-pres-layout-vars.ts
33201
+ var CONTAINER_LOCAL_NAMES = /* @__PURE__ */ new Set(["presLayoutVars", "varLst"]);
33202
+ function localNameOf2(key) {
33203
+ const idx = key.indexOf(":");
33204
+ return idx >= 0 ? key.slice(idx + 1) : key;
33205
+ }
33206
+ function findVarsContainer(node) {
33207
+ if (!node || typeof node !== "object") {
33208
+ return void 0;
33209
+ }
33210
+ if (Array.isArray(node)) {
33211
+ for (const entry of node) {
33212
+ const found = findVarsContainer(entry);
33213
+ if (found) {
33214
+ return found;
33215
+ }
33216
+ }
33217
+ return void 0;
33218
+ }
33219
+ for (const [key, value] of Object.entries(node)) {
33220
+ if (key.startsWith("@_")) {
33221
+ continue;
33222
+ }
33223
+ if (CONTAINER_LOCAL_NAMES.has(localNameOf2(key))) {
33224
+ const container = Array.isArray(value) ? value[0] : value;
33225
+ if (container && typeof container === "object") {
33226
+ return container;
33227
+ }
33228
+ }
33229
+ const nested = findVarsContainer(value);
33230
+ if (nested) {
33231
+ return nested;
33232
+ }
33233
+ }
33234
+ return void 0;
33235
+ }
33236
+ function varValue(container, name) {
33237
+ for (const [key, value] of Object.entries(container)) {
33238
+ if (key.startsWith("@_") || localNameOf2(key) !== name) {
33239
+ continue;
33240
+ }
33241
+ const node = Array.isArray(value) ? value[0] : value;
33242
+ if (node && typeof node === "object") {
33243
+ const raw = node["@_val"];
33244
+ const str = String(raw ?? "").trim();
33245
+ return str.length > 0 ? str : void 0;
33246
+ }
33247
+ }
33248
+ return void 0;
33249
+ }
33250
+ function boolValue2(container, name) {
33251
+ const raw = varValue(container, name);
33252
+ if (raw === void 0) {
33253
+ return void 0;
33254
+ }
33255
+ const lower = raw.toLowerCase();
33256
+ return lower === "1" || lower === "true" || lower === "on";
33257
+ }
33258
+ function intValue(container, name) {
33259
+ const raw = varValue(container, name);
33260
+ if (raw === void 0) {
33261
+ return void 0;
33262
+ }
33263
+ const parsed = Number.parseInt(raw, 10);
33264
+ return Number.isFinite(parsed) ? parsed : void 0;
33265
+ }
33266
+ var DIRECTIONS = /* @__PURE__ */ new Set(["norm", "rev"]);
33267
+ var HIER_BRANCHES = /* @__PURE__ */ new Set(["std", "init", "l", "r", "hang"]);
33268
+ function parseSmartArtPresLayoutVars(container) {
33269
+ if (!container) {
33270
+ return void 0;
33271
+ }
33272
+ const vars = findVarsContainer(container);
33273
+ if (!vars) {
33274
+ return void 0;
33275
+ }
33276
+ const result = {};
33277
+ const direction = varValue(vars, "dir");
33278
+ if (direction && DIRECTIONS.has(direction)) {
33279
+ result.direction = direction;
33280
+ }
33281
+ const hierBranch = varValue(vars, "hierBranch");
33282
+ if (hierBranch && HIER_BRANCHES.has(hierBranch)) {
33283
+ result.hierarchyBranch = hierBranch;
33284
+ }
33285
+ const orgChart = boolValue2(vars, "orgChart");
33286
+ if (orgChart !== void 0) {
33287
+ result.orgChart = orgChart;
33288
+ }
33289
+ const chMax = intValue(vars, "chMax");
33290
+ if (chMax !== void 0) {
33291
+ result.childMax = chMax;
33292
+ }
33293
+ const chPref = intValue(vars, "chPref");
33294
+ if (chPref !== void 0) {
33295
+ result.childPreferred = chPref;
33296
+ }
33297
+ const bulletEnabled = boolValue2(vars, "bulletEnabled");
33298
+ if (bulletEnabled !== void 0) {
33299
+ result.bulletEnabled = bulletEnabled;
33300
+ }
33301
+ const animLvl = varValue(vars, "animLvl");
33302
+ if (animLvl !== void 0) {
33303
+ result.animationLevel = animLvl;
33304
+ }
33305
+ const animOne = varValue(vars, "animOne");
33306
+ if (animOne !== void 0) {
33307
+ result.animateOne = animOne;
33308
+ }
33309
+ const resizeHandles = varValue(vars, "resizeHandles");
33310
+ if (resizeHandles !== void 0) {
33311
+ result.resizeHandles = resizeHandles;
33312
+ }
33313
+ return Object.keys(result).length > 0 ? result : void 0;
33314
+ }
33315
+
32579
33316
  // src/core/utils/smartart-decompose.ts
32580
33317
  function quickStyleStrokeScale(quickStyle) {
32581
33318
  if (!quickStyle?.effectIntensity) {
@@ -32681,15 +33418,27 @@ function decomposeSmartArt(smartArtData, containerBounds, themeColorMap, layoutD
32681
33418
  smartArtData.colorTransform?.fillColors
32682
33419
  );
32683
33420
  const layoutType = resolveEffectiveLayoutType(smartArtData);
33421
+ const layoutVars = smartArtData.presLayoutVars ?? parseSmartArtPresLayoutVars(smartArtData.layoutDefinition?.rawXml);
33422
+ const orderedNodes = layoutVars?.direction === "rev" ? [...nodes].reverse() : nodes;
32684
33423
  const namedLayout = smartArtData.layout;
32685
33424
  if (namedLayout) {
32686
- const namedResult = dispatchNamedLayout(namedLayout, nodes, containerBounds, effectiveThemeMap);
33425
+ const namedResult = dispatchNamedLayout(
33426
+ namedLayout,
33427
+ orderedNodes,
33428
+ containerBounds,
33429
+ effectiveThemeMap
33430
+ );
32687
33431
  if (namedResult) {
32688
- return applyNodeStylesToElements(namedResult, nodes);
33432
+ return applyNodeStylesToElements(namedResult, orderedNodes);
32689
33433
  }
32690
33434
  }
32691
- const algorithmic = dispatchLayoutByType(layoutType, nodes, containerBounds, effectiveThemeMap);
32692
- return algorithmic ? applyNodeStylesToElements(algorithmic, nodes) : algorithmic;
33435
+ const algorithmic = dispatchLayoutByType(
33436
+ layoutType,
33437
+ orderedNodes,
33438
+ containerBounds,
33439
+ effectiveThemeMap
33440
+ );
33441
+ return algorithmic ? applyNodeStylesToElements(algorithmic, orderedNodes) : algorithmic;
32693
33442
  }
32694
33443
  function dispatchLayoutByType(layoutType, nodes, containerBounds, effectiveThemeMap) {
32695
33444
  switch (layoutType) {
@@ -42468,6 +43217,128 @@ function applySmartArtConnectionAttributes(xml, connection, fallbackModelId) {
42468
43217
  applyNullableAttribute(xml, "@_presId", connection.presentationId);
42469
43218
  }
42470
43219
 
43220
+ // src/core/utils/smartart-color-lists.ts
43221
+ var COLOR_LOCAL_NAMES = /* @__PURE__ */ new Set([
43222
+ "srgbClr",
43223
+ "schemeClr",
43224
+ "scrgbClr",
43225
+ "sysClr",
43226
+ "prstClr",
43227
+ "hslClr"
43228
+ ]);
43229
+ var COLOR_METHODS2 = /* @__PURE__ */ new Set(["span", "cycle", "repeat"]);
43230
+ var HUE_DIRECTIONS2 = /* @__PURE__ */ new Set(["cw", "ccw"]);
43231
+ var PRIMARY_LABEL_PRIORITY = ["node0", "node1", "node2", "node3", "node4", "node"];
43232
+ function localNameOf3(key) {
43233
+ const idx = key.indexOf(":");
43234
+ return idx >= 0 ? key.slice(idx + 1) : key;
43235
+ }
43236
+ function parseSmartArtColorListHexes(list, deps) {
43237
+ if (!list) {
43238
+ return [];
43239
+ }
43240
+ const out = [];
43241
+ for (const [key, value] of Object.entries(list)) {
43242
+ if (key.startsWith("@_")) {
43243
+ continue;
43244
+ }
43245
+ const local = localNameOf3(key);
43246
+ if (!COLOR_LOCAL_NAMES.has(local)) {
43247
+ continue;
43248
+ }
43249
+ const nodes = Array.isArray(value) ? value : [value];
43250
+ for (const node of nodes) {
43251
+ if (!node || typeof node !== "object") {
43252
+ continue;
43253
+ }
43254
+ const wrapper = { [`a:${local}`]: node };
43255
+ const hex10 = deps.parseColorChoice(wrapper) ?? deps.resolveScheme(node);
43256
+ if (hex10) {
43257
+ out.push(hex10);
43258
+ }
43259
+ }
43260
+ }
43261
+ return out;
43262
+ }
43263
+ function listInterpolation(list) {
43264
+ if (!list) {
43265
+ return void 0;
43266
+ }
43267
+ const method = String(list["@_meth"] ?? "").trim();
43268
+ const hueDir = String(list["@_hueDir"] ?? "").trim();
43269
+ const meta = {};
43270
+ if (COLOR_METHODS2.has(method)) {
43271
+ meta.method = method;
43272
+ }
43273
+ if (HUE_DIRECTIONS2.has(hueDir)) {
43274
+ meta.hueDirection = hueDir;
43275
+ }
43276
+ return meta.method || meta.hueDirection ? meta : void 0;
43277
+ }
43278
+ function parseLabel(lbl, deps) {
43279
+ const fillList = deps.getChild(lbl, "fillClrLst");
43280
+ const lineList = deps.getChild(lbl, "linClrLst");
43281
+ return {
43282
+ name: String(lbl["@_name"] ?? "").trim(),
43283
+ fill: parseSmartArtColorListHexes(fillList, deps),
43284
+ line: parseSmartArtColorListHexes(lineList, deps),
43285
+ textFill: parseSmartArtColorListHexes(deps.getChild(lbl, "txFillClrLst"), deps),
43286
+ textLine: parseSmartArtColorListHexes(deps.getChild(lbl, "txLinClrLst"), deps),
43287
+ effect: parseSmartArtColorListHexes(deps.getChild(lbl, "effectClrLst"), deps),
43288
+ textEffect: parseSmartArtColorListHexes(deps.getChild(lbl, "txEffectClrLst"), deps),
43289
+ fillInterpolation: listInterpolation(fillList),
43290
+ lineInterpolation: listInterpolation(lineList)
43291
+ };
43292
+ }
43293
+ function selectPrimary(parsed) {
43294
+ const byName = new Map(parsed.map((p) => [p.name, p]));
43295
+ for (const name of PRIMARY_LABEL_PRIORITY) {
43296
+ const candidate = byName.get(name);
43297
+ if (candidate && candidate.fill.length > 0) {
43298
+ return candidate;
43299
+ }
43300
+ }
43301
+ for (const name of PRIMARY_LABEL_PRIORITY) {
43302
+ const candidate = byName.get(name);
43303
+ if (candidate && (candidate.line.length > 0 || candidate.fill.length > 0)) {
43304
+ return candidate;
43305
+ }
43306
+ }
43307
+ return parsed.find((p) => p.fill.length > 0) ?? parsed.find((p) => p.line.length > 0);
43308
+ }
43309
+ function buildSmartArtColorLists(styleLbls, deps) {
43310
+ const parsed = styleLbls.map((lbl) => parseLabel(lbl, deps));
43311
+ const primary = selectPrimary(parsed);
43312
+ let fillColors = primary?.fill ?? [];
43313
+ let lineColors = primary?.line ?? [];
43314
+ if (fillColors.length === 0) {
43315
+ fillColors = parsed.map((p) => p.fill[0]).filter((c) => Boolean(c));
43316
+ }
43317
+ if (lineColors.length === 0) {
43318
+ lineColors = parsed.map((p) => p.line[0]).filter((c) => Boolean(c));
43319
+ }
43320
+ const result = { fillColors, lineColors };
43321
+ if (primary?.textFill.length) {
43322
+ result.textFillColors = primary.textFill;
43323
+ }
43324
+ if (primary?.textLine.length) {
43325
+ result.textLineColors = primary.textLine;
43326
+ }
43327
+ if (primary?.effect.length) {
43328
+ result.effectColors = primary.effect;
43329
+ }
43330
+ if (primary?.textEffect.length) {
43331
+ result.textEffectColors = primary.textEffect;
43332
+ }
43333
+ if (primary?.fillInterpolation) {
43334
+ result.fillInterpolation = primary.fillInterpolation;
43335
+ }
43336
+ if (primary?.lineInterpolation) {
43337
+ result.lineInterpolation = primary.lineInterpolation;
43338
+ }
43339
+ return result;
43340
+ }
43341
+
42471
43342
  // src/core/utils/modern-comment-constants.ts
42472
43343
  var MODERN_COMMENT_NAMESPACE = "http://schemas.microsoft.com/office/powerpoint/2018/8/main";
42473
43344
  var MODERN_COMMENT_RELATIONSHIP = "http://schemas.microsoft.com/office/2018/10/relationships/comments";
@@ -44774,6 +45645,28 @@ function buildGeneratedChartAxis(axId, crossId, pos2, formatting) {
44774
45645
  return axis;
44775
45646
  }
44776
45647
 
45648
+ // src/core/utils/chart-xml-container-map.ts
45649
+ var CONTAINER_MAP = {
45650
+ pie: { tag: "c:pieChart", family: "pie" },
45651
+ pie3D: { tag: "c:pie3DChart", family: "pie" },
45652
+ ofPie: { tag: "c:ofPieChart", family: "ofPie" },
45653
+ doughnut: { tag: "c:doughnutChart", family: "doughnut" },
45654
+ scatter: { tag: "c:scatterChart", family: "scatter" },
45655
+ bubble: { tag: "c:bubbleChart", family: "bubble" },
45656
+ line: { tag: "c:lineChart", family: "line" },
45657
+ line3D: { tag: "c:line3DChart", family: "line" },
45658
+ area: { tag: "c:areaChart", family: "area" },
45659
+ area3D: { tag: "c:area3DChart", family: "area" },
45660
+ radar: { tag: "c:radarChart", family: "radar" },
45661
+ stock: { tag: "c:stockChart", family: "stock" },
45662
+ surface: { tag: "c:surfaceChart", family: "surface" },
45663
+ bar: { tag: "c:barChart", family: "bar" },
45664
+ bar3D: { tag: "c:bar3DChart", family: "bar" }
45665
+ };
45666
+ function resolveChartContainerType(type) {
45667
+ return CONTAINER_MAP[type] ?? { tag: "c:barChart", family: "bar" };
45668
+ }
45669
+
44777
45670
  // src/core/utils/chart-xml-generator.ts
44778
45671
  var NS_C = "http://schemas.openxmlformats.org/drawingml/2006/chart";
44779
45672
  var NS_A2 = "http://schemas.openxmlformats.org/drawingml/2006/main";
@@ -44804,29 +45697,6 @@ function strLit(values) {
44804
45697
  }
44805
45698
  };
44806
45699
  }
44807
- function resolveType(type) {
44808
- switch (type) {
44809
- case "pie":
44810
- case "pie3D":
44811
- return { tag: "c:pieChart", family: "pie" };
44812
- case "doughnut":
44813
- return { tag: "c:doughnutChart", family: "doughnut" };
44814
- case "scatter":
44815
- return { tag: "c:scatterChart", family: "scatter" };
44816
- case "bubble":
44817
- return { tag: "c:bubbleChart", family: "bubble" };
44818
- case "line":
44819
- case "line3D":
44820
- return { tag: "c:lineChart", family: "line" };
44821
- case "area":
44822
- case "area3D":
44823
- return { tag: "c:areaChart", family: "area" };
44824
- case "radar":
44825
- return { tag: "c:radarChart", family: "radar" };
44826
- default:
44827
- return { tag: "c:barChart", family: "bar" };
44828
- }
44829
- }
44830
45700
  function fillSpPr(color2, asLine) {
44831
45701
  const h = hex6(color2);
44832
45702
  if (!h) {
@@ -44894,7 +45764,10 @@ function buildChartTypeContainer(chartData, family) {
44894
45764
  } else if (family === "scatter") {
44895
45765
  container["c:scatterStyle"] = { "@_val": "lineMarker" };
44896
45766
  container["c:varyColors"] = { "@_val": "0" };
44897
- } else {
45767
+ } else if (family === "ofPie") {
45768
+ container["c:ofPieType"] = { "@_val": "pie" };
45769
+ container["c:varyColors"] = { "@_val": "1" };
45770
+ } else if (family === "stock" || family === "surface") ; else {
44898
45771
  container["c:varyColors"] = { "@_val": family === "bubble" ? "0" : "1" };
44899
45772
  }
44900
45773
  container["c:ser"] = chartData.series.map(
@@ -44906,12 +45779,13 @@ function buildChartTypeContainer(chartData, family) {
44906
45779
  if (family === "line" && chartData.upDownBars !== void 0) {
44907
45780
  applyChartUpDownBars(container, chartData.upDownBars, (key) => key.replace(/^.*:/u, ""));
44908
45781
  }
44909
- if (family === "bar") {
45782
+ if (family === "bar" || family === "ofPie") {
44910
45783
  container["c:gapWidth"] = { "@_val": "150" };
44911
- container["c:axId"] = [{ "@_val": String(CAT_AX_ID) }, { "@_val": String(VAL_AX_ID) }];
44912
- } else if (family === "line" || family === "area" || family === "radar") {
44913
- container["c:axId"] = [{ "@_val": String(CAT_AX_ID) }, { "@_val": String(VAL_AX_ID) }];
44914
- } else if (family === "scatter" || family === "bubble") {
45784
+ }
45785
+ if (family === "stock") {
45786
+ container["c:hiLowLines"] = {};
45787
+ }
45788
+ if (family === "bar" || family === "line" || family === "area" || family === "radar" || family === "scatter" || family === "bubble" || family === "stock" || family === "surface") {
44915
45789
  container["c:axId"] = [{ "@_val": String(CAT_AX_ID) }, { "@_val": String(VAL_AX_ID) }];
44916
45790
  } else if (family === "doughnut") {
44917
45791
  container["c:holeSize"] = { "@_val": "50" };
@@ -44924,7 +45798,8 @@ function buildPlotArea(chartData, tag, family) {
44924
45798
  if (chartData.style) {
44925
45799
  applyChartDataLabelsToXml(plotArea, chartData.style, (key) => key.replace(/^.*:/u, ""));
44926
45800
  }
44927
- if (family !== "pie" && family !== "doughnut" && SCATTER_LIKE.has(chartData.chartType)) {
45801
+ const hasAxes = family !== "pie" && family !== "doughnut" && family !== "ofPie";
45802
+ if (hasAxes && SCATTER_LIKE.has(chartData.chartType)) {
44928
45803
  plotArea["c:valAx"] = [
44929
45804
  buildGeneratedChartAxis(
44930
45805
  CAT_AX_ID,
@@ -44939,7 +45814,7 @@ function buildPlotArea(chartData, tag, family) {
44939
45814
  axisFormatting(chartData, "valAx", VAL_AX_ID, 1)
44940
45815
  )
44941
45816
  ];
44942
- } else if (family !== "pie" && family !== "doughnut") {
45817
+ } else if (hasAxes) {
44943
45818
  const dateAxis = chartData.dateCategories ? axisFormatting(chartData, "dateAx", CAT_AX_ID) : void 0;
44944
45819
  plotArea[dateAxis ? "c:dateAx" : "c:catAx"] = buildGeneratedChartAxis(
44945
45820
  CAT_AX_ID,
@@ -44958,7 +45833,7 @@ function buildPlotArea(chartData, tag, family) {
44958
45833
  return plotArea;
44959
45834
  }
44960
45835
  function buildChartSpaceXml(chartData) {
44961
- const { tag, family } = resolveType(chartData.chartType);
45836
+ const { tag, family } = resolveChartContainerType(chartData.chartType);
44962
45837
  const chart = {};
44963
45838
  if (chartData.title) {
44964
45839
  chart["c:title"] = {
@@ -46890,6 +47765,7 @@ function parseMediaExtensionData(mediaNode, cMediaNode, shapeId, ensureArray16)
46890
47765
  let playbackSpeed;
46891
47766
  let trimStartMs;
46892
47767
  let trimEndMs;
47768
+ let embedRId;
46893
47769
  const bookmarks = [];
46894
47770
  const extLst = mediaNode["p:extLst"] ?? cMediaNode["p:extLst"];
46895
47771
  if (extLst) {
@@ -46897,6 +47773,13 @@ function parseMediaExtensionData(mediaNode, cMediaNode, shapeId, ensureArray16)
46897
47773
  for (const ext of exts) {
46898
47774
  const p14Media = ext["p14:media"];
46899
47775
  if (p14Media) {
47776
+ if (embedRId === void 0) {
47777
+ const embedRaw = p14Media["@_r:embed"] ?? p14Media["@_embed"];
47778
+ const embedStr = embedRaw === void 0 ? "" : String(embedRaw).trim();
47779
+ if (embedStr.length > 0) {
47780
+ embedRId = embedStr;
47781
+ }
47782
+ }
46900
47783
  const p14Trim = p14Media["p14:trim"];
46901
47784
  if (p14Trim) {
46902
47785
  const st = p14Trim["@_st"];
@@ -46966,7 +47849,8 @@ function parseMediaExtensionData(mediaNode, cMediaNode, shapeId, ensureArray16)
46966
47849
  fadeInDuration,
46967
47850
  fadeOutDuration,
46968
47851
  playbackSpeed,
46969
- bookmarks
47852
+ bookmarks,
47853
+ embedRId
46970
47854
  };
46971
47855
  }
46972
47856
 
@@ -47196,6 +48080,12 @@ var PptxHandlerRuntime = class {
47196
48080
  loadedEmbeddedFonts = [];
47197
48081
  /** Typed source metadata for lossless embedded-font list round trips. */
47198
48082
  loadedEmbeddedFontList;
48083
+ /**
48084
+ * View properties parsed from `ppt/viewProps.xml` during load, preserved so
48085
+ * an unmodified load -> save round-trips the typed model and callers that do
48086
+ * not override `saveOptions.viewProperties` still persist the loaded state.
48087
+ */
48088
+ loadedViewProperties;
47199
48089
  /** Map of comment author IDs to display names (from `ppt/commentAuthors.xml`). */
47200
48090
  commentAuthorMap = /* @__PURE__ */ new Map();
47201
48091
  /** Full comment author details keyed by author ID, preserving initials/lastIdx/clrIdx for round-trip. */
@@ -47335,19 +48225,266 @@ var PptxHandlerRuntime = class {
47335
48225
  }
47336
48226
  };
47337
48227
 
48228
+ // src/core/core/runtime/table-style-border-parse.ts
48229
+ var EMU_PER_PIXEL = 9525;
48230
+ var BORDER_SIDES = [
48231
+ "left",
48232
+ "right",
48233
+ "top",
48234
+ "bottom",
48235
+ "insideH",
48236
+ "insideV",
48237
+ "tl2br",
48238
+ "bl2tr"
48239
+ ];
48240
+ function parseSolidFillStyle(solidFill2) {
48241
+ if (!solidFill2) {
48242
+ return void 0;
48243
+ }
48244
+ const schemeClr = solidFill2["a:schemeClr"];
48245
+ if (!schemeClr) {
48246
+ return void 0;
48247
+ }
48248
+ const schemeColor = String(schemeClr["@_val"] || "").trim() || void 0;
48249
+ if (!schemeColor) {
48250
+ return void 0;
48251
+ }
48252
+ const tintRaw = schemeClr["a:tint"];
48253
+ const tint = tintRaw ? parseInt(String(tintRaw["@_val"] || "0"), 10) || void 0 : void 0;
48254
+ const shadeRaw = schemeClr["a:shade"];
48255
+ const shade = shadeRaw ? parseInt(String(shadeRaw["@_val"] || "0"), 10) || void 0 : void 0;
48256
+ return { schemeColor, tint, shade };
48257
+ }
48258
+ function parseBorderSide(side) {
48259
+ if (!side) {
48260
+ return void 0;
48261
+ }
48262
+ const ln = side["a:ln"];
48263
+ if (!ln) {
48264
+ return void 0;
48265
+ }
48266
+ const border = {};
48267
+ let has = false;
48268
+ if (ln["a:noFill"] !== void 0) {
48269
+ border.noFill = true;
48270
+ has = true;
48271
+ }
48272
+ const widthEmu = parseInt(String(ln["@_w"] || "0"), 10);
48273
+ if (widthEmu > 0) {
48274
+ border.width = Math.max(1, Math.round(widthEmu / EMU_PER_PIXEL));
48275
+ has = true;
48276
+ }
48277
+ const prstDash = ln["a:prstDash"];
48278
+ const dashVal = prstDash ? String(prstDash["@_val"] || "").trim() : "";
48279
+ if (dashVal) {
48280
+ border.dash = dashVal;
48281
+ has = true;
48282
+ }
48283
+ const solidFill2 = ln["a:solidFill"];
48284
+ const fill = parseSolidFillStyle(solidFill2);
48285
+ if (fill) {
48286
+ border.fill = fill;
48287
+ has = true;
48288
+ } else {
48289
+ const srgb = solidFill2?.["a:srgbClr"];
48290
+ const hex10 = srgb ? String(srgb["@_val"] || "").trim() : "";
48291
+ if (hex10) {
48292
+ border.color = hex10.startsWith("#") ? hex10 : `#${hex10}`;
48293
+ has = true;
48294
+ }
48295
+ }
48296
+ return has ? border : void 0;
48297
+ }
48298
+ function parseTableStyleBorders(tcStyle) {
48299
+ const tcBdr = tcStyle?.["a:tcBdr"];
48300
+ if (!tcBdr) {
48301
+ return void 0;
48302
+ }
48303
+ const result = {};
48304
+ let has = false;
48305
+ for (const name of BORDER_SIDES) {
48306
+ const border = parseBorderSide(tcBdr[`a:${name}`]);
48307
+ if (border) {
48308
+ result[name] = border;
48309
+ has = true;
48310
+ }
48311
+ }
48312
+ return has ? result : void 0;
48313
+ }
48314
+
48315
+ // src/core/core/runtime/table-style-fill-parse.ts
48316
+ function toHex3(raw) {
48317
+ const hex10 = String(raw ?? "").trim();
48318
+ if (!hex10) {
48319
+ return void 0;
48320
+ }
48321
+ return hex10.startsWith("#") ? hex10 : `#${hex10}`;
48322
+ }
48323
+ function parseColorChoiceFill(node) {
48324
+ if (!node) {
48325
+ return void 0;
48326
+ }
48327
+ const scheme = parseSolidFillStyle(node);
48328
+ if (scheme) {
48329
+ return scheme;
48330
+ }
48331
+ const srgb = node["a:srgbClr"];
48332
+ const color2 = toHex3(srgb?.["@_val"]);
48333
+ if (!color2) {
48334
+ return void 0;
48335
+ }
48336
+ const fill = { schemeColor: "", color: color2 };
48337
+ const tintRaw = srgb?.["a:tint"];
48338
+ const tint = tintRaw ? parseInt(String(tintRaw["@_val"] || "0"), 10) || void 0 : void 0;
48339
+ if (tint !== void 0) {
48340
+ fill.tint = tint;
48341
+ }
48342
+ const shadeRaw = srgb?.["a:shade"];
48343
+ const shade = shadeRaw ? parseInt(String(shadeRaw["@_val"] || "0"), 10) || void 0 : void 0;
48344
+ if (shade !== void 0) {
48345
+ fill.shade = shade;
48346
+ }
48347
+ return fill;
48348
+ }
48349
+ function parseGradientFill(gradFill) {
48350
+ const gsLst = gradFill["a:gsLst"];
48351
+ const rawStops = gsLst?.["a:gs"];
48352
+ const gsNodes = Array.isArray(rawStops) ? rawStops : rawStops ? [rawStops] : [];
48353
+ const stops = [];
48354
+ for (const gs of gsNodes) {
48355
+ const fill = parseColorChoiceFill(gs);
48356
+ if (!fill) {
48357
+ continue;
48358
+ }
48359
+ const position2 = (parseInt(String(gs["@_pos"] || "0"), 10) || 0) / 1e3;
48360
+ stops.push({ position: position2, fill });
48361
+ }
48362
+ if (stops.length === 0) {
48363
+ return void 0;
48364
+ }
48365
+ const lin = gradFill["a:lin"];
48366
+ if (lin) {
48367
+ const angRaw = parseInt(String(lin["@_ang"] || "0"), 10) || 0;
48368
+ const angle = (angRaw / 6e4 % 360 + 360) % 360;
48369
+ return { stops, angle, type: "linear" };
48370
+ }
48371
+ if (gradFill["a:path"] !== void 0) {
48372
+ return { stops, type: "radial" };
48373
+ }
48374
+ return { stops, type: "linear" };
48375
+ }
48376
+ function parsePatternFill(pattFill) {
48377
+ const preset = String(pattFill["@_prst"] || "").trim();
48378
+ if (!preset) {
48379
+ return void 0;
48380
+ }
48381
+ const pattern = { preset };
48382
+ const foreground = parseColorChoiceFill(pattFill["a:fgClr"]);
48383
+ if (foreground) {
48384
+ pattern.foreground = foreground;
48385
+ }
48386
+ const background = parseColorChoiceFill(pattFill["a:bgClr"]);
48387
+ if (background) {
48388
+ pattern.background = background;
48389
+ }
48390
+ return pattern;
48391
+ }
48392
+ function parseTableStyleSectionFill(section) {
48393
+ if (!section) {
48394
+ return void 0;
48395
+ }
48396
+ const tcStyle = section["a:tcStyle"];
48397
+ const fillWrap = tcStyle?.["a:fill"];
48398
+ if (!fillWrap) {
48399
+ return void 0;
48400
+ }
48401
+ if (fillWrap["a:noFill"] !== void 0) {
48402
+ return { schemeColor: "", noFill: true };
48403
+ }
48404
+ const solid = fillWrap["a:solidFill"];
48405
+ if (solid) {
48406
+ return parseColorChoiceFill(solid);
48407
+ }
48408
+ const grad = fillWrap["a:gradFill"];
48409
+ if (grad) {
48410
+ const gradient = parseGradientFill(grad);
48411
+ if (gradient) {
48412
+ return { schemeColor: "", gradient };
48413
+ }
48414
+ }
48415
+ const patt = fillWrap["a:pattFill"];
48416
+ if (patt) {
48417
+ const pattern = parsePatternFill(patt);
48418
+ if (pattern) {
48419
+ return { schemeColor: "", pattern };
48420
+ }
48421
+ }
48422
+ return void 0;
48423
+ }
48424
+ function parseTableStyleSectionText(section) {
48425
+ const tcTxStyle = section?.["a:tcTxStyle"];
48426
+ if (!tcTxStyle) {
48427
+ return void 0;
48428
+ }
48429
+ const result = {};
48430
+ let hasProps = false;
48431
+ if (tcTxStyle["@_b"] === "on") {
48432
+ result.bold = true;
48433
+ hasProps = true;
48434
+ }
48435
+ if (tcTxStyle["@_i"] === "on") {
48436
+ result.italic = true;
48437
+ hasProps = true;
48438
+ }
48439
+ const underline = String(tcTxStyle["@_u"] || "").trim();
48440
+ if (underline && underline !== "none") {
48441
+ result.underline = true;
48442
+ hasProps = true;
48443
+ }
48444
+ const font = tcTxStyle["a:font"];
48445
+ const face = font ? String(font["@_typeface"] || "").trim() : "";
48446
+ if (face) {
48447
+ result.fontFace = face;
48448
+ hasProps = true;
48449
+ }
48450
+ const fontRef = tcTxStyle["a:fontRef"];
48451
+ const idx = fontRef ? String(fontRef["@_idx"] || "").trim() : "";
48452
+ if (idx) {
48453
+ result.fontRefIdx = idx;
48454
+ hasProps = true;
48455
+ }
48456
+ const schemeClr = fontRef?.["a:schemeClr"] ?? tcTxStyle["a:schemeClr"];
48457
+ if (schemeClr) {
48458
+ const val = String(schemeClr["@_val"] || "").trim();
48459
+ if (val) {
48460
+ result.fontSchemeColor = val;
48461
+ hasProps = true;
48462
+ const tintNode = schemeClr["a:tint"];
48463
+ if (tintNode) {
48464
+ result.fontTint = parseInt(String(tintNode["@_val"] || "0"), 10) || void 0;
48465
+ }
48466
+ const shadeNode = schemeClr["a:shade"];
48467
+ if (shadeNode) {
48468
+ result.fontShade = parseInt(String(shadeNode["@_val"] || "0"), 10) || void 0;
48469
+ }
48470
+ }
48471
+ } else {
48472
+ const srgb = fontRef?.["a:srgbClr"] ?? tcTxStyle["a:srgbClr"];
48473
+ const hex10 = toHex3(srgb?.["@_val"]);
48474
+ if (hex10) {
48475
+ result.fontColor = hex10;
48476
+ hasProps = true;
48477
+ }
48478
+ }
48479
+ return hasProps ? result : void 0;
48480
+ }
48481
+
47338
48482
  // src/core/core/runtime/PptxHandlerRuntimeTableStyles.ts
47339
48483
  var PptxHandlerRuntime2 = class extends PptxHandlerRuntime {
47340
48484
  /**
47341
- * Export slides to a raster/vector format.
47342
- *
47343
- * This is a stub that signals export intent. Actual rendering requires a
47344
- * platform-specific canvas or PDF library (e.g. Puppeteer, node-canvas,
47345
- * pdfkit). Host applications should override or extend this method with
47346
- * their own rendering pipeline.
47347
- *
47348
- * @param _slides The slides to export.
47349
- * @param _options Export options (format, DPI, slide indices, etc.).
47350
- * @returns A map of slide index → exported binary data.
48485
+ * Export slides to a raster/vector format. This is a stub that signals
48486
+ * export intent; actual rendering requires a platform-specific canvas or
48487
+ * PDF backend that host applications wire in by overriding this method.
47351
48488
  */
47352
48489
  async exportSlides(slides, options) {
47353
48490
  this.compatibilityService.reportWarning({
@@ -47412,77 +48549,26 @@ var PptxHandlerRuntime2 = class extends PptxHandlerRuntime {
47412
48549
  }
47413
48550
  /**
47414
48551
  * Extract fill information from a table style section element
47415
- * (e.g. `a:wholeTbl`, `a:band1H`, `a:firstRow`).
48552
+ * (e.g. `a:wholeTbl`, `a:band1H`, `a:firstRow`). Handles scheme + sRGB
48553
+ * solids, gradients, preset patterns, and `a:noFill` (issue #95).
47416
48554
  */
47417
48555
  extractTableStyleSectionFill(section) {
47418
- if (!section) {
47419
- return void 0;
47420
- }
47421
- const tcStyle = section["a:tcStyle"];
47422
- if (!tcStyle) {
47423
- return void 0;
47424
- }
47425
- const fill = tcStyle["a:fill"];
47426
- if (!fill) {
47427
- return void 0;
47428
- }
47429
- const solidFill2 = fill["a:solidFill"];
47430
- if (!solidFill2) {
47431
- return void 0;
47432
- }
47433
- const schemeClr = solidFill2["a:schemeClr"];
47434
- if (!schemeClr) {
47435
- return void 0;
47436
- }
47437
- const schemeColor = String(schemeClr["@_val"] || "").trim() || void 0;
47438
- if (!schemeColor) {
47439
- return void 0;
47440
- }
47441
- const tintRaw = schemeClr["a:tint"];
47442
- const tint = tintRaw ? parseInt(String(tintRaw["@_val"] || "0"), 10) || void 0 : void 0;
47443
- const shadeRaw = schemeClr["a:shade"];
47444
- const shade = shadeRaw ? parseInt(String(shadeRaw["@_val"] || "0"), 10) || void 0 : void 0;
47445
- return { schemeColor, tint, shade };
48556
+ return parseTableStyleSectionFill(section);
48557
+ }
48558
+ /**
48559
+ * Extract border styling from a table style section's
48560
+ * `a:tcStyle/a:tcBdr` (per-side line width, dash, and colour).
48561
+ */
48562
+ extractTableStyleSectionBorders(section) {
48563
+ return parseTableStyleBorders(section?.["a:tcStyle"]);
47446
48564
  }
47447
48565
  /**
47448
- * Extract text properties from a:tcTxStyle in a table style section.
48566
+ * Extract text properties from `a:tcTxStyle` in a table style section.
48567
+ * Captures bold/italic/underline, typeface, font-collection index, and the
48568
+ * font colour (scheme or sRGB) (issue #95).
47449
48569
  */
47450
48570
  extractTableStyleSectionText(section) {
47451
- if (!section) {
47452
- return void 0;
47453
- }
47454
- const tcTxStyle = section["a:tcTxStyle"];
47455
- if (!tcTxStyle) {
47456
- return void 0;
47457
- }
47458
- const result = {};
47459
- let hasProps = false;
47460
- if (tcTxStyle["@_b"] === "on") {
47461
- result.bold = true;
47462
- hasProps = true;
47463
- }
47464
- if (tcTxStyle["@_i"] === "on") {
47465
- result.italic = true;
47466
- hasProps = true;
47467
- }
47468
- const fontClr = tcTxStyle["a:fontRef"];
47469
- const schemeClr = fontClr?.["a:schemeClr"] ?? tcTxStyle["a:schemeClr"];
47470
- if (schemeClr) {
47471
- const val = String(schemeClr["@_val"] || "").trim();
47472
- if (val) {
47473
- result.fontSchemeColor = val;
47474
- hasProps = true;
47475
- const tintNode = schemeClr["a:tint"];
47476
- if (tintNode) {
47477
- result.fontTint = parseInt(String(tintNode["@_val"] || "0"), 10) || void 0;
47478
- }
47479
- const shadeNode = schemeClr["a:shade"];
47480
- if (shadeNode) {
47481
- result.fontShade = parseInt(String(shadeNode["@_val"] || "0"), 10) || void 0;
47482
- }
47483
- }
47484
- }
47485
- return hasProps ? result : void 0;
48571
+ return parseTableStyleSectionText(section);
47486
48572
  }
47487
48573
  ensureArray(val) {
47488
48574
  if (!val) {
@@ -47589,6 +48675,15 @@ var PptxHandlerRuntime2 = class extends PptxHandlerRuntime {
47589
48675
  textProps[`${name}Text`] = text2;
47590
48676
  }
47591
48677
  }
48678
+ const borderProps = {};
48679
+ for (const name of sectionNames) {
48680
+ const borders = this.extractTableStyleSectionBorders(
48681
+ style[`a:${name}`]
48682
+ );
48683
+ if (borders) {
48684
+ borderProps[`${name}Borders`] = borders;
48685
+ }
48686
+ }
47592
48687
  const entry = {
47593
48688
  styleId,
47594
48689
  styleName,
@@ -47607,7 +48702,8 @@ var PptxHandlerRuntime2 = class extends PptxHandlerRuntime {
47607
48702
  ...swCellFill ? { swCellFill } : {},
47608
48703
  ...neCellFill ? { neCellFill } : {},
47609
48704
  ...nwCellFill ? { nwCellFill } : {},
47610
- ...textProps
48705
+ ...textProps,
48706
+ ...borderProps
47611
48707
  };
47612
48708
  map[styleId] = entry;
47613
48709
  }
@@ -48152,6 +49248,7 @@ var PptxHandlerRuntime6 = class extends PptxHandlerRuntime5 {
48152
49248
  );
48153
49249
  const trimStartMs = timing.trimStartMs ?? extData.trimStartMs;
48154
49250
  const trimEndMs = timing.trimEndMs ?? extData.trimEndMs;
49251
+ const mediaEmbedPath = extData.embedRId ? this.resolveRelationshipTarget(slidePath, extData.embedRId) : void 0;
48155
49252
  result.set(shapeId, {
48156
49253
  trimStartMs: trimStartMs !== void 0 && !isNaN(trimStartMs) ? trimStartMs : void 0,
48157
49254
  trimEndMs: trimEndMs !== void 0 && !isNaN(trimEndMs) ? trimEndMs : void 0,
@@ -48165,7 +49262,8 @@ var PptxHandlerRuntime6 = class extends PptxHandlerRuntime5 {
48165
49262
  playAcrossSlides: timing.playAcrossSlides || void 0,
48166
49263
  hideWhenNotPlaying: hideWhenNotPlaying || void 0,
48167
49264
  bookmarks: extData.bookmarks.length > 0 ? extData.bookmarks : void 0,
48168
- playbackSpeed: extData.playbackSpeed
49265
+ playbackSpeed: extData.playbackSpeed,
49266
+ mediaEmbedPath
48169
49267
  });
48170
49268
  }
48171
49269
  }
@@ -48341,6 +49439,10 @@ var PptxHandlerRuntime7 = class extends PptxHandlerRuntime6 {
48341
49439
  if (!timing) {
48342
49440
  continue;
48343
49441
  }
49442
+ if (timing.mediaEmbedPath && (typeof el.mediaPath !== "string" || el.mediaPath.length === 0)) {
49443
+ el.mediaPath = timing.mediaEmbedPath;
49444
+ el.mediaMimeType = this.getImageMimeType(timing.mediaEmbedPath);
49445
+ }
48344
49446
  if (timing.trimStartMs !== void 0) {
48345
49447
  el.trimStartMs = timing.trimStartMs;
48346
49448
  }
@@ -49347,7 +50449,7 @@ var PptxHandlerRuntime11 = class extends PptxHandlerRuntime10 {
49347
50449
  }
49348
50450
  }
49349
50451
  async reconcilePresentationSlidesForSave(params) {
49350
- await this.presentationSlidesReconciler.reconcile({
50452
+ return await this.presentationSlidesReconciler.reconcile({
49351
50453
  ...params,
49352
50454
  zip: this.zip,
49353
50455
  parser: this.parser,
@@ -49418,6 +50520,15 @@ var PptxHandlerRuntime11 = class extends PptxHandlerRuntime10 {
49418
50520
  if (align === "justify") {
49419
50521
  return "just";
49420
50522
  }
50523
+ if (align === "justLow") {
50524
+ return "justLow";
50525
+ }
50526
+ if (align === "dist") {
50527
+ return "dist";
50528
+ }
50529
+ if (align === "thaiDist") {
50530
+ return "thaiDist";
50531
+ }
49421
50532
  return void 0;
49422
50533
  }
49423
50534
  pixelsToPoints(px2) {
@@ -49631,6 +50742,31 @@ function applyFontMetadata(fontNode, panose, pitchFamily, charset) {
49631
50742
  }
49632
50743
  return fontNode;
49633
50744
  }
50745
+ function buildUnderlineLineXml(line2) {
50746
+ const uln = {};
50747
+ if (typeof line2.widthEmu === "number" && Number.isFinite(line2.widthEmu)) {
50748
+ uln["@_w"] = String(Math.round(line2.widthEmu));
50749
+ }
50750
+ if (line2.compound) {
50751
+ uln["@_cmpd"] = line2.compound;
50752
+ }
50753
+ if (line2.cap) {
50754
+ uln["@_cap"] = line2.cap;
50755
+ }
50756
+ if (line2.algn) {
50757
+ uln["@_algn"] = line2.algn;
50758
+ }
50759
+ if (line2.prstDash) {
50760
+ uln["a:prstDash"] = { "@_val": line2.prstDash };
50761
+ }
50762
+ if (line2.headEndXml) {
50763
+ uln["a:headEnd"] = line2.headEndXml;
50764
+ }
50765
+ if (line2.tailEndXml) {
50766
+ uln["a:tailEnd"] = line2.tailEndXml;
50767
+ }
50768
+ return uln;
50769
+ }
49634
50770
  var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime11 {
49635
50771
  createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId) {
49636
50772
  const runProps = {
@@ -49651,6 +50787,8 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
49651
50787
  }
49652
50788
  if (style.underline) {
49653
50789
  runProps["@_u"] = style.underlineStyle || "sng";
50790
+ } else if (style.underlineExplicitNone) {
50791
+ runProps["@_u"] = "none";
49654
50792
  }
49655
50793
  if (style.strikethrough !== void 0) {
49656
50794
  runProps["@_strike"] = style.strikethrough ? style.strikeType || "sngStrike" : "noStrike";
@@ -49666,6 +50804,8 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
49666
50804
  }
49667
50805
  if (style.textCaps && style.textCaps !== "none") {
49668
50806
  runProps["@_cap"] = style.textCaps;
50807
+ } else if (style.textCapsExplicitNone) {
50808
+ runProps["@_cap"] = "none";
49669
50809
  }
49670
50810
  if (style.kumimoji !== void 0) {
49671
50811
  runProps["@_kumimoji"] = style.kumimoji ? "1" : "0";
@@ -49774,13 +50914,21 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
49774
50914
  runProps["a:effectDag"] = style.textEffectDagXml;
49775
50915
  }
49776
50916
  if (style.highlightColor) {
49777
- runProps["a:highlight"] = {
49778
- "a:srgbClr": {
49779
- "@_val": style.highlightColor.replace("#", "")
49780
- }
49781
- };
50917
+ const resolvedHighlight = style.highlightColorXml ? this.parseColor(style.highlightColorXml) : void 0;
50918
+ runProps["a:highlight"] = serializeColorChoice(
50919
+ style.highlightColorXml,
50920
+ resolvedHighlight,
50921
+ style.highlightColor
50922
+ );
49782
50923
  }
49783
- if (style.underline && style.underlineColor) {
50924
+ if (style.underlineLineFollowsText) {
50925
+ runProps["a:uLnTx"] = {};
50926
+ } else if (style.underlineLine) {
50927
+ runProps["a:uLn"] = buildUnderlineLineXml(style.underlineLine);
50928
+ }
50929
+ if (style.underlineFillFollowsText) {
50930
+ runProps["a:uFillTx"] = {};
50931
+ } else if (style.underline && style.underlineColor) {
49784
50932
  runProps["a:uFill"] = {
49785
50933
  "a:solidFill": {
49786
50934
  "a:srgbClr": {
@@ -49789,21 +50937,28 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
49789
50937
  }
49790
50938
  };
49791
50939
  }
49792
- if (style.fontFamily) {
50940
+ const latinFace = style.latinFontThemeToken ?? style.fontFamily;
50941
+ if (latinFace) {
49793
50942
  runProps["a:latin"] = applyFontMetadata(
49794
- { "@_typeface": style.fontFamily },
50943
+ { "@_typeface": latinFace },
49795
50944
  style.latinFontPanose,
49796
50945
  style.latinFontPitchFamily,
49797
50946
  style.latinFontCharset
49798
50947
  );
50948
+ }
50949
+ const eastAsiaFace = style.eastAsiaFontThemeToken ?? style.eastAsiaFont;
50950
+ if (eastAsiaFace) {
49799
50951
  runProps["a:ea"] = applyFontMetadata(
49800
- { "@_typeface": style.eastAsiaFont || style.fontFamily },
50952
+ { "@_typeface": eastAsiaFace },
49801
50953
  style.eastAsiaFontPanose,
49802
50954
  style.eastAsiaFontPitchFamily,
49803
50955
  style.eastAsiaFontCharset
49804
50956
  );
50957
+ }
50958
+ const complexScriptFace = style.complexScriptFontThemeToken ?? style.complexScriptFont;
50959
+ if (complexScriptFace) {
49805
50960
  runProps["a:cs"] = applyFontMetadata(
49806
- { "@_typeface": style.complexScriptFont || style.fontFamily },
50961
+ { "@_typeface": complexScriptFace },
49807
50962
  style.complexScriptFontPanose,
49808
50963
  style.complexScriptFontPitchFamily,
49809
50964
  style.complexScriptFontCharset
@@ -49853,12 +51008,17 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
49853
51008
  if (mouseOverTarget.length > 0) {
49854
51009
  const mouseOverRelId = resolveHyperlinkRelationshipId(mouseOverTarget);
49855
51010
  if (mouseOverRelId) {
49856
- runProps["a:hlinkMouseOver"] = {
49857
- "@_r:id": mouseOverRelId
49858
- };
51011
+ const mouseOverNode = { "@_r:id": mouseOverRelId };
51012
+ if (style.hyperlinkMouseOverSoundXml && typeof style.hyperlinkMouseOverSoundXml === "object") {
51013
+ mouseOverNode["a:snd"] = style.hyperlinkMouseOverSoundXml;
51014
+ }
51015
+ runProps["a:hlinkMouseOver"] = mouseOverNode;
49859
51016
  }
49860
51017
  }
49861
51018
  }
51019
+ if (style.runPropertiesExtLstXml && typeof style.runPropertiesExtLstXml === "object") {
51020
+ runProps["a:extLst"] = style.runPropertiesExtLstXml;
51021
+ }
49862
51022
  return runProps;
49863
51023
  }
49864
51024
  applyHyperlinkExtraAttrs(hlinkNode, style) {
@@ -49877,22 +51037,26 @@ var PptxHandlerRuntime12 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
49877
51037
  if (style.hyperlinkEndSound !== void 0) {
49878
51038
  hlinkNode["@_endSnd"] = style.hyperlinkEndSound ? "1" : "0";
49879
51039
  }
51040
+ if (style.hyperlinkSoundXml && typeof style.hyperlinkSoundXml === "object") {
51041
+ hlinkNode["a:snd"] = style.hyperlinkSoundXml;
51042
+ }
49880
51043
  }
49881
51044
  };
49882
51045
 
49883
51046
  // src/core/core/runtime/PptxHandlerRuntimeSaveParagraphs.ts
49884
51047
  var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
49885
51048
  createParagraphsFromTextContent(text2, textStyle, textSegments, resolveHyperlinkRelationshipId) {
49886
- const paragraphAlign = this.textAlignToDrawingValue(textStyle?.align);
49887
- const spacing = {
49888
- spacingBefore: this.createParagraphSpacingXmlFromPx(textStyle?.paragraphSpacingBefore),
49889
- spacingAfter: this.createParagraphSpacingXmlFromPx(textStyle?.paragraphSpacingAfter),
49890
- lineSpacing: this.createLineSpacingXmlFromMultiplier(textStyle?.lineSpacing),
49891
- lineSpacingExactPt: textStyle?.lineSpacingExactPt
49892
- };
49893
- const createParagraph = (runs, bulletInfo, level, endParaRunProperties) => {
51049
+ const createParagraph = (runs, bulletInfo, level, endParaRunProperties, paragraphProperties2) => {
51050
+ const effectiveStyle = paragraphProperties2 ? { ...textStyle, ...paragraphProperties2 } : textStyle;
51051
+ const paragraphAlign = this.textAlignToDrawingValue(effectiveStyle?.align);
51052
+ const spacing = {
51053
+ spacingBefore: this.createParagraphSpacingXmlFromPx(effectiveStyle?.paragraphSpacingBefore),
51054
+ spacingAfter: this.createParagraphSpacingXmlFromPx(effectiveStyle?.paragraphSpacingAfter),
51055
+ lineSpacing: this.createLineSpacingXmlFromMultiplier(effectiveStyle?.lineSpacing),
51056
+ lineSpacingExactPt: effectiveStyle?.lineSpacingExactPt
51057
+ };
49894
51058
  const paragraphProps = buildParagraphPropertiesXml(
49895
- textStyle,
51059
+ effectiveStyle,
49896
51060
  paragraphAlign,
49897
51061
  bulletInfo,
49898
51062
  spacing,
@@ -49904,12 +51068,22 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
49904
51068
  "a:rPr": this.createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId),
49905
51069
  "a:t": runText
49906
51070
  });
49907
- const createFieldRun = (runText, style, fieldType, fieldGuid) => ({
49908
- "@_type": fieldType,
49909
- ...fieldGuid ? { "@_id": fieldGuid } : {},
49910
- "a:rPr": this.createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId),
49911
- "a:t": runText
49912
- });
51071
+ const createFieldRun = (runText, style, fieldType, fieldGuid, fieldGuidAttr, fieldParagraphPropertiesXml) => {
51072
+ const fld = { "@_type": fieldType };
51073
+ if (fieldGuid) {
51074
+ if (fieldGuidAttr === "uuid") {
51075
+ fld["@_uuid"] = fieldGuid;
51076
+ } else {
51077
+ fld["@_id"] = fieldGuid;
51078
+ }
51079
+ }
51080
+ fld["a:rPr"] = this.createRunPropertiesFromTextStyle(style, resolveHyperlinkRelationshipId);
51081
+ if (fieldParagraphPropertiesXml && typeof fieldParagraphPropertiesXml === "object") {
51082
+ fld["a:pPr"] = fieldParagraphPropertiesXml;
51083
+ }
51084
+ fld["a:t"] = runText;
51085
+ return fld;
51086
+ };
49913
51087
  const createRubyRun = (segment, style) => {
49914
51088
  const rubyPr = {};
49915
51089
  if (segment.rubyAlignment) {
@@ -49948,17 +51122,27 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
49948
51122
  let currentBulletInfo;
49949
51123
  let currentLevel;
49950
51124
  let currentEndParaRunProperties;
51125
+ let currentParagraphProperties;
51126
+ let capturedParagraphMeta = false;
49951
51127
  const pushParagraph = () => {
49952
51128
  if (currentRuns.length === 0) {
49953
51129
  currentRuns.push(createRun("", textStyle));
49954
51130
  }
49955
51131
  paragraphs.push(
49956
- createParagraph(currentRuns, currentBulletInfo, currentLevel, currentEndParaRunProperties)
51132
+ createParagraph(
51133
+ currentRuns,
51134
+ currentBulletInfo,
51135
+ currentLevel,
51136
+ currentEndParaRunProperties,
51137
+ currentParagraphProperties
51138
+ )
49957
51139
  );
49958
51140
  currentRuns = [];
49959
51141
  currentBulletInfo = void 0;
49960
51142
  currentLevel = void 0;
49961
51143
  currentEndParaRunProperties = void 0;
51144
+ currentParagraphProperties = void 0;
51145
+ capturedParagraphMeta = false;
49962
51146
  };
49963
51147
  if (textSegments && textSegments.length > 0) {
49964
51148
  const uniformSegmentOverrides = computeUniformSegmentOverrides(textStyle, textSegments);
@@ -49968,7 +51152,7 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
49968
51152
  ...segment.style,
49969
51153
  ...uniformSegmentOverrides
49970
51154
  };
49971
- if (currentRuns.length === 0) {
51155
+ if (!capturedParagraphMeta) {
49972
51156
  if (segment.bulletInfo) {
49973
51157
  currentBulletInfo = segment.bulletInfo;
49974
51158
  }
@@ -49978,6 +51162,10 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
49978
51162
  if (segment.endParaRunProperties) {
49979
51163
  currentEndParaRunProperties = segment.endParaRunProperties;
49980
51164
  }
51165
+ if (segment.paragraphProperties) {
51166
+ currentParagraphProperties = segment.paragraphProperties;
51167
+ }
51168
+ capturedParagraphMeta = true;
49981
51169
  }
49982
51170
  if (segment.isLineBreak) {
49983
51171
  const brNode = {};
@@ -50012,7 +51200,9 @@ var PptxHandlerRuntime13 = class extends PptxHandlerRuntime12 {
50012
51200
  linePart,
50013
51201
  segmentStyle,
50014
51202
  segment.fieldType,
50015
- segment.fieldGuid
51203
+ segment.fieldGuid,
51204
+ segment.fieldGuidAttr,
51205
+ segment.fieldParagraphPropertiesXml
50016
51206
  );
50017
51207
  fieldRun.__isField = true;
50018
51208
  currentRuns.push(fieldRun);
@@ -50472,6 +51662,16 @@ var PptxHandlerRuntime15 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
50472
51662
  const chOffY = 0;
50473
51663
  const chExtCx = extCx;
50474
51664
  const chExtCy = extCy;
51665
+ const xfrmAttrs = {};
51666
+ if (typeof group.rotation === "number" && group.rotation !== 0) {
51667
+ xfrmAttrs["@_rot"] = String(Math.round(group.rotation * 6e4));
51668
+ }
51669
+ if (group.flipHorizontal) {
51670
+ xfrmAttrs["@_flipH"] = "1";
51671
+ }
51672
+ if (group.flipVertical) {
51673
+ xfrmAttrs["@_flipV"] = "1";
51674
+ }
50475
51675
  const grpXml = {
50476
51676
  "p:nvGrpSpPr": {
50477
51677
  "p:cNvPr": { "@_id": "0", "@_name": group.id },
@@ -50480,6 +51680,7 @@ var PptxHandlerRuntime15 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
50480
51680
  },
50481
51681
  "p:grpSpPr": {
50482
51682
  "a:xfrm": {
51683
+ ...xfrmAttrs,
50483
51684
  "a:off": {
50484
51685
  "@_x": String(offX),
50485
51686
  "@_y": String(offY)
@@ -50766,7 +51967,95 @@ var PptxHandlerRuntime16 = class extends PptxHandlerRuntime15 {
50766
51967
  };
50767
51968
 
50768
51969
  // src/core/core/runtime/PptxHandlerRuntimeTextStyleUtils.ts
51970
+ var SCRIPT_CANDIDATES = {
51971
+ cjk: ["Hans", "Hant", "Jpan", "Hang"],
51972
+ kana: ["Jpan", "Hans", "Hant"],
51973
+ hangul: ["Hang"],
51974
+ arabic: ["Arab"],
51975
+ hebrew: ["Hebr"],
51976
+ thai: ["Thai"]
51977
+ };
51978
+ function aggregateFontScriptOverrides(perPathMap) {
51979
+ const aggregate = {};
51980
+ for (const overrides10 of perPathMap.values()) {
51981
+ for (const [script, typeface] of Object.entries(overrides10)) {
51982
+ if (!(script in aggregate)) {
51983
+ aggregate[script] = typeface;
51984
+ }
51985
+ }
51986
+ }
51987
+ return aggregate;
51988
+ }
51989
+ function detectDominantScript(text2) {
51990
+ const counts = {};
51991
+ for (const ch of text2) {
51992
+ const code = ch.codePointAt(0) ?? 0;
51993
+ let cat;
51994
+ if (code >= 4352 && code <= 4607) {
51995
+ cat = "hangul";
51996
+ } else if (code >= 44032 && code <= 55215) {
51997
+ cat = "hangul";
51998
+ } else if (code >= 12352 && code <= 12543) {
51999
+ cat = "kana";
52000
+ } else if (code >= 19968 && code <= 40959 || code >= 13312 && code <= 19903 || code >= 63744 && code <= 64255) {
52001
+ cat = "cjk";
52002
+ } else if (code >= 1536 && code <= 1791) {
52003
+ cat = "arabic";
52004
+ } else if (code >= 1424 && code <= 1535) {
52005
+ cat = "hebrew";
52006
+ } else if (code >= 3584 && code <= 3711) {
52007
+ cat = "thai";
52008
+ }
52009
+ if (cat) {
52010
+ counts[cat] = (counts[cat] ?? 0) + 1;
52011
+ }
52012
+ }
52013
+ let best;
52014
+ let bestCount = 0;
52015
+ for (const [cat, count] of Object.entries(counts)) {
52016
+ if (count > bestCount) {
52017
+ best = cat;
52018
+ bestCount = count;
52019
+ }
52020
+ }
52021
+ return best;
52022
+ }
50769
52023
  var PptxHandlerRuntime17 = class extends PptxHandlerRuntime16 {
52024
+ /**
52025
+ * Resolve the automatic per-script fallback face for a run's text from the
52026
+ * theme's `<a:font script="...">` overrides (#83). Body (minor) fonts win
52027
+ * over heading (major) fonts. Returns `undefined` when the deck declares no
52028
+ * script overrides or the text needs no fallback.
52029
+ */
52030
+ resolveScriptFallbackFont(text2) {
52031
+ if (!text2) {
52032
+ return void 0;
52033
+ }
52034
+ if (this.masterThemeMinorFontScripts.size === 0 && this.masterThemeMajorFontScripts.size === 0) {
52035
+ return void 0;
52036
+ }
52037
+ const category = detectDominantScript(text2);
52038
+ if (!category) {
52039
+ return void 0;
52040
+ }
52041
+ const candidates = SCRIPT_CANDIDATES[category];
52042
+ if (!candidates) {
52043
+ return void 0;
52044
+ }
52045
+ const minor = aggregateFontScriptOverrides(this.masterThemeMinorFontScripts);
52046
+ for (const key of candidates) {
52047
+ if (minor[key]) {
52048
+ return minor[key];
52049
+ }
52050
+ }
52051
+ const major = aggregateFontScriptOverrides(this.masterThemeMajorFontScripts);
52052
+ for (const key of candidates) {
52053
+ if (major[key]) {
52054
+ return major[key];
52055
+ }
52056
+ }
52057
+ return void 0;
52058
+ }
50770
52059
  textStylesEqual(left, right) {
50771
52060
  const keys = [
50772
52061
  "fontFamily",
@@ -50927,6 +52216,10 @@ var PptxHandlerRuntime18 = class extends PptxHandlerRuntime17 {
50927
52216
  const esVal = String(endSnd).trim().toLowerCase();
50928
52217
  style.hyperlinkEndSound = esVal === "1" || esVal === "true";
50929
52218
  }
52219
+ const clickSnd = hyperlinkNode["a:snd"];
52220
+ if (clickSnd && typeof clickSnd === "object") {
52221
+ style.hyperlinkSoundXml = clickSnd;
52222
+ }
50930
52223
  }
50931
52224
  const actionStr = String(hyperlinkNode?.["@_action"] || "").trim();
50932
52225
  if (actionStr) {
@@ -50956,6 +52249,10 @@ var PptxHandlerRuntime18 = class extends PptxHandlerRuntime17 {
50956
52249
  } else {
50957
52250
  style.hyperlinkMouseOver = mouseOverRelId;
50958
52251
  }
52252
+ const mouseOverSnd = hlinkMouseOver["a:snd"];
52253
+ if (mouseOverSnd && typeof mouseOverSnd === "object") {
52254
+ style.hyperlinkMouseOverSoundXml = mouseOverSnd;
52255
+ }
50959
52256
  }
50960
52257
  }
50961
52258
  }
@@ -51182,6 +52479,8 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
51182
52479
  if (rawU.length > 0 && rawU !== "none") {
51183
52480
  style.underlineStyle = rawU;
51184
52481
  }
52482
+ } else if (underlineToken === "none") {
52483
+ style.underlineExplicitNone = true;
51185
52484
  }
51186
52485
  }
51187
52486
  const uFill = runProperties2["a:uFill"];
@@ -51193,6 +52492,46 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
51193
52492
  style.underlineColor = underlineColor;
51194
52493
  }
51195
52494
  }
52495
+ if (uLn) {
52496
+ const line2 = {};
52497
+ const widthEmu = Number.parseInt(String(uLn["@_w"] ?? ""), 10);
52498
+ if (Number.isFinite(widthEmu)) {
52499
+ line2.widthEmu = widthEmu;
52500
+ }
52501
+ const compound = String(uLn["@_cmpd"] ?? "").trim();
52502
+ if (compound) {
52503
+ line2.compound = compound;
52504
+ }
52505
+ const cap = String(uLn["@_cap"] ?? "").trim();
52506
+ if (cap) {
52507
+ line2.cap = cap;
52508
+ }
52509
+ const algn = String(uLn["@_algn"] ?? "").trim();
52510
+ if (algn) {
52511
+ line2.algn = algn;
52512
+ }
52513
+ const prstDash = String(uLn["a:prstDash"]?.["@_val"] ?? "").trim();
52514
+ if (prstDash) {
52515
+ line2.prstDash = prstDash;
52516
+ }
52517
+ const headEnd = uLn["a:headEnd"];
52518
+ if (headEnd && typeof headEnd === "object") {
52519
+ line2.headEndXml = headEnd;
52520
+ }
52521
+ const tailEnd = uLn["a:tailEnd"];
52522
+ if (tailEnd && typeof tailEnd === "object") {
52523
+ line2.tailEndXml = tailEnd;
52524
+ }
52525
+ if (Object.keys(line2).length > 0) {
52526
+ style.underlineLine = line2;
52527
+ }
52528
+ }
52529
+ if (runProperties2["a:uLnTx"] !== void 0) {
52530
+ style.underlineLineFollowsText = true;
52531
+ }
52532
+ if (runProperties2["a:uFillTx"] !== void 0) {
52533
+ style.underlineFillFollowsText = true;
52534
+ }
51196
52535
  if (runProperties2["@_strike"] !== void 0) {
51197
52536
  const strikeToken = String(runProperties2["@_strike"] || "").trim().toLowerCase();
51198
52537
  style.strikethrough = strikeToken.length > 0 && strikeToken !== "nostrike" && strikeToken !== "none" && strikeToken !== "0" && strikeToken !== "false";
@@ -51236,10 +52575,15 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
51236
52575
  }
51237
52576
  }
51238
52577
  if (runProperties2["a:highlight"]) {
51239
- const highlightHex = this.parseColor(xmlChild(runProperties2, "a:highlight"));
52578
+ const highlightNode = xmlChild(runProperties2, "a:highlight");
52579
+ const highlightHex = this.parseColor(highlightNode);
51240
52580
  if (highlightHex) {
51241
52581
  style.highlightColor = highlightHex;
51242
52582
  }
52583
+ const highlightXml = extractColorChoiceXml(highlightNode);
52584
+ if (highlightXml) {
52585
+ style.highlightColorXml = highlightXml;
52586
+ }
51243
52587
  }
51244
52588
  const textFillVariants = this.extractTextFillVariants(runProperties2);
51245
52589
  if (textFillVariants.textFillGradient) {
@@ -51260,16 +52604,28 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
51260
52604
  const latin = xmlChild(runProperties2, "a:latin");
51261
52605
  const eastAsian = xmlChild(runProperties2, "a:ea");
51262
52606
  const complexScript = xmlChild(runProperties2, "a:cs");
51263
- const chosenTypeface = xmlAttr(latin, "typeface") || xmlAttr(eastAsian, "typeface") || xmlAttr(complexScript, "typeface");
52607
+ const latinTypefaceToken = xmlAttr(latin, "typeface");
52608
+ const eaTypefaceToken = xmlAttr(eastAsian, "typeface");
52609
+ const csTypefaceToken = xmlAttr(complexScript, "typeface");
52610
+ const chosenTypeface = latinTypefaceToken || eaTypefaceToken || csTypefaceToken;
51264
52611
  const resolvedTypeface = this.resolveThemeTypeface(chosenTypeface);
51265
52612
  if (resolvedTypeface) {
51266
52613
  style.fontFamily = resolvedTypeface;
51267
52614
  }
51268
- const eaTypeface = this.resolveThemeTypeface(xmlAttr(eastAsian, "typeface"));
52615
+ if (latinTypefaceToken && latinTypefaceToken.startsWith("+")) {
52616
+ style.latinFontThemeToken = latinTypefaceToken;
52617
+ }
52618
+ if (eaTypefaceToken && eaTypefaceToken.startsWith("+")) {
52619
+ style.eastAsiaFontThemeToken = eaTypefaceToken;
52620
+ }
52621
+ if (csTypefaceToken && csTypefaceToken.startsWith("+")) {
52622
+ style.complexScriptFontThemeToken = csTypefaceToken;
52623
+ }
52624
+ const eaTypeface = this.resolveThemeTypeface(eaTypefaceToken);
51269
52625
  if (eaTypeface) {
51270
52626
  style.eastAsiaFont = eaTypeface;
51271
52627
  }
51272
- const csTypeface = this.resolveThemeTypeface(xmlAttr(complexScript, "typeface"));
52628
+ const csTypeface = this.resolveThemeTypeface(csTypefaceToken);
51273
52629
  if (csTypeface) {
51274
52630
  style.complexScriptFont = csTypeface;
51275
52631
  }
@@ -51285,6 +52641,9 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
51285
52641
  const capAttr = String(runProperties2["@_cap"] || "").trim().toLowerCase();
51286
52642
  if (capAttr === "all" || capAttr === "small") {
51287
52643
  style.textCaps = capAttr;
52644
+ } else if (capAttr === "none") {
52645
+ style.textCaps = "none";
52646
+ style.textCapsExplicitNone = true;
51288
52647
  }
51289
52648
  const symNode = xmlChild(runProperties2, "a:sym");
51290
52649
  if (symNode) {
@@ -51344,6 +52703,12 @@ var PptxHandlerRuntime19 = class _PptxHandlerRuntime extends PptxHandlerRuntime1
51344
52703
  this.applyTextRunEffects(style, runEffectList);
51345
52704
  }
51346
52705
  this.applyTextRunEffectDag(style, runProperties2);
52706
+ if (includeDefaultAlignment) {
52707
+ const runExtLst = runProperties2["a:extLst"];
52708
+ if (runExtLst && typeof runExtLst === "object") {
52709
+ style.runPropertiesExtLstXml = runExtLst;
52710
+ }
52711
+ }
51347
52712
  return style;
51348
52713
  }
51349
52714
  /**
@@ -52015,12 +53380,63 @@ function writeCellTextFormatting(xmlCell, style, ensureArray16) {
52015
53380
  }
52016
53381
 
52017
53382
  // src/core/core/runtime/PptxHandlerRuntimeSaveTableStyles.ts
53383
+ function flattenCellTxBodyText(txBody, ensureArray16) {
53384
+ if (!txBody) {
53385
+ return "";
53386
+ }
53387
+ const paragraphs = ensureArray16(txBody["a:p"]);
53388
+ const lines = [];
53389
+ for (const paragraph of paragraphs) {
53390
+ const runs = ensureArray16(paragraph?.["a:r"]);
53391
+ const fields = ensureArray16(paragraph?.["a:fld"]);
53392
+ let lineText = "";
53393
+ for (const run of runs) {
53394
+ lineText += String(run?.["a:t"] ?? "");
53395
+ }
53396
+ for (const field of fields) {
53397
+ lineText += String(field?.["a:t"] ?? "");
53398
+ }
53399
+ lines.push(lineText);
53400
+ }
53401
+ return lines.join("\n");
53402
+ }
53403
+ function isRichCellTxBody(txBody, ensureArray16) {
53404
+ if (!txBody) {
53405
+ return false;
53406
+ }
53407
+ const paragraphs = ensureArray16(txBody["a:p"]);
53408
+ let totalRuns = 0;
53409
+ for (const paragraph of paragraphs) {
53410
+ const runs = ensureArray16(paragraph?.["a:r"]);
53411
+ totalRuns += runs.length;
53412
+ if (totalRuns > 1) {
53413
+ return true;
53414
+ }
53415
+ if (ensureArray16(paragraph?.["a:fld"]).length > 0) {
53416
+ return true;
53417
+ }
53418
+ for (const run of runs) {
53419
+ const rPr = run?.["a:rPr"];
53420
+ if (rPr?.["a:hlinkClick"] !== void 0) {
53421
+ return true;
53422
+ }
53423
+ }
53424
+ }
53425
+ return false;
53426
+ }
52018
53427
  var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime21 {
52019
53428
  /**
52020
53429
  * Write plain text into a table cell's txBody, preserving
52021
53430
  * existing run properties where possible.
52022
53431
  */
52023
53432
  writeTableCellText(xmlCell, text2) {
53433
+ const ensureArray16 = this.ensureArray.bind(this);
53434
+ const existingTxBody = xmlCell["a:txBody"];
53435
+ if (existingTxBody && ensureArray16(existingTxBody["a:p"]).length > 0) {
53436
+ if (flattenCellTxBodyText(existingTxBody, ensureArray16) === text2) {
53437
+ return;
53438
+ }
53439
+ }
52024
53440
  if (!xmlCell["a:txBody"]) {
52025
53441
  xmlCell["a:txBody"] = { "a:bodyPr": {}, "a:p": {} };
52026
53442
  }
@@ -52148,7 +53564,9 @@ var PptxHandlerRuntime22 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
52148
53564
  }
52149
53565
  delete tcPr["a:tcMar"];
52150
53566
  writeDiagonalBorders(tcPr, style, _PptxHandlerRuntime.EMU_PER_PX);
52151
- writeCellTextFormatting(xmlCell, style, this.ensureArray.bind(this));
53567
+ if (!isRichCellTxBody(xmlCell["a:txBody"], this.ensureArray.bind(this))) {
53568
+ writeCellTextFormatting(xmlCell, style, this.ensureArray.bind(this));
53569
+ }
52152
53570
  const reordered = reorderObjectKeys(tcPr, TC_PR_BORDERS_ORDER);
52153
53571
  for (const key of Object.keys(tcPr)) {
52154
53572
  delete tcPr[key];
@@ -53833,7 +55251,7 @@ function findKey19(obj, name, getLocalName2) {
53833
55251
  function hex9(value) {
53834
55252
  return value.replace("#", "");
53835
55253
  }
53836
- var COLOR_LOCAL_NAMES = /* @__PURE__ */ new Set([
55254
+ var COLOR_LOCAL_NAMES2 = /* @__PURE__ */ new Set([
53837
55255
  "srgbClr",
53838
55256
  "schemeClr",
53839
55257
  "sysClr",
@@ -53842,7 +55260,7 @@ var COLOR_LOCAL_NAMES = /* @__PURE__ */ new Set([
53842
55260
  "hslClr"
53843
55261
  ]);
53844
55262
  function applyColorToList(list, value, getLocalName2) {
53845
- const colorKey = Object.keys(list).find((k) => COLOR_LOCAL_NAMES.has(getLocalName2(k)));
55263
+ const colorKey = Object.keys(list).find((k) => COLOR_LOCAL_NAMES2.has(getLocalName2(k)));
53846
55264
  const srgb = { "@_val": hex9(value) };
53847
55265
  if (!colorKey) {
53848
55266
  list["a:srgbClr"] = srgb;
@@ -56334,6 +57752,33 @@ var PptxHandlerRuntime27 = class extends PptxHandlerRuntime26 {
56334
57752
  }
56335
57753
  };
56336
57754
 
57755
+ // src/core/core/runtime/save-line-fill.ts
57756
+ function writeLineFill(lineNode, shapeStyle, parseColor) {
57757
+ delete lineNode["a:noFill"];
57758
+ delete lineNode["a:solidFill"];
57759
+ delete lineNode["a:gradFill"];
57760
+ delete lineNode["a:pattFill"];
57761
+ if (shapeStyle.strokeColor === "transparent" || shapeStyle.strokeWidth === 0) {
57762
+ lineNode["a:noFill"] = {};
57763
+ return;
57764
+ }
57765
+ if (shapeStyle.strokeFillMode === "gradient" && shapeStyle.strokeGradientXml) {
57766
+ lineNode["a:gradFill"] = shapeStyle.strokeGradientXml;
57767
+ return;
57768
+ }
57769
+ if (shapeStyle.strokeFillMode === "pattern" && shapeStyle.strokePatternXml) {
57770
+ lineNode["a:pattFill"] = shapeStyle.strokePatternXml;
57771
+ return;
57772
+ }
57773
+ const resolvedStrokeOriginal = shapeStyle.strokeColorXml ? parseColor(shapeStyle.strokeColorXml) : void 0;
57774
+ lineNode["a:solidFill"] = serializeColorChoice(
57775
+ shapeStyle.strokeColorXml,
57776
+ resolvedStrokeOriginal,
57777
+ shapeStyle.strokeColor ?? "#000000",
57778
+ shapeStyle.strokeOpacity
57779
+ );
57780
+ }
57781
+
56337
57782
  // src/core/core/runtime/PptxHandlerRuntimeSaveShapeStyleWriter.ts
56338
57783
  var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime27 {
56339
57784
  /**
@@ -56404,26 +57849,14 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
56404
57849
  );
56405
57850
  }
56406
57851
  }
56407
- if (shapeStyle.strokeColor !== void 0) {
57852
+ if (shapeStyle.strokeColor !== void 0 || shapeStyle.strokeFillMode === "gradient" || shapeStyle.strokeFillMode === "pattern") {
56408
57853
  if (!spPr["a:ln"]) {
56409
57854
  spPr["a:ln"] = {};
56410
57855
  }
56411
57856
  const lineNode = spPr["a:ln"];
56412
57857
  const w = Math.round((shapeStyle.strokeWidth || 1) * _PptxHandlerRuntime.EMU_PER_PX);
56413
57858
  lineNode["@_w"] = String(w);
56414
- if (shapeStyle.strokeColor === "transparent" || shapeStyle.strokeWidth === 0) {
56415
- lineNode["a:noFill"] = {};
56416
- delete lineNode["a:solidFill"];
56417
- } else {
56418
- delete lineNode["a:noFill"];
56419
- const resolvedStrokeOriginal = shapeStyle.strokeColorXml ? this.parseColor(shapeStyle.strokeColorXml) : void 0;
56420
- lineNode["a:solidFill"] = serializeColorChoice(
56421
- shapeStyle.strokeColorXml,
56422
- resolvedStrokeOriginal,
56423
- shapeStyle.strokeColor,
56424
- shapeStyle.strokeOpacity
56425
- );
56426
- }
57859
+ this.applyLineFill(lineNode, shapeStyle);
56427
57860
  }
56428
57861
  if (shapeStyle.strokeDash !== void 0) {
56429
57862
  if (!spPr["a:ln"]) {
@@ -56513,6 +57946,15 @@ var PptxHandlerRuntime28 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
56513
57946
  spPr["a:ln"]["a:effectLst"] = lineEffectListXml;
56514
57947
  }
56515
57948
  }
57949
+ /**
57950
+ * Emit the single fill child of an `<a:ln>` (CT_LineProperties allows at
57951
+ * most one of noFill/solidFill/gradFill/pattFill). Delegates to
57952
+ * {@link writeLineFill} so the logic stays unit-testable without the full
57953
+ * save runtime (issue #87).
57954
+ */
57955
+ applyLineFill(lineNode, shapeStyle) {
57956
+ writeLineFill(lineNode, shapeStyle, (colorNode) => this.parseColor(colorNode));
57957
+ }
56516
57958
  /**
56517
57959
  * Serialize the shape's `<p:style>` block (CT_ShapeStyle §20.1.2.2.36)
56518
57960
  * from the persisted ref indices/colour XML. Emits children in spec
@@ -56668,45 +58110,18 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
56668
58110
  const s3d = shapeStyle.scene3d;
56669
58111
  const hasData = s3d.cameraPreset || s3d.lightRigType;
56670
58112
  if (hasData) {
56671
- const cameraObj = {};
56672
- if (s3d.cameraPreset) {
56673
- cameraObj["@_prst"] = s3d.cameraPreset;
56674
- }
56675
- if (s3d.cameraRotX !== void 0 || s3d.cameraRotY !== void 0 || s3d.cameraRotZ !== void 0) {
56676
- const rot = {};
56677
- if (s3d.cameraRotX !== void 0) {
56678
- rot["@_lat"] = String(s3d.cameraRotX);
56679
- }
56680
- if (s3d.cameraRotY !== void 0) {
56681
- rot["@_lon"] = String(s3d.cameraRotY);
56682
- }
56683
- if (s3d.cameraRotZ !== void 0) {
56684
- rot["@_rev"] = String(s3d.cameraRotZ);
56685
- }
56686
- cameraObj["a:rot"] = rot;
56687
- }
56688
- const lightRigObj = {};
56689
- if (s3d.lightRigType) {
56690
- lightRigObj["@_rig"] = s3d.lightRigType;
56691
- }
56692
- if (s3d.lightRigDirection) {
56693
- lightRigObj["@_dir"] = s3d.lightRigDirection;
56694
- }
56695
- const scene3dXml = {};
56696
- scene3dXml["a:camera"] = cameraObj;
56697
- if (Object.keys(lightRigObj).length > 0) {
56698
- scene3dXml["a:lightRig"] = lightRigObj;
56699
- }
56700
- if (s3d.hasBackdrop) {
56701
- const backdropObj = {};
56702
- if (s3d.backdropAnchorX !== void 0 || s3d.backdropAnchorY !== void 0 || s3d.backdropAnchorZ !== void 0) {
56703
- backdropObj["a:anchor"] = {
56704
- "@_x": String(s3d.backdropAnchorX ?? 0),
56705
- "@_y": String(s3d.backdropAnchorY ?? 0),
56706
- "@_z": String(s3d.backdropAnchorZ ?? 0)
56707
- };
56708
- }
56709
- scene3dXml["a:backdrop"] = backdropObj;
58113
+ const source = spPr["a:scene3d"] ?? {};
58114
+ const scene3dXml = { ...source };
58115
+ scene3dXml["a:camera"] = buildScene3dCamera(s3d, source);
58116
+ const lightRig = buildScene3dLightRig(s3d, source);
58117
+ if (lightRig) {
58118
+ scene3dXml["a:lightRig"] = lightRig;
58119
+ }
58120
+ const backdrop = buildScene3dBackdrop(s3d);
58121
+ if (backdrop) {
58122
+ scene3dXml["a:backdrop"] = backdrop;
58123
+ } else {
58124
+ delete scene3dXml["a:backdrop"];
56710
58125
  }
56711
58126
  spPr["a:scene3d"] = scene3dXml;
56712
58127
  } else {
@@ -56751,12 +58166,12 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
56751
58166
  }
56752
58167
  if (sh3d.extrusionColor) {
56753
58168
  sp3dXml["a:extrusionClr"] = {
56754
- "a:srgbClr": { "@_val": sh3d.extrusionColor }
58169
+ "a:srgbClr": { "@_val": sh3d.extrusionColor.replace("#", "") }
56755
58170
  };
56756
58171
  }
56757
58172
  if (sh3d.contourColor) {
56758
58173
  sp3dXml["a:contourClr"] = {
56759
- "a:srgbClr": { "@_val": sh3d.contourColor }
58174
+ "a:srgbClr": { "@_val": sh3d.contourColor.replace("#", "") }
56760
58175
  };
56761
58176
  }
56762
58177
  spPr["a:sp3d"] = sp3dXml;
@@ -56768,6 +58183,77 @@ var PptxHandlerRuntime29 = class extends PptxHandlerRuntime28 {
56768
58183
  }
56769
58184
  }
56770
58185
  };
58186
+ function buildSphereRot(lat, lon, rev) {
58187
+ if (lat === void 0 && lon === void 0 && rev === void 0) {
58188
+ return void 0;
58189
+ }
58190
+ const rot = {};
58191
+ if (lat !== void 0) {
58192
+ rot["@_lat"] = String(lat);
58193
+ }
58194
+ if (lon !== void 0) {
58195
+ rot["@_lon"] = String(lon);
58196
+ }
58197
+ if (rev !== void 0) {
58198
+ rot["@_rev"] = String(rev);
58199
+ }
58200
+ return rot;
58201
+ }
58202
+ function buildScene3dCamera(s3d, source) {
58203
+ const camera = { ...source["a:camera"] ?? {} };
58204
+ if (s3d.cameraPreset) {
58205
+ camera["@_prst"] = s3d.cameraPreset;
58206
+ }
58207
+ if (s3d.cameraFieldOfView !== void 0) {
58208
+ camera["@_fov"] = String(s3d.cameraFieldOfView);
58209
+ }
58210
+ if (s3d.cameraZoom !== void 0) {
58211
+ camera["@_zoom"] = String(s3d.cameraZoom);
58212
+ }
58213
+ const rot = buildSphereRot(s3d.cameraRotX, s3d.cameraRotY, s3d.cameraRotZ);
58214
+ if (rot) {
58215
+ camera["a:rot"] = rot;
58216
+ }
58217
+ return camera;
58218
+ }
58219
+ function buildScene3dLightRig(s3d, source) {
58220
+ const lightRig = { ...source["a:lightRig"] ?? {} };
58221
+ if (s3d.lightRigType) {
58222
+ lightRig["@_rig"] = s3d.lightRigType;
58223
+ }
58224
+ if (s3d.lightRigDirection) {
58225
+ lightRig["@_dir"] = s3d.lightRigDirection;
58226
+ }
58227
+ const rot = buildSphereRot(s3d.lightRigRotX, s3d.lightRigRotY, s3d.lightRigRotZ);
58228
+ if (rot) {
58229
+ lightRig["a:rot"] = rot;
58230
+ }
58231
+ return Object.keys(lightRig).length > 0 ? lightRig : void 0;
58232
+ }
58233
+ function buildScene3dBackdrop(s3d) {
58234
+ const hasNorm = s3d.backdropNormalX !== void 0 || s3d.backdropNormalY !== void 0 || s3d.backdropNormalZ !== void 0;
58235
+ const hasUp = s3d.backdropUpX !== void 0 || s3d.backdropUpY !== void 0 || s3d.backdropUpZ !== void 0;
58236
+ if (!s3d.hasBackdrop || !hasNorm || !hasUp) {
58237
+ return void 0;
58238
+ }
58239
+ return {
58240
+ "a:anchor": {
58241
+ "@_x": String(s3d.backdropAnchorX ?? 0),
58242
+ "@_y": String(s3d.backdropAnchorY ?? 0),
58243
+ "@_z": String(s3d.backdropAnchorZ ?? 0)
58244
+ },
58245
+ "a:norm": {
58246
+ "@_dx": String(s3d.backdropNormalX ?? 0),
58247
+ "@_dy": String(s3d.backdropNormalY ?? 0),
58248
+ "@_dz": String(s3d.backdropNormalZ ?? 0)
58249
+ },
58250
+ "a:up": {
58251
+ "@_dx": String(s3d.backdropUpX ?? 0),
58252
+ "@_dy": String(s3d.backdropUpY ?? 0),
58253
+ "@_dz": String(s3d.backdropUpZ ?? 0)
58254
+ }
58255
+ };
58256
+ }
56771
58257
 
56772
58258
  // src/core/core/runtime/PptxHandlerRuntimeSaveTextWriter.ts
56773
58259
  var PptxHandlerRuntime30 = class _PptxHandlerRuntime extends PptxHandlerRuntime29 {
@@ -58808,14 +60294,20 @@ var PptxHandlerRuntime41 = class _PptxHandlerRuntime extends PptxHandlerRuntime4
58808
60294
  relationshipType: constants.slideSyncRelationshipType,
58809
60295
  contentType: constants.slideSyncContentType
58810
60296
  });
58811
- this.slideBackgroundBuilder.applyBackground({
60297
+ await this.slideBackgroundBuilder.applyBackground({
58812
60298
  slideNode,
58813
60299
  slide,
58814
60300
  zip: this.zip,
58815
60301
  saveState: saveSession,
58816
60302
  relationshipRegistry: slideRelationshipRegistry,
58817
60303
  slideImageRelationshipType: constants.slideImageRelationshipType,
58818
- parseDataUrlToBytes: (dataUrl) => this.parseDataUrlToBytes(dataUrl)
60304
+ resolveImageToBytes: (url) => this.resolveMediaToBytes(url),
60305
+ reportUnsupportedBackground: (imageUrl) => this.compatibilityService.reportWarning({
60306
+ code: "SAVE_BACKGROUND_IMAGE_UNSUPPORTED",
60307
+ message: `Slide background image could not be embedded and was preserved as-is or omitted: ${imageUrl.slice(0, 120)}`,
60308
+ scope: "save",
60309
+ slideId: slide.id
60310
+ })
58819
60311
  });
58820
60312
  this.slideCommentPartWriter.writeComments({
58821
60313
  slide,
@@ -60320,7 +61812,7 @@ var PptxHandlerRuntime51 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
60320
61812
  } = saveConstants;
60321
61813
  this.compatibilityService.resetWarnings();
60322
61814
  const saveSession = new PptxSaveStateBuilder().withZip(this.zip).withCommentAuthorMap(this.commentAuthorMap).withCommentAuthorDetails(this.commentAuthorDetails).withCommentAuthorsRootXml(this.commentAuthorsRootXml).withEmuPerPx(_PptxHandlerRuntime.EMU_PER_PX).build();
60323
- await this.reconcilePresentationSlidesForSave({
61815
+ const slideReferenceRemap = await this.reconcilePresentationSlidesForSave({
60324
61816
  slides,
60325
61817
  saveSession,
60326
61818
  slideRelationshipType,
@@ -60415,7 +61907,8 @@ var PptxHandlerRuntime51 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
60415
61907
  rawSlideWidthEmu: this.rawSlideWidthEmu,
60416
61908
  rawSlideHeightEmu: this.rawSlideHeightEmu,
60417
61909
  rawSlideSizeType: this.rawSlideSizeType,
60418
- xmlLookupService: this.xmlLookupService
61910
+ xmlLookupService: this.xmlLookupService,
61911
+ slideReferenceRemap
60419
61912
  });
60420
61913
  this.deduplicateExtensionLists(this.presentationData);
60421
61914
  if (effectiveConformance === "transitional") {
@@ -60432,7 +61925,7 @@ var PptxHandlerRuntime51 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
60432
61925
  printSlidesPerPage: options.handoutMaster.slidesPerPage
60433
61926
  } : options?.presentationProperties;
60434
61927
  await this.applyPresentationPropertiesPart(presentationProperties);
60435
- await this.applyViewPropertiesPart(options?.viewProperties);
61928
+ await this.applyViewPropertiesPart(options?.viewProperties ?? this.loadedViewProperties);
60436
61929
  await this.applyTableStylesPart(options?.tableStyles);
60437
61930
  await this.documentPropertiesUpdater.updateOnSave(slides, {
60438
61931
  coreProperties: options?.coreProperties,
@@ -60720,26 +62213,16 @@ var PptxHandlerRuntime52 = class _PptxHandlerRuntime extends PptxHandlerRuntime5
60720
62213
  return true;
60721
62214
  }
60722
62215
  const typesMatch = source.type === target.type || source.type === "ctrtitle" && target.type === "title" || source.type === "subtitle" && target.type === "body";
60723
- if (source.idx !== void 0 && target.idx !== void 0) {
60724
- if (source.idx !== target.idx) {
60725
- return false;
60726
- }
60727
- if (source.type && target.type && !typesMatch) {
60728
- return false;
60729
- }
60730
- return true;
60731
- }
60732
- if (source.idx !== void 0 && target.idx === void 0) {
60733
- const singletonTypes = /* @__PURE__ */ new Set(["title", "ctrtitle", "subtitle", "dt", "ftr", "sldnum"]);
60734
- if (source.type && singletonTypes.has(source.type)) {
60735
- return typesMatch;
60736
- }
62216
+ const sourceIdx = source.idx ?? "0";
62217
+ const targetIdx = target.idx ?? "0";
62218
+ if (sourceIdx !== targetIdx) {
60737
62219
  return false;
60738
62220
  }
60739
62221
  if (source.type && target.type && !typesMatch) {
60740
62222
  return false;
60741
62223
  }
60742
- if (source.type && !target.type) {
62224
+ const bothHaveExplicitIdx = source.idx !== void 0 && target.idx !== void 0;
62225
+ if (!bothHaveExplicitIdx && source.type && !target.type) {
60743
62226
  return false;
60744
62227
  }
60745
62228
  return true;
@@ -62185,6 +63668,19 @@ var PptxHandlerRuntime61 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
62185
63668
  });
62186
63669
  return hasAny ? locks : void 0;
62187
63670
  }
63671
+ /**
63672
+ * Parse the `@txBox` attribute from a `p:cNvSpPr` node. Returns `true` /
63673
+ * `false` when the attribute is present, or `undefined` when absent so
63674
+ * callers can distinguish "not a text box" from "unspecified".
63675
+ */
63676
+ parseTxBoxFlag(cNvSpPr) {
63677
+ const raw = cNvSpPr?.["@_txBox"];
63678
+ if (raw === void 0) {
63679
+ return void 0;
63680
+ }
63681
+ const val = String(raw).trim().toLowerCase();
63682
+ return val === "1" || val === "true";
63683
+ }
62188
63684
  /**
62189
63685
  * Extract body-level text properties from `a:bodyPr` and apply them to the
62190
63686
  * provided {@link TextStyle}. Returns linked-textbox info when present.
@@ -62367,6 +63863,62 @@ var PptxHandlerRuntime61 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
62367
63863
 
62368
63864
  // src/core/core/runtime/PptxHandlerRuntimeShapeTextParsing.ts
62369
63865
  var PptxHandlerRuntime62 = class _PptxHandlerRuntime extends PptxHandlerRuntime61 {
63866
+ /**
63867
+ * Extract a paragraph's OWN `a:pPr` geometry (align, spacing, margins,
63868
+ * indent, tabs, rtl) as a partial {@link TextStyle} so per-paragraph
63869
+ * formatting round-trips rather than collapsing to one shape-level pPr
63870
+ * (#69). Inherited layout/master values are not re-stamped.
63871
+ */
63872
+ extractParagraphOwnProperties(p, basisFontSize) {
63873
+ const pPr = p["a:pPr"];
63874
+ if (!pPr) {
63875
+ return void 0;
63876
+ }
63877
+ const pp = { ...parseParagraphMargins(pPr) };
63878
+ const align = pPr["@_algn"] !== void 0 ? parseAlignmentAttr2(String(pPr["@_algn"])) : void 0;
63879
+ if (align) {
63880
+ pp.align = align;
63881
+ }
63882
+ const rtl = parseParagraphRtl(pPr);
63883
+ if (rtl !== void 0) {
63884
+ pp.rtl = rtl;
63885
+ }
63886
+ const spcBef = this.parseParagraphSpacingPx(
63887
+ pPr["a:spcBef"],
63888
+ basisFontSize
63889
+ );
63890
+ if (spcBef !== void 0) {
63891
+ pp.paragraphSpacingBefore = spcBef;
63892
+ }
63893
+ const spcAft = this.parseParagraphSpacingPx(
63894
+ pPr["a:spcAft"],
63895
+ basisFontSize
63896
+ );
63897
+ if (spcAft !== void 0) {
63898
+ pp.paragraphSpacingAfter = spcAft;
63899
+ }
63900
+ const lnSpcNode = pPr["a:lnSpc"];
63901
+ const lineSpacing = this.parseLineSpacingMultiplier(lnSpcNode);
63902
+ const exactPt = lineSpacing === void 0 ? this.parseLineSpacingExactPt(lnSpcNode) : void 0;
63903
+ if (lineSpacing !== void 0) {
63904
+ pp.lineSpacing = lineSpacing;
63905
+ } else if (exactPt !== void 0) {
63906
+ pp.lineSpacingExactPt = exactPt;
63907
+ }
63908
+ const tabStops = parseTabStops(pPr);
63909
+ if (tabStops && tabStops.length > 0) {
63910
+ pp.tabStops = tabStops;
63911
+ }
63912
+ const defRPr = pPr["a:defRPr"];
63913
+ if (defRPr && typeof defRPr === "object") {
63914
+ pp.paragraphDefaultRunPropertiesXml = defRPr;
63915
+ }
63916
+ const pPrExtLst = pPr["a:extLst"];
63917
+ if (pPrExtLst && typeof pPrExtLst === "object") {
63918
+ pp.paragraphPropertiesExtLstXml = pPrExtLst;
63919
+ }
63920
+ return Object.keys(pp).length > 0 ? pp : void 0;
63921
+ }
62370
63922
  /**
62371
63923
  * Resolve paragraph-level styles (alignment, spacing, margins, tabs,
62372
63924
  * level styles) for a single paragraph. Modifies `textStyle` in place
@@ -62615,6 +64167,12 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
62615
64167
  ...mergedDefaultRunStyle,
62616
64168
  ...this.extractTextRunStyle(runProps, paraAlign, ctx.slideRelationshipMap)
62617
64169
  };
64170
+ if (!runStyle2.scriptFallbackFont) {
64171
+ const fallback = this.resolveScriptFallbackFont(runText);
64172
+ if (fallback) {
64173
+ runStyle2.scriptFallbackFont = fallback;
64174
+ }
64175
+ }
62618
64176
  parts.push(runText);
62619
64177
  segments.push({ text: runText, style: runStyle2 });
62620
64178
  maybeSeed(runStyle2);
@@ -62656,14 +64214,25 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
62656
64214
  )
62657
64215
  };
62658
64216
  const fldType = String(field["@_type"] || "").trim() || void 0;
62659
- const fldGuid = String(field["@_uuid"] || field["@_id"] || "").trim() || void 0;
64217
+ const uuidAttr = String(field["@_uuid"] || "").trim();
64218
+ const idAttr = String(field["@_id"] || "").trim();
64219
+ const fldGuid = uuidAttr || idAttr || void 0;
64220
+ const fldGuidAttr = uuidAttr ? "uuid" : idAttr ? "id" : void 0;
62660
64221
  parts.push(fieldText);
62661
- segments.push({
64222
+ const fieldSegment = {
62662
64223
  text: fieldText,
62663
64224
  style: fieldRunStyle,
62664
64225
  fieldType: fldType,
62665
64226
  fieldGuid: fldGuid
62666
- });
64227
+ };
64228
+ if (fldGuidAttr) {
64229
+ fieldSegment.fieldGuidAttr = fldGuidAttr;
64230
+ }
64231
+ const fieldPPr = field["a:pPr"];
64232
+ if (fieldPPr && typeof fieldPPr === "object") {
64233
+ fieldSegment.fieldParagraphPropertiesXml = fieldPPr;
64234
+ }
64235
+ segments.push(fieldSegment);
62667
64236
  maybeSeed(fieldRunStyle);
62668
64237
  };
62669
64238
  const processMathElement = (mathEl) => {
@@ -62790,6 +64359,11 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
62790
64359
  ...endParaRPrRaw
62791
64360
  };
62792
64361
  }
64362
+ const basisFontSize = typeof mergedDefaultRunStyle.fontSize === "number" ? mergedDefaultRunStyle.fontSize : void 0;
64363
+ const paragraphOwnProps = this.extractParagraphOwnProperties(p, basisFontSize);
64364
+ if (paragraphOwnProps) {
64365
+ segments[firstSegmentIndex].paragraphProperties = paragraphOwnProps;
64366
+ }
62793
64367
  }
62794
64368
  return { parts, segments, seedStyle };
62795
64369
  }
@@ -63098,7 +64672,11 @@ var PptxHandlerRuntime64 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
63098
64672
  const inheritedCNvSpPr = xmlPath(inheritedPlaceholder?.shape, "p:nvSpPr", "p:cNvSpPr") ?? xmlPath(inheritedPlaceholder?.picture, "p:nvPicPr", "p:cNvPicPr");
63099
64673
  const inheritedLockNode = inheritedCNvSpPr?.["a:spLocks"] ?? inheritedCNvSpPr?.["a:picLocks"];
63100
64674
  const inheritedLocks = this.parseShapeLocks(inheritedLockNode);
63101
- const locks = inheritedLocks ? { ...inheritedLocks, ...slideLocks } : slideLocks;
64675
+ let locks = inheritedLocks ? { ...inheritedLocks, ...slideLocks } : slideLocks;
64676
+ const txBox = this.parseTxBoxFlag(cNvSpPr);
64677
+ if (txBox !== void 0) {
64678
+ locks = { ...locks ?? {}, txBox };
64679
+ }
63102
64680
  const promptText = !hasText && phDefaults?.promptText ? phDefaults.promptText : void 0;
63103
64681
  const opaqueExtLstXml = this.extractOpaqueSpPrExtLst(effectiveSpPr);
63104
64682
  const commonProps = {
@@ -63197,7 +64775,7 @@ var PptxHandlerRuntime65 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
63197
64775
  const skewY = xfrm["@_skewY"] ? parseEmuInt(xfrm["@_skewY"]) / 6e4 : void 0;
63198
64776
  const { flipHorizontal, flipVertical } = this.readFlipState(xfrm);
63199
64777
  const nvPr = pic?.["p:nvPicPr"]?.["p:nvPr"];
63200
- const mediaReference = parseDrawingMediaReference(nvPr);
64778
+ const mediaReference = parseDrawingMediaReference(nvPr, this.externalRelsMap.get(slidePath));
63201
64779
  if (mediaReference) {
63202
64780
  this.compatibilityService.inspectMediaReferenceCompatibility(
63203
64781
  mediaReference.kind,
@@ -63965,6 +65543,9 @@ var PptxHandlerRuntime67 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
63965
65543
  const grpSpPr = group["p:grpSpPr"];
63966
65544
  const xfrm = grpSpPr?.["a:xfrm"];
63967
65545
  let parentX = 0, parentY = 0, parentW = 0, parentH = 0;
65546
+ let groupRotation;
65547
+ let flipHorizontal = false;
65548
+ let flipVertical = false;
63968
65549
  if (xfrm) {
63969
65550
  const off = xfrm["a:off"];
63970
65551
  if (off) {
@@ -63976,6 +65557,12 @@ var PptxHandlerRuntime67 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
63976
65557
  parentW = Math.round(parseEmuInt2(ext["@_cx"]) / _PptxHandlerRuntime.EMU_PER_PX);
63977
65558
  parentH = Math.round(parseEmuInt2(ext["@_cy"]) / _PptxHandlerRuntime.EMU_PER_PX);
63978
65559
  }
65560
+ if (xfrm["@_rot"] !== void 0 && xfrm["@_rot"] !== null) {
65561
+ const rot = parseInt(String(xfrm["@_rot"]), 10) / 6e4;
65562
+ groupRotation = Number.isFinite(rot) && rot !== 0 ? rot : void 0;
65563
+ }
65564
+ flipHorizontal = this.parseBooleanAttr(xfrm["@_flipH"]);
65565
+ flipVertical = this.parseBooleanAttr(xfrm["@_flipV"]);
63979
65566
  }
63980
65567
  const grpFillStyle = grpSpPr ? this.extractShapeStyle(grpSpPr) : void 0;
63981
65568
  const hasGroupFill = grpFillStyle && grpFillStyle.fillMode && grpFillStyle.fillMode !== "none";
@@ -64021,6 +65608,9 @@ var PptxHandlerRuntime67 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
64021
65608
  y: parentY,
64022
65609
  width: parentW || Math.max(...children10.map((c) => c.x + c.width)),
64023
65610
  height: parentH || Math.max(...children10.map((c) => c.y + c.height)),
65611
+ rotation: groupRotation,
65612
+ flipHorizontal: flipHorizontal || void 0,
65613
+ flipVertical: flipVertical || void 0,
64024
65614
  children: children10,
64025
65615
  rawXml: group,
64026
65616
  actionClick: grpActionClick,
@@ -65037,9 +66627,9 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
65037
66627
  }
65038
66628
  const buClr = levelProps["a:buClr"];
65039
66629
  if (buClr) {
65040
- const srgb = buClr["a:srgbClr"];
65041
- if (srgb?.["@_val"]) {
65042
- style.bulletColor = String(srgb["@_val"]);
66630
+ const bulletColor = this.parseColor(buClr);
66631
+ if (bulletColor) {
66632
+ style.bulletColor = bulletColor;
65043
66633
  }
65044
66634
  }
65045
66635
  const buSzPts = levelProps["a:buSzPts"];
@@ -66639,16 +68229,20 @@ var PptxHandlerRuntime80 = class extends PptxHandlerRuntime79 {
66639
68229
  }
66640
68230
  let fontScheme;
66641
68231
  if (hasFonts) {
68232
+ const majorByScript = this.aggregateFontScriptOverrides(this.masterThemeMajorFontScripts);
68233
+ const minorByScript = this.aggregateFontScriptOverrides(this.masterThemeMinorFontScripts);
66642
68234
  fontScheme = {
66643
68235
  majorFont: {
66644
68236
  latin: this.themeFontMap["mj-lt"],
66645
68237
  eastAsia: this.themeFontMap["mj-ea"],
66646
- complexScript: this.themeFontMap["mj-cs"]
68238
+ complexScript: this.themeFontMap["mj-cs"],
68239
+ ...Object.keys(majorByScript).length > 0 ? { byScript: majorByScript } : {}
66647
68240
  },
66648
68241
  minorFont: {
66649
68242
  latin: this.themeFontMap["mn-lt"],
66650
68243
  eastAsia: this.themeFontMap["mn-ea"],
66651
- complexScript: this.themeFontMap["mn-cs"]
68244
+ complexScript: this.themeFontMap["mn-cs"],
68245
+ ...Object.keys(minorByScript).length > 0 ? { byScript: minorByScript } : {}
66652
68246
  }
66653
68247
  };
66654
68248
  }
@@ -66856,6 +68450,23 @@ var PptxHandlerRuntime80 = class extends PptxHandlerRuntime79 {
66856
68450
  *
66857
68451
  * Phase 4 Stream A / M4.
66858
68452
  */
68453
+ /**
68454
+ * Flatten a per-theme-path script-override map (`themePath -> {script ->
68455
+ * typeface}`) into a single `{script -> typeface}` lookup for
68456
+ * {@link buildThemeObject}. Earlier entries win on collision, which matches
68457
+ * the primary-theme-first parse order. Phase 4 Stream A / M4 (#83).
68458
+ */
68459
+ aggregateFontScriptOverrides(perPathMap) {
68460
+ const aggregate = {};
68461
+ for (const overrides10 of perPathMap.values()) {
68462
+ for (const [script, typeface] of Object.entries(overrides10)) {
68463
+ if (!(script in aggregate)) {
68464
+ aggregate[script] = typeface;
68465
+ }
68466
+ }
68467
+ }
68468
+ return aggregate;
68469
+ }
66859
68470
  collectFontScriptOverrides(fontNode) {
66860
68471
  const overrides10 = {};
66861
68472
  if (!fontNode) {
@@ -67491,33 +69102,16 @@ var PptxHandlerRuntime83 = class extends PptxHandlerRuntime82 {
67491
69102
  const metadata = parseSmartArtDefinitionMetadata(colorsDef, localName22);
67492
69103
  const labels = parseSmartArtColorStyleLabels(colorsDef, localName22);
67493
69104
  const name = metadata.titles?.[0]?.value || String(colorsDef["@_title"] || colorsDef["@_uniqueId"] || "").trim() || void 0;
67494
- const fillColors = [];
67495
- const lineColors = [];
67496
69105
  const styleLbls = this.xmlLookupService.getChildrenArrayByLocalName(colorsDef, "styleLbl");
67497
- for (const lbl of styleLbls) {
67498
- const fillClrLst = this.xmlLookupService.getChildByLocalName(lbl, "fillClrLst");
67499
- const linClrLst = this.xmlLookupService.getChildByLocalName(lbl, "linClrLst");
67500
- if (fillClrLst) {
67501
- const color2 = this.parseColor(fillClrLst) ?? this.resolveSmartArtSchemeColor(
67502
- this.xmlLookupService.getChildByLocalName(fillClrLst, "schemeClr")
67503
- );
67504
- if (color2) {
67505
- fillColors.push(color2);
67506
- }
67507
- }
67508
- if (linClrLst) {
67509
- const color2 = this.parseColor(linClrLst) ?? this.resolveSmartArtSchemeColor(
67510
- this.xmlLookupService.getChildByLocalName(linClrLst, "schemeClr")
67511
- );
67512
- if (color2) {
67513
- lineColors.push(color2);
67514
- }
67515
- }
67516
- }
67517
- if (fillColors.length === 0 && lineColors.length === 0) {
69106
+ const colorLists = buildSmartArtColorLists(styleLbls, {
69107
+ getChild: (node, childName) => this.xmlLookupService.getChildByLocalName(node, childName),
69108
+ parseColorChoice: (colorChoice) => this.parseColor(colorChoice),
69109
+ resolveScheme: (colorNode) => this.resolveSmartArtSchemeColor(colorNode)
69110
+ });
69111
+ if (colorLists.fillColors.length === 0 && colorLists.lineColors.length === 0) {
67518
69112
  return void 0;
67519
69113
  }
67520
- return { ...metadata, name, fillColors, lineColors, labels };
69114
+ return { ...metadata, name, ...colorLists, labels };
67521
69115
  } catch {
67522
69116
  return void 0;
67523
69117
  }
@@ -67541,6 +69135,89 @@ var PptxHandlerRuntime83 = class extends PptxHandlerRuntime82 {
67541
69135
  }
67542
69136
  };
67543
69137
 
69138
+ // src/core/core/runtime/smartart-drawing-shape-style.ts
69139
+ function extractDrawingShapeFill(spPr, deps) {
69140
+ const result = {};
69141
+ const solidFill2 = deps.getChild(spPr, "solidFill");
69142
+ if (solidFill2) {
69143
+ result.fillColor = deps.parseColor(solidFill2) ?? void 0;
69144
+ }
69145
+ const gradFill = !solidFill2 ? deps.getChild(spPr, "gradFill") : void 0;
69146
+ if (gradFill) {
69147
+ const stops = deps.extractGradientStops(gradFill).map((stop) => ({
69148
+ color: stop.color,
69149
+ position: stop.position,
69150
+ ...stop.opacity !== void 0 ? { opacity: stop.opacity } : {}
69151
+ }));
69152
+ if (stops.length > 0) {
69153
+ result.fillGradientStops = stops;
69154
+ result.fillGradientType = deps.extractGradientType(gradFill);
69155
+ result.fillGradientAngle = deps.extractGradientAngle(gradFill);
69156
+ result.fillColor ??= stops[Math.floor(stops.length / 2)]?.color;
69157
+ }
69158
+ }
69159
+ const pattFill = !solidFill2 && !gradFill ? deps.getChild(spPr, "pattFill") : void 0;
69160
+ if (pattFill) {
69161
+ const preset = String(pattFill["@_prst"] || "").trim();
69162
+ if (preset) {
69163
+ result.fillPatternPreset = preset;
69164
+ }
69165
+ const fg = deps.parseColor(deps.getChild(pattFill, "fgClr"));
69166
+ const bg = deps.parseColor(deps.getChild(pattFill, "bgClr"));
69167
+ if (fg) {
69168
+ result.fillPatternForegroundColor = fg;
69169
+ }
69170
+ if (bg) {
69171
+ result.fillPatternBackgroundColor = bg;
69172
+ }
69173
+ result.fillColor ??= fg ?? bg;
69174
+ }
69175
+ const blipFill = !solidFill2 && !gradFill && !pattFill ? deps.getChild(spPr, "blipFill") : void 0;
69176
+ if (blipFill) {
69177
+ const blip = deps.getChild(blipFill, "blip");
69178
+ const embed = String(
69179
+ blip?.["@_r:embed"] || blip?.["@_embed"] || blip?.["@_r:link"] || ""
69180
+ ).trim();
69181
+ if (embed) {
69182
+ result.fillBlipEmbedId = embed;
69183
+ }
69184
+ }
69185
+ const shadowColor = deps.extractShadowColor(spPr);
69186
+ if (shadowColor) {
69187
+ result.hasShadow = true;
69188
+ result.shadowColor = shadowColor;
69189
+ }
69190
+ return result;
69191
+ }
69192
+ function extractDrawingShapeTextStyle(txBody, deps) {
69193
+ let fontSize;
69194
+ let fontColor;
69195
+ if (!txBody) {
69196
+ return { fontSize, fontColor };
69197
+ }
69198
+ const paragraphs = deps.getChildren(txBody, "p");
69199
+ for (const p of paragraphs) {
69200
+ const runs = deps.getChildren(p, "r");
69201
+ for (const r of runs) {
69202
+ const rPr = deps.getChild(r, "rPr");
69203
+ if (rPr && !fontSize) {
69204
+ const szRaw = parseInt(String(rPr["@_sz"] || ""), 10);
69205
+ if (Number.isFinite(szRaw) && szRaw > 0) {
69206
+ fontSize = szRaw / 100;
69207
+ }
69208
+ fontColor = deps.parseColor(deps.getChild(rPr, "solidFill")) ?? void 0;
69209
+ }
69210
+ if (fontSize) {
69211
+ break;
69212
+ }
69213
+ }
69214
+ if (fontSize) {
69215
+ break;
69216
+ }
69217
+ }
69218
+ return { fontSize, fontColor };
69219
+ }
69220
+
67544
69221
  // src/core/core/runtime/smartart-text-style-resolution.ts
67545
69222
  function resolveSmartArtTextStyles(paragraphs, resolve) {
67546
69223
  for (const paragraph of paragraphs ?? []) {
@@ -67716,8 +69393,7 @@ var PptxHandlerRuntime84 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
67716
69393
  };
67717
69394
  }
67718
69395
  }
67719
- const solidFill2 = this.xmlLookupService.getChildByLocalName(spPr, "solidFill");
67720
- const fillColor = this.parseColor(solidFill2);
69396
+ const fill = extractDrawingShapeFill(spPr, this.drawingShapeStyleDeps());
67721
69397
  const lnNode = this.xmlLookupService.getChildByLocalName(spPr, "ln");
67722
69398
  const lnFill = lnNode ? this.xmlLookupService.getChildByLocalName(lnNode, "solidFill") : void 0;
67723
69399
  const strokeColor = this.parseColor(lnFill);
@@ -67729,7 +69405,10 @@ var PptxHandlerRuntime84 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
67729
69405
  this.collectLocalTextValues(txBody, "t", textValues2);
67730
69406
  }
67731
69407
  const text2 = textValues2.join("").trim() || void 0;
67732
- const { fontSize, fontColor } = this.extractDrawingShapeTextStyle(txBody);
69408
+ const { fontSize, fontColor } = extractDrawingShapeTextStyle(
69409
+ txBody,
69410
+ this.drawingShapeStyleDeps()
69411
+ );
67733
69412
  const paragraphs = txBody ? resolveSmartArtTextStyles(
67734
69413
  parseSmartArtTextParagraphs({ "dgm:t": txBody }),
67735
69414
  (rPr) => this.extractTextRunStyle(rPr, void 0, void 0, false)
@@ -67755,7 +69434,8 @@ var PptxHandlerRuntime84 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
67755
69434
  rotation,
67756
69435
  skewX,
67757
69436
  skewY,
67758
- fillColor: fillColor ?? void 0,
69437
+ ...fill,
69438
+ fillColor: fill.fillColor ?? void 0,
67759
69439
  strokeColor: strokeColor ?? void 0,
67760
69440
  strokeWidth,
67761
69441
  text: structuredText,
@@ -67765,36 +69445,126 @@ var PptxHandlerRuntime84 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
67765
69445
  ...customGeometry
67766
69446
  };
67767
69447
  }
67768
- extractDrawingShapeTextStyle(txBody) {
67769
- let fontSize;
67770
- let fontColor;
67771
- if (!txBody) {
67772
- return { fontSize, fontColor };
67773
- }
67774
- const paragraphs = this.xmlLookupService.getChildrenArrayByLocalName(txBody, "p");
67775
- for (const p of paragraphs) {
67776
- const runs = this.xmlLookupService.getChildrenArrayByLocalName(p, "r");
67777
- for (const r of runs) {
67778
- const rPr = this.xmlLookupService.getChildByLocalName(r, "rPr");
67779
- if (rPr && !fontSize) {
67780
- const szRaw = parseInt(String(rPr["@_sz"] || ""), 10);
67781
- if (Number.isFinite(szRaw) && szRaw > 0) {
67782
- fontSize = szRaw / 100;
67783
- }
67784
- const rprFill = this.xmlLookupService.getChildByLocalName(rPr, "solidFill");
67785
- fontColor = this.parseColor(rprFill) ?? void 0;
67786
- }
67787
- if (fontSize) {
67788
- break;
67789
- }
67790
- }
67791
- if (fontSize) {
67792
- break;
69448
+ /**
69449
+ * Build the injected accessor bundle used by the pure drawing-shape style
69450
+ * helpers, binding the shared XML-lookup / colour / gradient / shadow codec
69451
+ * methods so no new colour logic is duplicated here.
69452
+ */
69453
+ drawingShapeStyleDeps() {
69454
+ return {
69455
+ getChild: (node, local) => this.xmlLookupService.getChildByLocalName(node, local),
69456
+ getChildren: (node, local) => this.xmlLookupService.getChildrenArrayByLocalName(node, local),
69457
+ parseColor: (node) => this.parseColor(node),
69458
+ extractGradientStops: (gradFill) => this.extractGradientStops(gradFill),
69459
+ extractGradientType: (gradFill) => this.extractGradientType(gradFill),
69460
+ extractGradientAngle: (gradFill) => this.extractGradientAngle(gradFill),
69461
+ extractShadowColor: (spPr) => this.extractShadowStyle(spPr).shadowColor
69462
+ };
69463
+ }
69464
+ };
69465
+
69466
+ // src/core/core/runtime/smartart-drawing-blip.ts
69467
+ function collectDrawingShapeNodes(root, getChildren) {
69468
+ const out = [];
69469
+ const walk = (container) => {
69470
+ if (!container) {
69471
+ return;
69472
+ }
69473
+ for (const sp of getChildren(container, "sp")) {
69474
+ out.push({ node: sp, isPic: false });
69475
+ }
69476
+ for (const pic of getChildren(container, "pic")) {
69477
+ out.push({ node: pic, isPic: true });
69478
+ }
69479
+ for (const grp of getChildren(container, "grpSp")) {
69480
+ walk(grp);
69481
+ }
69482
+ };
69483
+ walk(root);
69484
+ return out;
69485
+ }
69486
+ function picBlipEmbedId(pic, getChild) {
69487
+ const blip = getChild(getChild(pic, "blipFill"), "blip");
69488
+ if (!blip) {
69489
+ return void 0;
69490
+ }
69491
+ const embed = String(blip["@_r:embed"] || blip["@_embed"] || blip["@_r:link"] || "").trim();
69492
+ return embed.length > 0 ? embed : void 0;
69493
+ }
69494
+ function parseDrawingRelTargets(relsXml, parse, ensureArray16) {
69495
+ const map = /* @__PURE__ */ new Map();
69496
+ try {
69497
+ const relsRoot = parse(relsXml)["Relationships"];
69498
+ if (!relsRoot) {
69499
+ return map;
69500
+ }
69501
+ for (const rel of ensureArray16(relsRoot["Relationship"])) {
69502
+ const id = String(rel?.["@_Id"] || "").trim();
69503
+ const target = String(rel?.["@_Target"] || "").trim();
69504
+ if (id.length > 0 && target.length > 0) {
69505
+ map.set(id, target);
67793
69506
  }
67794
69507
  }
67795
- return { fontSize, fontColor };
69508
+ } catch {
67796
69509
  }
67797
- };
69510
+ return map;
69511
+ }
69512
+ async function resolveDrawingBlipFills(shapes, drawingPath, deps) {
69513
+ const pending = shapes.filter((shape) => shape.fillBlipEmbedId && !shape.fillImageUrl);
69514
+ if (pending.length === 0) {
69515
+ return;
69516
+ }
69517
+ const dir = drawingPath.replace(/\/[^/]+$/u, "");
69518
+ const file = drawingPath.split("/").pop() ?? "";
69519
+ const relsXml = await deps.readText(`${dir}/_rels/${file}.rels`);
69520
+ if (!relsXml) {
69521
+ return;
69522
+ }
69523
+ const targets = parseDrawingRelTargets(relsXml, deps.parse, deps.ensureArray);
69524
+ for (const shape of pending) {
69525
+ const target = targets.get(shape.fillBlipEmbedId ?? "");
69526
+ if (!target) {
69527
+ continue;
69528
+ }
69529
+ const source = /^(?:https?:|data:)/u.test(target) ? target : deps.resolveImagePath(drawingPath, target);
69530
+ const resolved = await deps.getImageData(source);
69531
+ if (resolved) {
69532
+ shape.fillImageUrl = resolved;
69533
+ }
69534
+ }
69535
+ }
69536
+ async function parseDrawingShapesFromPart(drawingPath, deps) {
69537
+ const xmlString = await deps.readText(drawingPath);
69538
+ if (!xmlString) {
69539
+ return [];
69540
+ }
69541
+ try {
69542
+ const xml = deps.parse(xmlString);
69543
+ const drawing = deps.getChild(xml, "drawing");
69544
+ const spTree = deps.getChild(drawing || xml, "spTree");
69545
+ if (!spTree) {
69546
+ return [];
69547
+ }
69548
+ const shapes = [];
69549
+ collectDrawingShapeNodes(spTree, deps.getChildren).forEach(({ node, isPic }, index) => {
69550
+ const shape = deps.parseDrawingShape(node, index, deps.emuPerPx);
69551
+ if (!shape) {
69552
+ return;
69553
+ }
69554
+ if (isPic && !shape.fillBlipEmbedId) {
69555
+ const embed = picBlipEmbedId(node, deps.getChild);
69556
+ if (embed) {
69557
+ shape.fillBlipEmbedId = embed;
69558
+ }
69559
+ }
69560
+ shapes.push(shape);
69561
+ });
69562
+ await resolveDrawingBlipFills(shapes, drawingPath, deps);
69563
+ return shapes;
69564
+ } catch {
69565
+ return [];
69566
+ }
69567
+ }
67798
69568
 
67799
69569
  // src/core/core/runtime/smartart-layout-category.ts
67800
69570
  var CATEGORY_FAMILY = {
@@ -67931,6 +69701,7 @@ var PptxHandlerRuntime85 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
67931
69701
  layoutDefinition,
67932
69702
  nodes,
67933
69703
  connections: parsedConnections.length > 0 ? parsedConnections : void 0,
69704
+ presLayoutVars: parseSmartArtPresLayoutVars(dataModel),
67934
69705
  drawingShapes: drawingShapes.length > 0 ? drawingShapes : void 0,
67935
69706
  chrome,
67936
69707
  colorTransform,
@@ -68009,30 +69780,28 @@ var PptxHandlerRuntime85 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
68009
69780
  }
68010
69781
  }
68011
69782
  /**
68012
- * Parse SmartArt drawing shapes given an absolute part path.
69783
+ * Parse cached SmartArt drawing shapes from an absolute part path.
68013
69784
  *
68014
- * Wraps `parseSmartArtDrawingShapes` (which expects a slide-relative
68015
- * relationship id) with a path-based lookup so the resolution layer
68016
- * can pull the part from anywhere in the package.
69785
+ * Enumerates `dsp:sp` / bare `dsp:pic` (incl. nested `dsp:grpSp`) and
69786
+ * resolves picture (blip) fills to data URLs via the drawing part's own
69787
+ * relationships. Delegates to a pure helper with an injected dep bundle.
68017
69788
  */
68018
69789
  async parseSmartArtDrawingShapesFromPath(drawingPath) {
68019
- const xmlString = await this.zip.file(drawingPath)?.async("string");
68020
- if (!xmlString) {
68021
- return [];
68022
- }
68023
- try {
68024
- const xml = this.parser.parse(xmlString);
68025
- const drawing = this.xmlLookupService.getChildByLocalName(xml, "drawing");
68026
- const spTree = this.xmlLookupService.getChildByLocalName(drawing || xml, "spTree");
68027
- if (!spTree) {
68028
- return [];
68029
- }
68030
- const shapes = this.xmlLookupService.getChildrenArrayByLocalName(spTree, "sp");
68031
- const emuPerPx = _PptxHandlerRuntime.EMU_PER_PX;
68032
- return shapes.map((sp, index) => this.parseDrawingShape(sp, index, emuPerPx)).filter((entry) => entry !== null);
68033
- } catch {
68034
- return [];
68035
- }
69790
+ return parseDrawingShapesFromPart(drawingPath, this.drawingBlipDeps());
69791
+ }
69792
+ /** Bind runtime zip / parser / lookup / image helpers for the drawing parser. */
69793
+ drawingBlipDeps() {
69794
+ return {
69795
+ readText: (path) => this.zip.file(path)?.async("string") ?? Promise.resolve(void 0),
69796
+ parse: (xml) => this.parser.parse(xml),
69797
+ getChild: (node, local) => this.xmlLookupService.getChildByLocalName(node, local),
69798
+ getChildren: (node, local) => this.xmlLookupService.getChildrenArrayByLocalName(node, local),
69799
+ parseDrawingShape: (sp, index, emuPerPx) => this.parseDrawingShape(sp, index, emuPerPx),
69800
+ emuPerPx: _PptxHandlerRuntime.EMU_PER_PX,
69801
+ ensureArray: (value) => this.ensureArray(value),
69802
+ resolveImagePath: (base, target) => this.resolveImagePath(base, target),
69803
+ getImageData: (path) => this.getImageData(path)
69804
+ };
68036
69805
  }
68037
69806
  };
68038
69807
 
@@ -68730,6 +70499,11 @@ var PptxHandlerRuntime90 = class extends PptxHandlerRuntime89 {
68730
70499
  grouping = "clustered";
68731
70500
  }
68732
70501
  }
70502
+ const varyColors = this.parseChartBoolVal(seriesContainer, "varyColors");
70503
+ const firstSliceAngle = this.parseChartNumberVal(seriesContainer, "firstSliceAng");
70504
+ const doughnutHoleSize = this.parseChartNumberVal(seriesContainer, "holeSize");
70505
+ const barGapWidth = this.parseChartNumberVal(seriesContainer, "gapWidth");
70506
+ const barOverlap = this.parseChartNumberVal(seriesContainer, "overlap");
68733
70507
  const chartPartPath = chartPart.partPath;
68734
70508
  const dataTable = parseDataTable(plotArea, this.xmlLookupService);
68735
70509
  const dropLines = parseLineStyle(
@@ -68806,6 +70580,11 @@ var PptxHandlerRuntime90 = class extends PptxHandlerRuntime89 {
68806
70580
  title: titleTextValues[0],
68807
70581
  style: chartStyle,
68808
70582
  grouping,
70583
+ ...varyColors !== void 0 ? { varyColors } : {},
70584
+ ...firstSliceAngle !== void 0 ? { firstSliceAngle } : {},
70585
+ ...doughnutHoleSize !== void 0 ? { doughnutHoleSize } : {},
70586
+ ...barGapWidth !== void 0 ? { barGapWidth } : {},
70587
+ ...barOverlap !== void 0 ? { barOverlap } : {},
68809
70588
  chartPartPath,
68810
70589
  chartRelationshipId,
68811
70590
  ...dataTable ? { dataTable } : {},
@@ -68882,6 +70661,35 @@ var PptxHandlerRuntime90 = class extends PptxHandlerRuntime89 {
68882
70661
  }
68883
70662
  return { categories, series };
68884
70663
  }
70664
+ /**
70665
+ * Read a numeric `@val` from a named child of a chart-type container.
70666
+ * Returns `undefined` when the child or its `@val` is absent/non-finite.
70667
+ */
70668
+ parseChartNumberVal(container, localName22) {
70669
+ const node = this.xmlLookupService.getChildByLocalName(container, localName22);
70670
+ const raw = node?.["@_val"];
70671
+ if (raw === void 0 || raw === null || raw === "") {
70672
+ return void 0;
70673
+ }
70674
+ const num = Number.parseFloat(String(raw));
70675
+ return Number.isFinite(num) ? num : void 0;
70676
+ }
70677
+ /**
70678
+ * Read a boolean `@val` from a named child of a chart-type container.
70679
+ * A present element with no `@val` follows the OOXML `CT_Boolean` default
70680
+ * of `true`; `undefined` when the child is absent.
70681
+ */
70682
+ parseChartBoolVal(container, localName22) {
70683
+ const node = this.xmlLookupService.getChildByLocalName(container, localName22);
70684
+ if (!node) {
70685
+ return void 0;
70686
+ }
70687
+ const raw = node["@_val"];
70688
+ if (raw === void 0 || raw === null || raw === "") {
70689
+ return true;
70690
+ }
70691
+ return !(raw === "0" || raw === "false");
70692
+ }
68885
70693
  /**
68886
70694
  * Build the series array from raw OOXML `c:ser` nodes.
68887
70695
  *
@@ -68925,6 +70733,10 @@ var PptxHandlerRuntime90 = class extends PptxHandlerRuntime89 {
68925
70733
  );
68926
70734
  const dataLabels = parseSeriesDataLabels(seriesNode, this.xmlLookupService);
68927
70735
  const explosion = parseSeriesExplosion(seriesNode, this.xmlLookupService);
70736
+ const smoothNode = this.xmlLookupService.getChildByLocalName(seriesNode, "smooth");
70737
+ const smooth = smoothNode ? !(smoothNode["@_val"] === "0" || smoothNode["@_val"] === "false") : void 0;
70738
+ const invertNode = this.xmlLookupService.getChildByLocalName(seriesNode, "invertIfNegative");
70739
+ const invertIfNegative = invertNode ? !(invertNode["@_val"] === "0" || invertNode["@_val"] === "false") : void 0;
68928
70740
  return {
68929
70741
  name: seriesName.trim().length > 0 ? seriesName : `Series ${seriesIndex + 1}`,
68930
70742
  values: fallbackValues,
@@ -68935,6 +70747,8 @@ var PptxHandlerRuntime90 = class extends PptxHandlerRuntime89 {
68935
70747
  ...seriesMarker ? { marker: seriesMarker } : {},
68936
70748
  ...dataLabels.length > 0 ? { dataLabels } : {},
68937
70749
  ...explosion !== void 0 ? { explosion } : {},
70750
+ ...invertIfNegative !== void 0 ? { invertIfNegative } : {},
70751
+ ...smooth !== void 0 ? { smooth } : {},
68938
70752
  ...axisId !== void 0 ? { axisId } : {},
68939
70753
  ...seriesChartType ? { seriesChartType } : {}
68940
70754
  };
@@ -69761,6 +71575,8 @@ var PptxHandlerRuntime94 = class extends PptxHandlerRuntime93 {
69761
71575
  async buildLoadData(presentationState, slidesWithWarnings, slideMasters) {
69762
71576
  const headerFooter = this.extractHeaderFooter();
69763
71577
  const presentationProperties = await this.parsePresentationProperties();
71578
+ const viewProperties = await this.parseViewProperties();
71579
+ this.loadedViewProperties = viewProperties;
69764
71580
  const customShows = this.parseCustomShows();
69765
71581
  const tableStyleMap = await this.parseTableStyles();
69766
71582
  const embeddedFontList = parseEmbeddedFontList(this.presentationData);
@@ -69790,7 +71606,7 @@ var PptxHandlerRuntime94 = class extends PptxHandlerRuntime93 {
69790
71606
  presentationState.height,
69791
71607
  this.rawSlideWidthEmu,
69792
71608
  this.rawSlideHeightEmu
69793
- ).withNotesDimensions(presentationState.notesWidthEmu, presentationState.notesHeightEmu).withSlides(slidesWithWarnings).withLayoutOptions(this.getLayoutOptions()).withHeaderFooter(headerFooter).withPresentationProperties(presentationProperties).withCustomShows(customShows).withSections(
71609
+ ).withNotesDimensions(presentationState.notesWidthEmu, presentationState.notesHeightEmu).withSlides(slidesWithWarnings).withLayoutOptions(this.getLayoutOptions()).withHeaderFooter(headerFooter).withPresentationProperties(presentationProperties).withViewProperties(viewProperties).withCustomShows(customShows).withSections(
69794
71610
  presentationState.orderedSections.length > 0 ? presentationState.orderedSections : void 0
69795
71611
  ).withWarnings(this.compatibilityService.getWarnings()).withThemeColorMap({ ...this.themeColorMap }).withTheme(this.buildThemeObject()).withThemeOptions(themeOptions.length > 0 ? themeOptions : void 0).withTableStyleMap(tableStyleMap).withEmbeddedFonts(embeddedFonts.length > 0 ? embeddedFonts : void 0).withEmbeddedFontList(embeddedFontList).withMruColors(presentationProperties?.mruColors).withNotesMaster(notesMaster).withHandoutMaster(handoutMaster).withSlideMasters(slideMasters.length > 0 ? slideMasters : void 0).withTags(tags.length > 0 ? tags : void 0).withCustomProperties(customProperties.length > 0 ? customProperties : void 0).withCoreProperties(coreProperties).withAppProperties(appProperties).withHasMacros(this.vbaProjectBin !== null ? true : void 0).withHasDigitalSignatures(this.signatureDetection?.hasSignatures || void 0).withDigitalSignatureCount(
69796
71612
  this.signatureDetection?.signatureCount && this.signatureDetection.signatureCount > 0 ? this.signatureDetection.signatureCount : void 0
@@ -69921,6 +71737,7 @@ var PptxHandlerRuntime94 = class extends PptxHandlerRuntime93 {
69921
71737
  this.customXmlParts = [];
69922
71738
  this.loadedEmbeddedFonts = [];
69923
71739
  this.loadedEmbeddedFontList = void 0;
71740
+ this.loadedViewProperties = void 0;
69924
71741
  this.orderedSlidePaths = [];
69925
71742
  this.zip = null;
69926
71743
  }
@@ -70266,6 +72083,7 @@ var PptxHandlerRuntime95 = class _PptxHandlerRuntime extends PptxHandlerRuntime9
70266
72083
  });
70267
72084
  this.mediaDataParser = new PptxMediaDataParser({
70268
72085
  slideRelsMap: this.slideRelsMap,
72086
+ externalRelsMap: this.externalRelsMap,
70269
72087
  resolvePath: (base, relative) => this.resolvePath(base, relative),
70270
72088
  getPathExtension: (pathValue) => this.getPathExtension(pathValue)
70271
72089
  });
@@ -70877,11 +72695,13 @@ function parseDrawingColorChoice(colorNode) {
70877
72695
  }
70878
72696
  if (colorNode["a:scrgbClr"]) {
70879
72697
  const scrgb = colorNode["a:scrgbClr"];
70880
- const red = parseDrawingPercent(scrgb["@_r"]);
70881
- const green = parseDrawingPercent(scrgb["@_g"]);
70882
- const blue = parseDrawingPercent(scrgb["@_b"]);
72698
+ const red = parseDrawingFraction(scrgb["@_r"]);
72699
+ const green = parseDrawingFraction(scrgb["@_g"]);
72700
+ const blue = parseDrawingFraction(scrgb["@_b"]);
70883
72701
  if (red !== void 0 && green !== void 0 && blue !== void 0) {
70884
- const base = `#${toHex(red * 255)}${toHex(green * 255)}${toHex(blue * 255)}`;
72702
+ const base = `#${toHex(scrgbLinearToSrgb8(red))}${toHex(scrgbLinearToSrgb8(green))}${toHex(
72703
+ scrgbLinearToSrgb8(blue)
72704
+ )}`;
70885
72705
  return applyDrawingColorTransforms(base, scrgb);
70886
72706
  }
70887
72707
  }
@@ -70966,7 +72786,7 @@ function parseDrawingColorOpacity(colorNode) {
70966
72786
  const alphaMod = parseDrawingPercent(
70967
72787
  colorChoice["a:alphaMod"]?.["@_val"]
70968
72788
  );
70969
- const alphaOff = parseDrawingPercent(
72789
+ const alphaOff = parseDrawingFraction(
70970
72790
  colorChoice["a:alphaOff"]?.["@_val"]
70971
72791
  );
70972
72792
  if (alpha === void 0 && alphaMod === void 0 && alphaOff === void 0) {
@@ -72956,9 +74776,9 @@ function removeEmptyDataPoint(series, pointIndex) {
72956
74776
  }
72957
74777
  }
72958
74778
  }
72959
- var EMU_PER_PIXEL = 9525;
74779
+ var EMU_PER_PIXEL2 = 9525;
72960
74780
  function pxToEmu(px2) {
72961
- return Math.round(px2 * EMU_PER_PIXEL);
74781
+ return Math.round(px2 * EMU_PER_PIXEL2);
72962
74782
  }
72963
74783
  function placeholderSpXml(ph, shapeId) {
72964
74784
  const name = ph.name ?? `${ph.type.charAt(0).toUpperCase() + ph.type.slice(1)} Placeholder ${shapeId - 1}`;
@@ -74712,7 +76532,7 @@ var GroupBuilder = class _GroupBuilder {
74712
76532
  // src/core/builders/sdk/units.ts
74713
76533
  var PPI = 96;
74714
76534
  var POINTS_PER_INCH = 72;
74715
- var EMU_PER_PIXEL2 = 9525;
76535
+ var EMU_PER_PIXEL3 = 9525;
74716
76536
  var EMU_PER_INCH = 914400;
74717
76537
  var EMU_PER_POINT = 12700;
74718
76538
  function inches(value) {
@@ -74728,10 +76548,10 @@ function pt(value) {
74728
76548
  return Math.round(value / POINTS_PER_INCH * PPI);
74729
76549
  }
74730
76550
  function emuToPixels(emu) {
74731
- return Math.round(emu / EMU_PER_PIXEL2);
76551
+ return Math.round(emu / EMU_PER_PIXEL3);
74732
76552
  }
74733
76553
  function pixelsToEmu(px2) {
74734
- return Math.round(px2 * EMU_PER_PIXEL2);
76554
+ return Math.round(px2 * EMU_PER_PIXEL3);
74735
76555
  }
74736
76556
  function inchesToEmu(value) {
74737
76557
  return Math.round(value * EMU_PER_INCH);
@@ -85077,7 +86897,7 @@ exports.EFFECT_LST_ORDER = EFFECT_LST_ORDER;
85077
86897
  exports.ELEMENT_FIELD_KIND = ELEMENT_FIELD_KIND;
85078
86898
  exports.EMPHASIS_PRESETS = EMPHASIS_PRESETS;
85079
86899
  exports.EMU_PER_INCH = EMU_PER_INCH;
85080
- exports.EMU_PER_PIXEL = EMU_PER_PIXEL2;
86900
+ exports.EMU_PER_PIXEL = EMU_PER_PIXEL3;
85081
86901
  exports.EMU_PER_POINT = EMU_PER_POINT;
85082
86902
  exports.EMU_PER_PX = EMU_PER_PX;
85083
86903
  exports.ENTERPRISE_FAIL_ON_REVOCATION_UNKNOWN_ENV = ENTERPRISE_FAIL_ON_REVOCATION_UNKNOWN_ENV;
@@ -85228,6 +87048,7 @@ exports.buildInkMlContent = buildInkMlContent;
85228
87048
  exports.buildLinkedTextBoxChains = buildLinkedTextBoxChains;
85229
87049
  exports.buildOle2 = buildOle2;
85230
87050
  exports.buildSingleEffectNode = buildSingleEffectNode;
87051
+ exports.buildSlideReferenceRemap = buildSlideReferenceRemap;
85231
87052
  exports.buildSrgbColorChoice = buildSrgbColorChoice;
85232
87053
  exports.buildThemeColorMap = buildThemeColorMap;
85233
87054
  exports.catmullRomToBezier = catmullRomToBezier;
@@ -85299,6 +87120,8 @@ exports.decryptPptx = decryptPptx;
85299
87120
  exports.demoteSmartArtNode = demoteSmartArtNode;
85300
87121
  exports.deobfuscateFont = deobfuscateFont;
85301
87122
  exports.deriveOutputPath = deriveOutputPath;
87123
+ exports.deriveSlideTitle = deriveSlideTitle;
87124
+ exports.deriveSlideTitles = deriveSlideTitles;
85302
87125
  exports.detectDigitalSignatures = detectDigitalSignatures;
85303
87126
  exports.detectFileFormat = detectFileFormat;
85304
87127
  exports.detectFontFormat = detectFontFormat;