reamkit 1.21.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/esm/core/bytes.d.ts +22 -4
  2. package/dist/esm/core/bytes.js +73 -5
  3. package/dist/esm/core/converter/ream.d.ts +16 -0
  4. package/dist/esm/core/converter/ream.js +59 -9
  5. package/dist/esm/core/document-model/types.d.ts +78 -0
  6. package/dist/esm/core/drawingml/chart-geometry.js +11 -5
  7. package/dist/esm/core/drawingml/chart-parser.d.ts +2 -1
  8. package/dist/esm/core/drawingml/chart-parser.js +23 -1
  9. package/dist/esm/core/drawingml/colors.d.ts +30 -4
  10. package/dist/esm/core/drawingml/colors.js +45 -6
  11. package/dist/esm/core/drawingml/preset-geometry.js +236 -0
  12. package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
  13. package/dist/esm/core/drawingml/theme-parser.js +64 -1
  14. package/dist/esm/core/fonts/families.d.ts +10 -0
  15. package/dist/esm/core/fonts/families.js +44 -0
  16. package/dist/esm/core/fonts/index.d.ts +3 -2
  17. package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
  18. package/dist/esm/core/fonts/remote-fonts.js +114 -8
  19. package/dist/esm/core/fonts/scripts.d.ts +26 -0
  20. package/dist/esm/core/fonts/scripts.js +177 -0
  21. package/dist/esm/core/metafile/blit.d.ts +33 -0
  22. package/dist/esm/core/metafile/blit.js +67 -0
  23. package/dist/esm/core/metafile/dib.d.ts +61 -0
  24. package/dist/esm/core/metafile/dib.js +205 -0
  25. package/dist/esm/core/metafile/emf.js +139 -24
  26. package/dist/esm/core/metafile/picture.d.ts +12 -1
  27. package/dist/esm/core/metafile/symbol-fonts.d.ts +42 -0
  28. package/dist/esm/core/metafile/symbol-fonts.js +154 -0
  29. package/dist/esm/core/metafile/wmf.js +183 -10
  30. package/dist/esm/core/ole/escher-blip.d.ts +12 -0
  31. package/dist/esm/core/ole/escher-blip.js +88 -0
  32. package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
  33. package/dist/esm/core/vector.d.ts +5 -0
  34. package/dist/esm/excel/print-model.js +3 -1
  35. package/dist/esm/excel/sheet-shape-parser.js +1 -12
  36. package/dist/esm/excel/styles-parser.js +1 -1
  37. package/dist/esm/excel/xls/biff-reader.js +53 -18
  38. package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
  39. package/dist/esm/excel/xls/biff-styles.js +9 -7
  40. package/dist/esm/excel/xls/escher.js +90 -24
  41. package/dist/esm/excel/xlsx-reader.d.ts +1 -1
  42. package/dist/esm/excel/xlsx-reader.js +3 -3
  43. package/dist/esm/layout/page-doc.d.ts +77 -0
  44. package/dist/esm/layout/page-doc.js +34 -18
  45. package/dist/esm/layout/styled-layout.d.ts +2 -2
  46. package/dist/esm/layout/styled-layout.js +467 -76
  47. package/dist/esm/pdf/shading.d.ts +19 -0
  48. package/dist/esm/pdf/shading.js +84 -11
  49. package/dist/esm/pdf/styled-page-emitter.js +647 -444
  50. package/dist/esm/pdf-reader/image-decode.js +1 -1
  51. package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
  52. package/dist/esm/pptx/embedded-fonts.js +104 -0
  53. package/dist/esm/pptx/ole-preview.d.ts +10 -0
  54. package/dist/esm/pptx/ole-preview.js +52 -0
  55. package/dist/esm/pptx/placeholder-cascade.d.ts +136 -5
  56. package/dist/esm/pptx/placeholder-cascade.js +260 -27
  57. package/dist/esm/pptx/ppt/ppt-reader.js +120 -10
  58. package/dist/esm/pptx/ppt/ppt-text.d.ts +66 -1
  59. package/dist/esm/pptx/ppt/ppt-text.js +576 -137
  60. package/dist/esm/pptx/pptx-reader.d.ts +8 -0
  61. package/dist/esm/pptx/pptx-reader.js +271 -41
  62. package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
  63. package/dist/esm/pptx/preset-table-styles.js +27 -0
  64. package/dist/esm/pptx/slide-parser.d.ts +78 -10
  65. package/dist/esm/pptx/slide-parser.js +396 -95
  66. package/dist/esm/pptx/sp-helpers.d.ts +2 -1
  67. package/dist/esm/pptx/sp-helpers.js +22 -6
  68. package/dist/esm/pptx/table-style.d.ts +64 -0
  69. package/dist/esm/pptx/table-style.js +203 -0
  70. package/dist/esm/svg/svg-writer.js +53 -5
  71. package/dist/esm/word/document-parser.d.ts +7 -1
  72. package/dist/esm/word/document-parser.js +6 -6
  73. package/dist/esm/word/docx-reader.js +8 -5
  74. package/dist/esm/word/docx-to-pdf.d.ts +8 -7
  75. package/dist/esm/word/docx-to-pdf.js +25 -7
  76. package/dist/esm/word/drawing-parser.d.ts +34 -0
  77. package/dist/esm/word/drawing-parser.js +173 -15
  78. package/dist/esm/word/numbering-parser.d.ts +2 -1
  79. package/dist/esm/word/numbering-parser.js +6 -6
  80. package/dist/esm/word/paragraph-properties.d.ts +2 -1
  81. package/dist/esm/word/paragraph-properties.js +2 -2
  82. package/dist/esm/word/run-properties.d.ts +5 -2
  83. package/dist/esm/word/run-properties.js +13 -8
  84. package/dist/esm/word/styles-parser.d.ts +2 -1
  85. package/dist/esm/word/styles-parser.js +12 -12
  86. package/dist/esm/word/table-parser.js +3 -3
  87. package/dist/esm/word/theme-fonts.d.ts +10 -0
  88. package/dist/esm/word/theme-fonts.js +28 -0
  89. package/package.json +1 -1
  90. /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
@@ -1,4 +1,5 @@
1
- import { resolveFamilyKey } from "../core/fonts/remote-fonts.js";
1
+ import { resolveFamilyStyle } from "../core/fonts/remote-fonts.js";
2
+ import { scriptForCodepoint } from "../core/fonts/scripts.js";
2
3
  import { shapeText } from "../core/font/opentype-layout.js";
3
4
  import { createFontMeasure } from "../core/font/measure.js";
4
5
  import { halfPtToPt, pt } from "../core/ir/units.js";
@@ -948,10 +949,11 @@ function layoutBodyElement(el, options, fontResources, imageResources, contentWi
948
949
  if (el.kind === "paragraph") return layoutParagraphBlock(el.paragraph, options, fontResources, imageResources, contentWidth);
949
950
  if (el.kind === "table") return layoutTableBlock(el.table, options, fontResources, imageResources, contentWidth);
950
951
  if (el.kind === "image") {
951
- const meta = el.image.resource ? imageResources?.get(el.image.resource)?.metafile : void 0;
952
- return meta ? layoutMetafileBlock(el.image, meta, options, fontResources, contentWidth, maxHeight, box) : layoutImageBlock(el.image, imageResources, contentWidth, maxHeight, box);
952
+ const res = el.image.resource ? imageResources?.get(el.image.resource) : void 0;
953
+ const meta = res?.metafile;
954
+ return meta ? layoutMetafileBlock(el.image, meta, res.metafileImages, options, fontResources, contentWidth, maxHeight, box) : layoutImageBlock(el.image, imageResources, contentWidth, maxHeight, box);
953
955
  }
954
- if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight);
956
+ if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight, imageResources);
955
957
  return layoutShapeBlock(el.shape, options, fontResources, imageResources, contentWidth, maxHeight, box);
956
958
  }
957
959
  function layoutImageBlock(image, imageResources, contentWidth, maxHeight, box) {
@@ -999,6 +1001,7 @@ function layoutImageBlock(image, imageResources, contentWidth, maxHeight, box) {
999
1001
  resourceName: res?.resourceName ?? "",
1000
1002
  ...image.outline ? { outline: image.outline } : {},
1001
1003
  ...image.wash ? { wash: image.wash } : {},
1004
+ ...image.alpha !== void 0 && image.alpha < 1 ? { alpha: image.alpha } : {},
1002
1005
  ...image.crop ? { crop: image.crop } : {},
1003
1006
  ...image.rotation60k ? { rotationDeg: image.rotation60k / 6e4 } : {},
1004
1007
  ...image.flipH ? { flipH: true } : {},
@@ -1026,9 +1029,9 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
1026
1029
  const fillGradient = shape.fill.kind === "gradient" ? shape.fill.gradient : void 0;
1027
1030
  const fillImage = shape.fill.kind === "picture" && shape.fill.imageResource !== void 0 ? imageResources?.get(shape.fill.imageResource) : void 0;
1028
1031
  const fillImageResourceName = fillImage?.resourceName;
1029
- const fillImageTile = shape.fill.kind === "picture" && shape.fill.tiled === true && fillImage?.prepared ? {
1030
- widthPt: fillImage.prepared.widthPx * 72 / 96,
1031
- heightPt: fillImage.prepared.heightPx * 72 / 96
1032
+ const fillImageTile = shape.fill.kind === "picture" && shape.fill.tiled === true && fillImage?.prepared ? shape.fill.tileSizePt ?? {
1033
+ widthPt: fillImage.prepared.widthPx * 72 / 96 * (shape.fill.tileScale?.sx ?? 1),
1034
+ heightPt: fillImage.prepared.heightPx * 72 / 96 * (shape.fill.tileScale?.sy ?? 1)
1032
1035
  } : void 0;
1033
1036
  const fillColorHex = shape.fill.kind === "solid" ? shape.fill.colorHex : fillGradient ? gradientToSolid(fillGradient) : void 0;
1034
1037
  const stroke = buildStroke(shape.line);
@@ -1073,7 +1076,7 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
1073
1076
  continue;
1074
1077
  }
1075
1078
  if (el.kind === "chart") {
1076
- const laid = layoutChartBlock(el.chart, options, fontResources, innerWidth);
1079
+ const laid = layoutChartBlock(el.chart, options, fontResources, innerWidth, void 0, imageResources);
1077
1080
  const line = {
1078
1081
  tokens: [],
1079
1082
  contentWidthPt: laid.widthPt,
@@ -1185,6 +1188,8 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
1185
1188
  ...fillImageResourceName ? { fillImageResourceName } : {},
1186
1189
  ...fillImageTile ? { fillImageTile } : {},
1187
1190
  ...fillImageResourceName && shape.fill.imageCrop ? { fillImageCrop: shape.fill.imageCrop } : {},
1191
+ ...fillImageResourceName && shape.fill.imageFillRect ? { fillImageRect: shape.fill.imageFillRect } : {},
1192
+ ...fillImageResourceName && shape.fill.duotone ? { fillImageDuotone: shape.fill.duotone } : {},
1188
1193
  ...fillColorHex ? { fillColorHex } : {},
1189
1194
  ...fillGradient ? { fillGradient } : {},
1190
1195
  ...shape.fill.alpha !== void 0 && shape.fill.alpha < 1 ? { fillAlpha: shape.fill.alpha } : {},
@@ -1222,11 +1227,11 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
1222
1227
  * frame. So one is turned into the other rather than growing a block kind, a
1223
1228
  * pagination arm and an emitter of its own.
1224
1229
  */
1225
- function layoutMetafileBlock(image, pic, options, fontResources, contentWidth, maxHeight, box) {
1230
+ function layoutMetafileBlock(image, pic, blitted, options, fontResources, contentWidth, maxHeight, box) {
1226
1231
  const placed = layoutImageBlock(image, void 0, contentWidth, maxHeight, box);
1227
1232
  const widthPt = placed.widthPt;
1228
1233
  const heightPt = placed.heightPt;
1229
- const layout = rotateDrawing(metafileDrawing(pic, widthPt, heightPt, options, fontResources), (image.rotation60k ?? 0) / 6e4, widthPt / 2, heightPt / 2);
1234
+ const layout = rotateDrawing(metafileDrawing(pic, widthPt, heightPt, options, fontResources, image.colorChange, blitted), (image.rotation60k ?? 0) / 6e4, widthPt / 2, heightPt / 2);
1230
1235
  const pp = image.paragraphProperties;
1231
1236
  return {
1232
1237
  kind: "chart",
@@ -1253,6 +1258,7 @@ function rotateDrawing(layout, deg, cx, cy) {
1253
1258
  });
1254
1259
  return {
1255
1260
  shapes: layout.shapes.map((sh) => ({
1261
+ ...sh.seq !== void 0 ? { seq: sh.seq } : {},
1256
1262
  ...sh,
1257
1263
  paths: sh.paths.map((path) => ({
1258
1264
  ...path,
@@ -1289,7 +1295,16 @@ function rotateDrawing(layout, deg, cx, cy) {
1289
1295
  y: p.y,
1290
1296
  rotationDeg: (t.rotationDeg ?? 0) - deg
1291
1297
  };
1292
- })
1298
+ }),
1299
+ ...layout.images ? { images: layout.images.map((img) => {
1300
+ const c = at(img.x + img.width / 2, img.y + img.height / 2);
1301
+ return {
1302
+ ...img,
1303
+ x: c.x - img.width / 2,
1304
+ y: c.y - img.height / 2,
1305
+ rotationDeg: (img.rotationDeg ?? 0) + deg
1306
+ };
1307
+ }) } : {}
1293
1308
  };
1294
1309
  }
1295
1310
  /**
@@ -1297,16 +1312,47 @@ function rotateDrawing(layout, deg, cx, cy) {
1297
1312
  * `heightPt` one and turned y-up about its bottom-left corner — the frame both
1298
1313
  * a chart block and an inline picture token are drawn in.
1299
1314
  */
1300
- function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
1315
+ function metafileDrawing(pic, widthPt, heightPt, options, fontResources, colorChange, blitted) {
1316
+ const recolour = (hex) => {
1317
+ if (hex === void 0 || colorChange === void 0) return hex;
1318
+ if (hex.toUpperCase() !== colorChange.fromHex.toUpperCase()) return hex;
1319
+ return colorChange.transparent ? null : colorChange.toHex;
1320
+ };
1301
1321
  const sx = widthPt / pic.width;
1302
1322
  const sy = heightPt / pic.height;
1303
1323
  const mapX = (x) => (x - pic.left) * sx;
1304
1324
  const mapY = (y) => heightPt - (y - pic.top) * sy;
1305
1325
  const shapes = [];
1306
1326
  const texts = [];
1327
+ const images = [];
1328
+ let seq = 0;
1329
+ let blit = 0;
1307
1330
  for (const prim of pic.prims) {
1331
+ if (prim.kind === "image") {
1332
+ const resourceName = blitted?.[blit++] ?? "";
1333
+ if (resourceName === "") {
1334
+ seq++;
1335
+ continue;
1336
+ }
1337
+ images.push({
1338
+ seq: seq++,
1339
+ resourceName,
1340
+ x: mapX(prim.x),
1341
+ y: mapY(prim.y + prim.height),
1342
+ width: prim.width * sx,
1343
+ height: prim.height * sy
1344
+ });
1345
+ continue;
1346
+ }
1308
1347
  if (prim.kind === "path") {
1348
+ const fill = recolour(prim.fillColorHex);
1349
+ const strokeHex = recolour(prim.stroke?.colorHex);
1350
+ if (fill === null && (prim.stroke === void 0 || strokeHex === null)) {
1351
+ seq++;
1352
+ continue;
1353
+ }
1309
1354
  shapes.push({
1355
+ seq: seq++,
1310
1356
  paths: prim.paths.map((path) => ({
1311
1357
  ...path,
1312
1358
  segments: path.segments.map((seg) => seg.op === "close" ? seg : seg.op === "cubic" ? {
@@ -1323,23 +1369,29 @@ function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
1323
1369
  y: mapY(seg.y)
1324
1370
  })
1325
1371
  })),
1326
- ...prim.fillColorHex !== void 0 ? { fillColorHex: prim.fillColorHex } : {},
1327
- ...prim.stroke ? { stroke: {
1372
+ ...fill !== void 0 && fill !== null ? { fillColorHex: fill } : {},
1373
+ ...prim.stroke && strokeHex !== null ? { stroke: {
1328
1374
  ...prim.stroke,
1375
+ ...strokeHex !== void 0 ? { colorHex: strokeHex } : {},
1329
1376
  widthPt: Math.max(.25, prim.stroke.widthPt * sx)
1330
1377
  } } : {}
1331
1378
  });
1332
1379
  continue;
1333
1380
  }
1334
- if (prim.kind !== "text") continue;
1335
1381
  const { variant } = options.registry.resolveByStyle(prim.bold === true, prim.italic === true);
1336
1382
  const font = fontResources.get(variant);
1337
1383
  if (!font) continue;
1338
1384
  const sizePt = Math.max(1, prim.sizeLu * sy);
1339
- const line = makeChartLabelLine(prim.text, font, sizePt, prim.colorHex);
1385
+ const textHex = recolour(prim.colorHex);
1386
+ if (textHex === null) {
1387
+ seq++;
1388
+ continue;
1389
+ }
1390
+ const line = makeChartLabelLine(prim.text, font, sizePt, textHex ?? prim.colorHex);
1340
1391
  const shift = prim.alignH === "center" ? -line.contentWidthPt / 2 : prim.alignH === "right" ? -line.contentWidthPt : 0;
1341
1392
  const baselineY = mapY(prim.y) - (prim.alignBaseline ? 0 : sizePt * .8);
1342
1393
  texts.push({
1394
+ seq: seq++,
1343
1395
  line,
1344
1396
  x: mapX(prim.x) + shift,
1345
1397
  y: baselineY,
@@ -1348,10 +1400,11 @@ function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
1348
1400
  }
1349
1401
  return {
1350
1402
  shapes,
1351
- texts
1403
+ texts,
1404
+ ...images.length > 0 ? { images } : {}
1352
1405
  };
1353
1406
  }
1354
- function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight) {
1407
+ function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight, imageResources) {
1355
1408
  let widthPt = block.width;
1356
1409
  let heightPt = block.height;
1357
1410
  if (widthPt > contentWidth && widthPt > 0) {
@@ -1373,11 +1426,20 @@ function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight
1373
1426
  };
1374
1427
  const pp = block.paragraphProperties;
1375
1428
  const altText = block.altText ?? chart?.title;
1429
+ const bgRes = chart?.frameFillImage ? imageResources?.get(chart.frameFillImage.resource) : void 0;
1430
+ const bgTile = chart?.frameFillImage?.tiled === true && bgRes?.prepared ? {
1431
+ widthPt: bgRes.prepared.widthPx * 72 / 96,
1432
+ heightPt: bgRes.prepared.heightPx * 72 / 96
1433
+ } : void 0;
1376
1434
  return {
1377
1435
  kind: "chart",
1378
1436
  widthPt,
1379
1437
  heightPt,
1380
1438
  layout,
1439
+ ...bgRes ? { background: {
1440
+ resourceName: bgRes.resourceName,
1441
+ ...bgTile ? { tile: bgTile } : {}
1442
+ } } : {},
1381
1443
  resolvedAlignment: pp.alignment ?? "left",
1382
1444
  spacingBeforePt: pp.spacingBefore ?? 0,
1383
1445
  spacingAfterPt: pp.spacingAfter ?? 0,
@@ -1653,6 +1715,7 @@ function collectImageResources(body, headersFooters, options) {
1653
1715
  }
1654
1716
  };
1655
1717
  visit(body);
1718
+ for (const chart of options.charts?.values() ?? []) if (chart.frameFillImage) seen.add(chart.frameFillImage.resource);
1656
1719
  if (options.pageBackgroundFill?.imageResource !== void 0) seen.add(options.pageBackgroundFill.imageResource);
1657
1720
  for (const hf of headersFooters.values()) visit(hf);
1658
1721
  for (const note of options.footnotes?.values() ?? []) visit(note);
@@ -1665,9 +1728,29 @@ function collectImageResources(body, headersFooters, options) {
1665
1728
  if (!bytes) continue;
1666
1729
  if (isEmf(bytes) || isWmf(bytes)) {
1667
1730
  try {
1731
+ const metafile = isEmf(bytes) ? readEmf(bytes) : readWmf(bytes);
1732
+ const metafileImages = [];
1733
+ for (const prim of metafile.prims) {
1734
+ if (prim.kind !== "image") continue;
1735
+ let blitted;
1736
+ try {
1737
+ blitted = prepareImage(prim.png, { flattenAlpha });
1738
+ } catch {
1739
+ metafileImages.push("");
1740
+ continue;
1741
+ }
1742
+ counter++;
1743
+ const name = `Im${counter}`;
1744
+ metafileImages.push(name);
1745
+ out.set(`${resourceId}#${String(metafileImages.length)}`, {
1746
+ resourceName: name,
1747
+ prepared: blitted
1748
+ });
1749
+ }
1668
1750
  out.set(resourceId, {
1669
1751
  resourceName: "",
1670
- metafile: isEmf(bytes) ? readEmf(bytes) : readWmf(bytes)
1752
+ metafile,
1753
+ ...metafileImages.length > 0 ? { metafileImages } : {}
1671
1754
  });
1672
1755
  } catch {}
1673
1756
  continue;
@@ -1688,8 +1771,47 @@ function collectImageResources(body, headersFooters, options) {
1688
1771
  }
1689
1772
  function chartPageItems(laid, x, bottomYUp, pageHeight, structId) {
1690
1773
  const fig = structId !== void 0 ? { structId } : {};
1691
- const out = [];
1692
- for (const sh of laid.layout.shapes) out.push({
1774
+ const ordered = laid.layout.shapes.some((sh) => sh.seq !== void 0) || (laid.layout.images?.length ?? 0) > 0;
1775
+ const picture = ordered ? { pictureId: nextPictureId++ } : {};
1776
+ const backdrop = [];
1777
+ if (laid.background) {
1778
+ const box = {
1779
+ x,
1780
+ y: pageHeight - (bottomYUp + laid.heightPt),
1781
+ width: laid.widthPt,
1782
+ height: laid.heightPt
1783
+ };
1784
+ const tile = laid.background.tile;
1785
+ const clip = {
1786
+ paths: [rectPath(laid.widthPt, laid.heightPt)],
1787
+ transform: flipTransform([
1788
+ 1,
1789
+ 0,
1790
+ 0,
1791
+ 1,
1792
+ x,
1793
+ bottomYUp
1794
+ ], pageHeight)
1795
+ };
1796
+ const items = tile ? PageAssembler.tileItems(laid.background.resourceName, tile, box) : [{
1797
+ type: "image",
1798
+ x: pt(box.x),
1799
+ y: pt(box.y),
1800
+ width: pt(box.width),
1801
+ height: pt(box.height),
1802
+ imageResourceName: laid.background.resourceName
1803
+ }];
1804
+ for (const item of items) {
1805
+ if (item.type !== "image") continue;
1806
+ backdrop.push({
1807
+ ...item,
1808
+ clip,
1809
+ ...fig,
1810
+ ...picture
1811
+ });
1812
+ }
1813
+ }
1814
+ const shapes = laid.layout.shapes.map((sh) => ({
1693
1815
  type: "shape",
1694
1816
  shape: {
1695
1817
  paths: sh.paths,
@@ -1704,18 +1826,41 @@ function chartPageItems(laid, x, bottomYUp, pageHeight, structId) {
1704
1826
  bottomYUp
1705
1827
  ], pageHeight)
1706
1828
  },
1707
- ...fig
1708
- });
1709
- for (const t of laid.layout.texts) out.push({
1829
+ ...fig,
1830
+ ...picture,
1831
+ seq: sh.seq ?? 0
1832
+ }));
1833
+ const texts = laid.layout.texts.map((t) => ({
1710
1834
  type: "line",
1711
1835
  line: t.line,
1712
1836
  originX: pt(x + t.x),
1713
1837
  baselineY: pt(pageHeight - (bottomYUp + t.y)),
1714
1838
  ...t.rotationDeg ? { rotationDeg: t.rotationDeg } : {},
1715
- ...fig
1716
- });
1717
- return out;
1718
- }
1839
+ ...fig,
1840
+ ...picture,
1841
+ seq: t.seq ?? Number.MAX_SAFE_INTEGER
1842
+ }));
1843
+ const blits = (laid.layout.images ?? []).map((img) => ({
1844
+ type: "image",
1845
+ x: pt(x + img.x),
1846
+ y: pt(pageHeight - (bottomYUp + img.y + img.height)),
1847
+ width: pt(img.width),
1848
+ height: pt(img.height),
1849
+ imageResourceName: img.resourceName,
1850
+ ...img.rotationDeg ? { rotationDeg: img.rotationDeg } : {},
1851
+ ...fig,
1852
+ ...picture,
1853
+ seq: img.seq ?? 0
1854
+ }));
1855
+ const all = [
1856
+ ...shapes,
1857
+ ...texts,
1858
+ ...blits
1859
+ ];
1860
+ if (ordered) all.sort((a, b) => a.seq - b.seq);
1861
+ return [...backdrop, ...all.map(({ seq: _seq, ...item }) => item)];
1862
+ }
1863
+ var nextPictureId = 1;
1719
1864
  function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
1720
1865
  if (sh.textLines.length === 0) return;
1721
1866
  if (sh.vertical) {
@@ -1767,10 +1912,11 @@ function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
1767
1912
  }
1768
1913
  return;
1769
1914
  }
1915
+ const indentLeft = line.resolved.indentLeft + (line.firstLine ? line.resolved.indentFirstLine : 0);
1770
1916
  sink.push({
1771
1917
  type: "line",
1772
1918
  line,
1773
- originX: pt(x + sh.insetLeftPt + lineOffset),
1919
+ originX: pt(x + sh.insetLeftPt + indentLeft + lineOffset),
1774
1920
  baselineY: pt(pageHeight - (textY + lineBaselineOffset(line, line.resolved))),
1775
1921
  ...figId !== void 0 ? { structId: figId } : {}
1776
1922
  });
@@ -1806,6 +1952,7 @@ function emitCellFloat(cf, ctx, frame) {
1806
1952
  imageResourceName: cf.block.resourceName,
1807
1953
  ...cf.block.crop ? { crop: cf.block.crop } : {},
1808
1954
  ...cf.block.wash ? { wash: cf.block.wash } : {},
1955
+ ...cf.block.alpha !== void 0 ? { alpha: cf.block.alpha } : {},
1809
1956
  ...cf.block.rotationDeg ? { rotationDeg: cf.block.rotationDeg } : {},
1810
1957
  ...cf.block.flipH ? { flipH: true } : {},
1811
1958
  ...cf.block.flipV ? { flipV: true } : {}
@@ -1832,20 +1979,30 @@ function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
1832
1979
  sink.push({
1833
1980
  ...item,
1834
1981
  clip,
1982
+ ...fig,
1983
+ ...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {}
1984
+ });
1985
+ }
1986
+ else {
1987
+ const r = sh.fillImageRect;
1988
+ const boxX = x + (r ? r.left * sh.widthPt : 0);
1989
+ const boxW = sh.widthPt * (r ? 1 - r.left - r.right : 1);
1990
+ const boxH = sh.heightPt * (r ? 1 - r.top - r.bottom : 1);
1991
+ const boxTop = pageHeight - (bottomYUp + sh.heightPt) + (r ? r.top * sh.heightPt : 0);
1992
+ sink.push({
1993
+ type: "image",
1994
+ x: pt(boxX),
1995
+ y: pt(boxTop),
1996
+ width: pt(boxW),
1997
+ height: pt(boxH),
1998
+ imageResourceName: sh.fillImageResourceName,
1999
+ ...sh.fillImageCrop ? { crop: sh.fillImageCrop } : {},
2000
+ ...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {},
2001
+ ...sh.fillImageDuotone ? { duotone: sh.fillImageDuotone } : {},
2002
+ clip,
1835
2003
  ...fig
1836
2004
  });
1837
2005
  }
1838
- else sink.push({
1839
- type: "image",
1840
- x: pt(x),
1841
- y: pt(pageHeight - (bottomYUp + sh.heightPt)),
1842
- width: pt(sh.widthPt),
1843
- height: pt(sh.heightPt),
1844
- imageResourceName: sh.fillImageResourceName,
1845
- ...sh.fillImageCrop ? { crop: sh.fillImageCrop } : {},
1846
- clip,
1847
- ...fig
1848
- });
1849
2006
  }
1850
2007
  if (sh.markerPaths && sh.stroke) sink.push({
1851
2008
  type: "shape",
@@ -1982,6 +2139,7 @@ function drawBlocksSequentially(blocks, startX, startY, pageHeight, contentWidth
1982
2139
  imageResourceName: block.resourceName,
1983
2140
  ...block.crop ? { crop: block.crop } : {},
1984
2141
  ...block.wash ? { wash: block.wash } : {},
2142
+ ...block.alpha !== void 0 ? { alpha: block.alpha } : {},
1985
2143
  ...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
1986
2144
  ...block.flipH ? { flipH: true } : {},
1987
2145
  ...block.flipV ? { flipV: true } : {}
@@ -2080,24 +2238,197 @@ function runFontKeyAndParsed(options, ascii, bold, italic) {
2080
2238
  }
2081
2239
  const byFamily = options.registriesByFamily;
2082
2240
  if (byFamily && byFamily.size > 0) {
2083
- let key = resolveFamilyKey(ascii);
2241
+ const named = resolveFamilyStyle(ascii);
2242
+ let key = named.key;
2084
2243
  let reg = byFamily.get(key);
2085
2244
  if (!reg) {
2086
2245
  key = byFamily.keys().next().value;
2087
2246
  reg = byFamily.get(key);
2088
2247
  }
2089
- const { variant, parsed } = reg.resolveByStyle(bold, italic);
2248
+ const wantBold = bold || named.bold === true;
2249
+ const wantItalic = italic || named.italic === true;
2250
+ const { variant, parsed } = reg.resolveByStyle(wantBold, wantItalic);
2090
2251
  return {
2091
2252
  fontKey: `${key}:${variant}`,
2092
- parsed
2253
+ parsed,
2254
+ ...syntheticFace(variant, wantBold, wantItalic, named.widthScale)
2093
2255
  };
2094
2256
  }
2095
2257
  const { variant, parsed } = options.registry.resolveByStyle(bold, italic);
2096
2258
  return {
2097
2259
  fontKey: variant,
2098
- parsed
2260
+ parsed,
2261
+ ...syntheticFace(variant, bold, italic, resolveFamilyStyle(ascii).widthScale)
2262
+ };
2263
+ }
2264
+ /**
2265
+ * The face a CHARACTER falls back to when the run's own has no glyph for it.
2266
+ *
2267
+ * The curated substitutes are Latin families: Han, Kana, Hangul, Arabic, Thai
2268
+ * and the geometric symbols are a notdef box in every one of them, and 2145
2269
+ * characters of the corpus are exactly those. A face for the character's
2270
+ * writing system is fetched when the document holds one (see `addScriptFonts`),
2271
+ * and this is where a run reaches it — followed by every other family already
2272
+ * loaded, because a glyph one of them happens to carry is still better than a
2273
+ * box.
2274
+ *
2275
+ * Called from BOTH walks that need it — the glyph-subset collection and the
2276
+ * tokenizer — so the face a character is measured, subset and drawn with is one
2277
+ * decision made once.
2278
+ *
2279
+ * @param options The render options (the loaded registries).
2280
+ * @param cp The code point with no glyph in the run's own face.
2281
+ * @param bold Whether the run is bold…
2282
+ * @param italic …and whether it is italic.
2283
+ * @returns The face to draw it with, or `undefined` when nobody has it.
2284
+ */
2285
+ function fallbackFaceKey(options, cp, bold, italic) {
2286
+ const byFamily = options.registriesByFamily;
2287
+ if (!byFamily || byFamily.size === 0) return void 0;
2288
+ const script = scriptForCodepoint(cp, byFamily.has("jp") ? "jp" : byFamily.has("kr") ? "kr" : "sc");
2289
+ const order = script ? [script] : [];
2290
+ for (const key of byFamily.keys()) if (key !== script) order.push(key);
2291
+ for (const key of order) {
2292
+ const reg = byFamily.get(key);
2293
+ if (!reg) continue;
2294
+ const { variant, parsed } = reg.resolveByStyle(bold, italic);
2295
+ if (parsed.glyphForCodepoint(cp) !== 0) return {
2296
+ fontKey: `${key}:${variant}`,
2297
+ parsed
2298
+ };
2299
+ }
2300
+ }
2301
+ /**
2302
+ * §9.2.2 — the face a request had to settle for, and what is left to draw.
2303
+ *
2304
+ * A registry may hold one face and be asked for four: `FontBytesByVariant`
2305
+ * requires only `regular`, so a caller who supplies a single file (or a script
2306
+ * fallback with no bold cut) had every heading drawn plain. What the file does
2307
+ * not carry, the page draws: a stroke around the glyphs for weight, a shear for
2308
+ * slant — the same two tricks a word processor calls faux bold and faux italic.
2309
+ *
2310
+ * @param variant The face the registry actually gave.
2311
+ * @param bold Whether bold was asked for.
2312
+ * @param italic Whether italic was.
2313
+ * @param widthScale The squeeze a condensed NAME asks for, when it does.
2314
+ * @returns `{ synthetic }` when something is missing, `{}` when nothing is.
2315
+ */
2316
+ function syntheticFace(variant, bold, italic, widthScale) {
2317
+ const missingBold = bold && variant !== "bold" && variant !== "boldItalic";
2318
+ const missingItalic = italic && variant !== "italic" && variant !== "boldItalic";
2319
+ if (!missingBold && !missingItalic && widthScale === void 0) return {};
2320
+ return { synthetic: {
2321
+ ...missingBold ? { bold: true } : {},
2322
+ ...missingItalic ? { italic: true } : {},
2323
+ ...widthScale !== void 0 ? { widthScale } : {}
2324
+ } };
2325
+ }
2326
+ /**
2327
+ * `text` cut into the stretches ONE face draws — the whole string as a single
2328
+ * piece when the run's own face covers it, which is nearly always.
2329
+ *
2330
+ * @param plan The run being tokenized.
2331
+ * @param text The stretch of it to cut.
2332
+ */
2333
+ function splitByFace(plan, text) {
2334
+ const first = faceOf(plan, text.codePointAt(0) ?? 0);
2335
+ if (!plan.faceFor || plan.faceFor.size === 0) return [{
2336
+ text,
2337
+ face: first
2338
+ }];
2339
+ const out = [];
2340
+ let buf = "";
2341
+ let face = first;
2342
+ for (const ch of text) {
2343
+ const next = faceOf(plan, ch.codePointAt(0));
2344
+ if (buf !== "" && next.font !== face.font) {
2345
+ out.push({
2346
+ text: buf,
2347
+ face
2348
+ });
2349
+ buf = "";
2350
+ }
2351
+ face = next;
2352
+ buf += ch;
2353
+ }
2354
+ if (buf !== "") out.push({
2355
+ text: buf,
2356
+ face
2357
+ });
2358
+ return out;
2359
+ }
2360
+ /**
2361
+ * The face a character of a run is drawn with — its own, unless the run carries
2362
+ * a fallback for that code point (see {@link facesForRun}).
2363
+ */
2364
+ function faceOf(plan, cp) {
2365
+ return plan.faceFor?.get(cp) ?? {
2366
+ font: plan.font,
2367
+ ...plan.synthetic ? { synthetic: plan.synthetic } : {}
2099
2368
  };
2100
2369
  }
2370
+ /**
2371
+ * `text` cut into the stretches ONE face draws, by the same decision the
2372
+ * tokenizer makes — the whole string as a single span when the run's own face
2373
+ * covers it, which is nearly always.
2374
+ *
2375
+ * @param options The render options (the loaded registries).
2376
+ * @param primary The run's own face.
2377
+ * @param resolved Its resolved properties (weight and slant).
2378
+ * @param text The run's text.
2379
+ */
2380
+ function faceSpans(options, primary, resolved, text) {
2381
+ const out = [];
2382
+ let cur = primary;
2383
+ let buf = "";
2384
+ for (const ch of text) {
2385
+ const cp = ch.codePointAt(0);
2386
+ const face = primary.parsed.glyphForCodepoint(cp) !== 0 ? primary : fallbackFaceKey(options, cp, resolved.bold, resolved.italic) ?? primary;
2387
+ if (buf !== "" && face.fontKey !== cur.fontKey) {
2388
+ out.push({
2389
+ ...cur,
2390
+ text: buf
2391
+ });
2392
+ buf = "";
2393
+ }
2394
+ cur = face;
2395
+ buf += ch;
2396
+ }
2397
+ if (buf !== "") out.push({
2398
+ ...cur,
2399
+ text: buf
2400
+ });
2401
+ return out;
2402
+ }
2403
+ /**
2404
+ * The face for every character of `text` the run's own cannot draw.
2405
+ *
2406
+ * @param options The render options (the loaded registries).
2407
+ * @param fontResources The faces the document embeds, by key.
2408
+ * @param primary The run's own face.
2409
+ * @param resolved Its resolved properties (weight and slant).
2410
+ * @param text The run's text.
2411
+ * @returns A map from code point to face, or `undefined` when the run's own
2412
+ * face draws all of it.
2413
+ */
2414
+ function facesForRun(options, fontResources, primary, resolved, text) {
2415
+ let out;
2416
+ for (const ch of text) {
2417
+ const cp = ch.codePointAt(0);
2418
+ if (out?.has(cp) === true || primary.glyphForCodepoint(cp) !== 0) continue;
2419
+ const fallback = fallbackFaceKey(options, cp, resolved.bold, resolved.italic);
2420
+ if (!fallback) continue;
2421
+ const font = fontResources.get(fallback.fontKey);
2422
+ if (!font) continue;
2423
+ out ??= /* @__PURE__ */ new Map();
2424
+ const { variant } = { variant: fallback.fontKey.split(":")[1] ?? "" };
2425
+ out.set(cp, {
2426
+ font,
2427
+ ...syntheticFace(variant === "bold" || variant === "boldItalic" || variant === "italic" ? variant : "regular", resolved.bold, resolved.italic)
2428
+ });
2429
+ }
2430
+ return out;
2431
+ }
2101
2432
  function lookupFont(resources, fontKey) {
2102
2433
  return resources.get(fontKey) ?? resources.values().next().value;
2103
2434
  }
@@ -2114,8 +2445,22 @@ function collectFontResources(body, headersFooters, options, imageResources) {
2114
2445
  };
2115
2446
  used.set(fontKey, bucket);
2116
2447
  }
2117
- const shaped = shapeText(run.text, parsed.glyphForCodepoint, parsed.advanceWidths, parsed.ligatures, parsed.kerning, parsed.joiningForms);
2118
- for (const g of shaped.gids) bucket.gids.add(g);
2448
+ const text = run.listMarker === true ? markerText(run.text, parsed) : run.text;
2449
+ for (const span of faceSpans(options, {
2450
+ fontKey,
2451
+ parsed
2452
+ }, resolved, text)) {
2453
+ let sink = used.get(span.fontKey);
2454
+ if (!sink) {
2455
+ sink = {
2456
+ parsed: span.parsed,
2457
+ gids: /* @__PURE__ */ new Set()
2458
+ };
2459
+ used.set(span.fontKey, sink);
2460
+ }
2461
+ const shaped = shapeText(span.text, span.parsed.glyphForCodepoint, span.parsed.advanceWidths, span.parsed.ligatures, span.parsed.kerning, span.parsed.joiningForms);
2462
+ for (const g of shaped.gids) sink.gids.add(g);
2463
+ }
2119
2464
  if (run.text.includes(" ")) for (const stop of resolveParagraphProperties(para.properties, options.styles).tabs) {
2120
2465
  const ch = stop.leader === void 0 ? void 0 : TAB_LEADER_CHARS.get(stop.leader);
2121
2466
  if (ch !== void 0) bucket.gids.add(parsed.glyphForCodepoint(ch.codePointAt(0)));
@@ -2485,7 +2830,7 @@ function tokenizeParagraph(paragraph, options, fontResources, imageResources, co
2485
2830
  imageWidthPt: widthPt,
2486
2831
  imageHeightPt: heightPt,
2487
2832
  imageResourceName: res?.resourceName ?? "",
2488
- ...res?.metafile ? { imageMetafile: metafileDrawing(res.metafile, drawBox?.widthPt ?? widthPt, drawBox?.heightPt ?? heightPt, options, fontResources) } : {},
2833
+ ...res?.metafile ? { imageMetafile: metafileDrawing(res.metafile, drawBox?.widthPt ?? widthPt, drawBox?.heightPt ?? heightPt, options, fontResources, void 0, res.metafileImages) } : {},
2489
2834
  ...run.inlineImage.outline ? { imageOutline: run.inlineImage.outline } : {},
2490
2835
  ...run.inlineImage.shadow ? { imageShadow: run.inlineImage.shadow } : {},
2491
2836
  ...run.inlineImage.wash ? { imageWash: run.inlineImage.wash } : {},
@@ -2525,12 +2870,16 @@ function tokenizeParagraph(paragraph, options, fontResources, imageResources, co
2525
2870
  };
2526
2871
  }
2527
2872
  const resolvedRun = resolveRunProperties(run.properties, paragraph.properties, options.styles);
2528
- const { fontKey } = runFontKeyAndParsed(options, resolvedRun.fontFamily.ascii, resolvedRun.bold, resolvedRun.italic);
2873
+ const { fontKey, synthetic } = runFontKeyAndParsed(options, resolvedRun.fontFamily.ascii, resolvedRun.bold, resolvedRun.italic);
2529
2874
  const script = SCRIPT_OFFSET[resolvedRun.verticalAlign] ?? 0;
2875
+ const own = lookupFont(fontResources, fontKey);
2876
+ const faceFor = facesForRun(options, fontResources, own.parsed, resolvedRun, run.text);
2530
2877
  return {
2531
2878
  run,
2532
2879
  resolvedRun,
2533
- font: lookupFont(fontResources, fontKey),
2880
+ font: own,
2881
+ ...faceFor ? { faceFor } : {},
2882
+ ...synthetic ? { synthetic } : {},
2534
2883
  fontSizePt: script === 0 ? resolvedRun.fontSizePt : resolvedRun.fontSizePt * SCRIPT_SCALE,
2535
2884
  ...script === 0 ? {} : { risePt: resolvedRun.fontSizePt * script },
2536
2885
  isImage: false,
@@ -2597,28 +2946,56 @@ function tokenizePlansLtr(plans) {
2597
2946
  continue;
2598
2947
  }
2599
2948
  const highlight = (plan.run.commentRangeRefs?.length ?? 0) > 0;
2600
- for (const t of tokenizeText(plan.run.text)) tokens.push({
2601
- kind: "text",
2602
- text: t.text,
2603
- isSpace: t.isSpace,
2604
- ...t.tab ? { tab: true } : {},
2605
- ...plan.run.href !== void 0 ? { href: plan.run.href } : {},
2606
- ...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
2607
- ...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
2608
- ...plan.run.listMarker ? { listMarker: true } : {},
2609
- ...plan.run.columnBreak ? { columnBreak: true } : {},
2610
- ...highlight ? { highlight: true } : {},
2611
- resolvedRun: plan.resolvedRun,
2612
- font: plan.font,
2613
- fontSizePt: plan.fontSizePt,
2614
- ...plan.risePt !== void 0 ? { risePt: plan.risePt } : {},
2615
- widthPt: measureRunText(plan, t.text),
2616
- bidiLevel: 0
2617
- });
2949
+ for (const t of tokenizeText(plan.run.text)) for (const piece of splitByFace(plan, t.text)) {
2950
+ const text = plan.run.listMarker === true ? markerText(piece.text, plan.font.parsed) : piece.text;
2951
+ tokens.push({
2952
+ kind: "text",
2953
+ text,
2954
+ isSpace: t.isSpace,
2955
+ ...t.tab ? { tab: true } : {},
2956
+ ...plan.run.href !== void 0 ? { href: plan.run.href } : {},
2957
+ ...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
2958
+ ...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
2959
+ ...plan.run.listMarker ? { listMarker: true } : {},
2960
+ ...plan.run.columnBreak ? { columnBreak: true } : {},
2961
+ ...highlight ? { highlight: true } : {},
2962
+ resolvedRun: plan.resolvedRun,
2963
+ font: piece.face.font,
2964
+ ...piece.face.synthetic ? { synthetic: piece.face.synthetic } : {},
2965
+ fontSizePt: plan.fontSizePt,
2966
+ ...plan.risePt !== void 0 ? { risePt: plan.risePt } : {},
2967
+ widthPt: measureRunText(plan, text, piece.face),
2968
+ bidiLevel: 0
2969
+ });
2970
+ }
2618
2971
  }
2619
2972
  return tokens;
2620
2973
  }
2621
2974
  /**
2975
+ * A LIST MARKER the font has no glyph for, swapped for the dot every text font
2976
+ * carries.
2977
+ *
2978
+ * §21.1.2.4.5 — a bullet is stated in a face of its own, and the symbol faces
2979
+ * are not alphabets: Wingdings `l` is a filled circle, U+25CF once translated.
2980
+ * The font a document is RENDERED with may have no such character — Roboto does
2981
+ * not — and a missing glyph is a box: 45541_Header wore a row of them down
2982
+ * eleven slides. The marker is the one place where the shape matters more than
2983
+ * the code point, so it takes the nearest thing the font can draw.
2984
+ *
2985
+ * @param text The marker's text.
2986
+ * @param font The font it is set in.
2987
+ * @returns The text to draw.
2988
+ */
2989
+ function markerText(text, parsed) {
2990
+ let out = "";
2991
+ for (const ch of text) {
2992
+ const cp = ch.codePointAt(0) ?? 0;
2993
+ const missing = cp > 127 && parsed.glyphForCodepoint(cp) === 0;
2994
+ out += missing && parsed.glyphForCodepoint(8226) !== 0 ? "•" : ch;
2995
+ }
2996
+ return out;
2997
+ }
2998
+ /**
2622
2999
  * §17.3.2.35 — a run's text measured with the space it puts between its
2623
3000
  * characters. PDF adds the same amount per glyph through `Tc`, so the width the
2624
3001
  * line is broken at and the width the page draws agree.
@@ -2627,8 +3004,12 @@ function tokenizePlansLtr(plans) {
2627
3004
  * @param text The token's text.
2628
3005
  * @returns The advance width in points.
2629
3006
  */
2630
- function measureRunText(plan, text) {
2631
- const base = plan.font.measure.textWidthPt(text, plan.fontSizePt);
3007
+ function measureRunText(plan, text, face) {
3008
+ const drawn = face ?? {
3009
+ font: plan.font,
3010
+ ...plan.synthetic ? { synthetic: plan.synthetic } : {}
3011
+ };
3012
+ const base = drawn.font.measure.textWidthPt(text, plan.fontSizePt) * (drawn.synthetic?.widthScale ?? 1);
2632
3013
  const extra = plan.resolvedRun.letterSpacingPt;
2633
3014
  return extra === void 0 || extra === 0 ? base : base + extra * [...text].length;
2634
3015
  }
@@ -2675,9 +3056,11 @@ function tokenizePlansBidi(plans, realLevels) {
2675
3056
  let bufStart = 0;
2676
3057
  let curSpace = false;
2677
3058
  let curLevel = -1;
3059
+ let curFace = { font: plan.font };
2678
3060
  const flush = (endExclusive) => {
2679
3061
  if (endExclusive <= bufStart) return;
2680
- const text = chars.slice(bufStart, endExclusive).join("");
3062
+ const raw = chars.slice(bufStart, endExclusive).join("");
3063
+ const text = plan.run.listMarker === true ? markerText(raw, plan.font.parsed) : raw;
2681
3064
  tokens.push({
2682
3065
  kind: "text",
2683
3066
  text,
@@ -2689,10 +3072,11 @@ function tokenizePlansBidi(plans, realLevels) {
2689
3072
  ...plan.run.columnBreak ? { columnBreak: true } : {},
2690
3073
  ...(plan.run.commentRangeRefs?.length ?? 0) > 0 ? { highlight: true } : {},
2691
3074
  resolvedRun: plan.resolvedRun,
2692
- font: plan.font,
3075
+ font: curFace.font,
3076
+ ...curFace.synthetic ? { synthetic: curFace.synthetic } : {},
2693
3077
  fontSizePt: plan.fontSizePt,
2694
3078
  ...plan.risePt !== void 0 ? { risePt: plan.risePt } : {},
2695
- widthPt: measureRunText(plan, text),
3079
+ widthPt: measureRunText(plan, text, curFace),
2696
3080
  bidiLevel: curLevel
2697
3081
  });
2698
3082
  };
@@ -2700,14 +3084,17 @@ function tokenizePlansBidi(plans, realLevels) {
2700
3084
  const ch = chars[c];
2701
3085
  const isSpace = /\s/.test(ch);
2702
3086
  const level = realLevels[realIdx] ?? 0;
3087
+ const face = faceOf(plan, ch.codePointAt(0));
2703
3088
  if (c === 0) {
2704
3089
  curSpace = isSpace;
2705
3090
  curLevel = level;
2706
- } else if (isSpace !== curSpace || level !== curLevel) {
3091
+ curFace = face;
3092
+ } else if (isSpace !== curSpace || level !== curLevel || face.font !== curFace.font) {
2707
3093
  flush(c);
2708
3094
  bufStart = c;
2709
3095
  curSpace = isSpace;
2710
3096
  curLevel = level;
3097
+ curFace = face;
2711
3098
  }
2712
3099
  realIdx++;
2713
3100
  }
@@ -3535,10 +3922,10 @@ function measureSingleLine(paragraph, options, fontResources) {
3535
3922
  let total = 0;
3536
3923
  for (const run of paragraph.runs) {
3537
3924
  const resolved = resolveRunProperties(run.properties, paragraph.properties, options.styles);
3538
- const { fontKey } = runFontKeyAndParsed(options, resolved.fontFamily.ascii, resolved.bold, resolved.italic);
3925
+ const { fontKey, synthetic } = runFontKeyAndParsed(options, resolved.fontFamily.ascii, resolved.bold, resolved.italic);
3539
3926
  const font = lookupFont(fontResources, fontKey);
3540
3927
  const fontSizePt = resolved.fontSizePt;
3541
- total += font.measure.textWidthPt(run.text, fontSizePt);
3928
+ total += font.measure.textWidthPt(run.text, fontSizePt) * (synthetic?.widthScale ?? 1);
3542
3929
  }
3543
3930
  return total;
3544
3931
  }
@@ -4328,7 +4715,10 @@ var PageAssembler = class PageAssembler {
4328
4715
  ...this.pageBorderItems(),
4329
4716
  ...this.columnSeparatorItems(),
4330
4717
  ...header.commands,
4331
- ...PageAssembler.byZ(this.floatsBehind),
4718
+ ...PageAssembler.byZ(this.floatsBehind).map((item) => ({
4719
+ ...item,
4720
+ behind: true
4721
+ })),
4332
4722
  ...this.current,
4333
4723
  ...PageAssembler.byZ(this.floatsFront),
4334
4724
  ...this.renderNotesBand(),
@@ -4701,6 +5091,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
4701
5091
  imageResourceName: block.resourceName,
4702
5092
  ...block.crop ? { crop: block.crop } : {},
4703
5093
  ...block.wash ? { wash: block.wash } : {},
5094
+ ...block.alpha !== void 0 ? { alpha: block.alpha } : {},
4704
5095
  ...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
4705
5096
  ...block.flipH ? { flipH: true } : {},
4706
5097
  ...block.flipV ? { flipV: true } : {},