@shadow-garden/bapbong-layout-engine 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,9 +2,21 @@
2
2
  import {
3
3
  createNumberingCounter
4
4
  } from "@shadow-garden/bapbong-model";
5
- var DEFAULT_FONT = { family: "Arial", sizePt: 11, bold: false, italic: false };
5
+ var DEFAULT_FONT = {
6
+ family: "Arial",
7
+ sizePt: 11,
8
+ bold: false,
9
+ italic: false
10
+ };
6
11
  var PT_TO_PX = 96 / 72;
7
- var HEADING_PT = { 1: 24, 2: 18, 3: 14, 4: 12, 5: 11, 6: 11 };
12
+ var HEADING_PT = {
13
+ 1: 24,
14
+ 2: 18,
15
+ 3: 14,
16
+ 4: 12,
17
+ 5: 11,
18
+ 6: 11
19
+ };
8
20
  var LINE_HEIGHT_FACTOR = 1.2;
9
21
  var BASELINE_FACTOR = 0.8;
10
22
  var DEFAULT_TAB_WIDTH = 48;
@@ -80,11 +92,13 @@ function resolveImage(node, pos) {
80
92
  function paragraphToFlow(node, base, nodePos, allowFloats = false, marker) {
81
93
  const contentStart = nodePos + 1;
82
94
  const headingLevel = node.attrs["heading"];
83
- const runBase = headingLevel ? { ...base, sizePt: HEADING_PT[headingLevel] ?? base.sizePt, bold: true } : base;
95
+ const styleId = node.attrs["styleId"];
96
+ const runBase = headingLevel ? { ...base, sizePt: HEADING_PT[headingLevel] ?? base.sizePt, bold: true } : styleId === "Title" ? { ...base, sizePt: 28 } : styleId === "Subtitle" ? { ...base, sizePt: 14, italic: true } : base;
84
97
  const runs = [];
85
98
  const floats = [];
86
99
  node.forEach((child, offset) => {
87
- if (child.isText) runs.push(resolveRun(child, runBase, contentStart + offset));
100
+ if (child.isText)
101
+ runs.push(resolveRun(child, runBase, contentStart + offset));
88
102
  else if (child.type.name === "image") {
89
103
  const float = child.attrs["float"];
90
104
  if (float && allowFloats) {
@@ -111,7 +125,8 @@ function paragraphToFlow(node, base, nodePos, allowFloats = false, marker) {
111
125
  }
112
126
  } else if (child.type.name === "page_field")
113
127
  runs.push(resolveField(child, runBase, contentStart + offset));
114
- else if (child.type.name === "hard_break") runs.push({ break: true, pos: contentStart + offset });
128
+ else if (child.type.name === "hard_break")
129
+ runs.push({ break: true, pos: contentStart + offset });
115
130
  });
116
131
  const list = node.attrs["list"];
117
132
  const align = node.attrs["align"];
@@ -147,8 +162,15 @@ function markerFor(node, counter) {
147
162
  }
148
163
  function nodeToBlock(node, base, nodePos, allowFloats = false, counter) {
149
164
  if (node.type.name === "paragraph")
150
- return paragraphToFlow(node, base, nodePos, allowFloats, markerFor(node, counter));
151
- if (node.type.name === "table") return tableToFlow(node, base, nodePos, counter);
165
+ return paragraphToFlow(
166
+ node,
167
+ base,
168
+ nodePos,
169
+ allowFloats,
170
+ markerFor(node, counter)
171
+ );
172
+ if (node.type.name === "table")
173
+ return tableToFlow(node, base, nodePos, counter);
152
174
  return null;
153
175
  }
154
176
  function tableToFlow(node, base, nodePos, counter) {
@@ -160,7 +182,13 @@ function tableToFlow(node, base, nodePos, counter) {
160
182
  const cellPos = rowPos + 1 + cellOffset;
161
183
  const content = [];
162
184
  cellNode.forEach((child, childOffset) => {
163
- const block = nodeToBlock(child, base, cellPos + 1 + childOffset, true, counter);
185
+ const block = nodeToBlock(
186
+ child,
187
+ base,
188
+ cellPos + 1 + childOffset,
189
+ true,
190
+ counter
191
+ );
164
192
  if (block) content.push(block);
165
193
  });
166
194
  const a = cellNode.attrs;
@@ -192,7 +220,9 @@ function tableToFlow(node, base, nodePos, counter) {
192
220
  }
193
221
  function toFlowBlocks(doc, defaultFont = {}, allowFloats = true) {
194
222
  const base = { ...DEFAULT_FONT, ...defaultFont };
195
- const counter = createNumberingCounter(doc.attrs["numbering"]);
223
+ const counter = createNumberingCounter(
224
+ doc.attrs["numbering"]
225
+ );
196
226
  const blocks = [];
197
227
  doc.forEach((node, offset) => {
198
228
  const block = nodeToBlock(node, base, offset, allowFloats, counter);
@@ -202,7 +232,16 @@ function toFlowBlocks(doc, defaultFont = {}, allowFloats = true) {
202
232
  }
203
233
  function tokenizeInline(inline, ctx) {
204
234
  if ("break" in inline) {
205
- return [{ isBreak: true, font: ctx.base, width: 0, isSpace: false, pos: inline.pos, size: 1 }];
235
+ return [
236
+ {
237
+ isBreak: true,
238
+ font: ctx.base,
239
+ width: 0,
240
+ isSpace: false,
241
+ pos: inline.pos,
242
+ size: 1
243
+ }
244
+ ];
206
245
  }
207
246
  if ("src" in inline) {
208
247
  return [
@@ -313,7 +352,12 @@ function wrapParagraph(block, ctx, bandFn, emit) {
313
352
  return lineLeft + k * tabWidth - x;
314
353
  };
315
354
  const tabStops = block.tabs ? [...block.tabs].sort((a, b) => a.pos - b.pos) : [];
316
- const LEADER_CHARS = { dot: ".", hyphen: "-", underscore: "_", middleDot: "\xB7" };
355
+ const LEADER_CHARS = {
356
+ dot: ".",
357
+ hyphen: "-",
358
+ underscore: "_",
359
+ middleDot: "\xB7"
360
+ };
317
361
  const MIN_TAB = 2;
318
362
  const tabGroup = (ti) => {
319
363
  let width = 0;
@@ -323,7 +367,8 @@ function wrapParagraph(block, ctx, bandFn, emit) {
323
367
  if (t.isTab) break;
324
368
  if (decimalPrefix === null && t.text != null && !t.field) {
325
369
  const m = /[.,]/.exec(t.text);
326
- if (m) decimalPrefix = width + measure(t.text.slice(0, m.index), t.font);
370
+ if (m)
371
+ decimalPrefix = width + measure(t.text.slice(0, m.index), t.font);
327
372
  }
328
373
  width += t.width;
329
374
  }
@@ -446,7 +491,16 @@ function wrapParagraph(block, ctx, bandFn, emit) {
446
491
  height = target;
447
492
  }
448
493
  const painted = firstLine && marker ? [marker, ...segments] : segments;
449
- emit({ x: startX, width: lineRight - startX, height, baseline, segments: painted, images, from, to });
494
+ emit({
495
+ x: startX,
496
+ width: lineRight - startX,
497
+ height,
498
+ baseline,
499
+ segments: painted,
500
+ images,
501
+ from,
502
+ to
503
+ });
450
504
  prevTo = to;
451
505
  lineTokens = [];
452
506
  lineWidth = 0;
@@ -480,10 +534,14 @@ function wrapParagraph(block, ctx, bandFn, emit) {
480
534
  softWrapped = false;
481
535
  continue;
482
536
  }
483
- if (token.isSpace && !token.isTab && lineTokens.length === 0 && softWrapped) continue;
537
+ if (token.isSpace && !token.isTab && lineTokens.length === 0 && softWrapped)
538
+ continue;
484
539
  if (token.isTab) resolveTab(token, lineStart() + lineWidth, ti);
485
540
  if (clusterable(token) && clusterFont && sameFont(clusterFont, token.font)) {
486
- token.width = Math.max(0, measure(clusterText + token.text, token.font) - clusterWidth);
541
+ token.width = Math.max(
542
+ 0,
543
+ measure(clusterText + token.text, token.font) - clusterWidth
544
+ );
487
545
  }
488
546
  const cursor = lineStart() + lineWidth;
489
547
  if (!token.isSpace && lineTokens.length > 0 && cursor + token.width > lineRight) {
@@ -491,14 +549,21 @@ function wrapParagraph(block, ctx, bandFn, emit) {
491
549
  resetCluster();
492
550
  softWrapped = true;
493
551
  if (token.isTab) resolveTab(token, lineStart() + lineWidth, ti);
494
- else if (clusterable(token)) token.width = measure(token.text, token.font);
552
+ else if (clusterable(token))
553
+ token.width = measure(token.text, token.font);
495
554
  }
496
555
  if (clusterable(token) && lineTokens.length === 0 && token.text.length > 1 && lineStart() + token.width > lineRight) {
497
556
  const avail = lineRight - lineStart();
498
557
  let n = 1;
499
- while (n < token.text.length && measure(token.text.slice(0, n + 1), token.font) <= avail) n++;
558
+ while (n < token.text.length && measure(token.text.slice(0, n + 1), token.font) <= avail)
559
+ n++;
500
560
  const restText = token.text.slice(n);
501
- const rest = { ...token, text: restText, width: measure(restText, token.font), size: restText.length };
561
+ const rest = {
562
+ ...token,
563
+ text: restText,
564
+ width: measure(restText, token.font),
565
+ size: restText.length
566
+ };
502
567
  if (token.pos != null) rest.pos = token.pos + n;
503
568
  token.text = token.text.slice(0, n);
504
569
  token.size = n;
@@ -519,7 +584,10 @@ function wrapParagraph(block, ctx, bandFn, emit) {
519
584
  const rotH = rotatedBoxHeight(token.image);
520
585
  maxImagePx = Math.max(maxImagePx, rotH);
521
586
  maxAscent = Math.max(maxAscent, token.image.height / 2 + rotH / 2);
522
- maxDescent = Math.max(maxDescent, Math.max(0, (rotH - token.image.height) / 2));
587
+ maxDescent = Math.max(
588
+ maxDescent,
589
+ Math.max(0, (rotH - token.image.height) / 2)
590
+ );
523
591
  } else {
524
592
  maxFontPx = Math.max(maxFontPx, sizePx(token.font));
525
593
  if (metrics) {
@@ -572,7 +640,13 @@ function shiftTableX(table, dx) {
572
640
  }
573
641
  var TEXTBOX_INSET = { l: 10, t: 5, r: 10, b: 5 };
574
642
  function resolveFloat(f, x, y, ctx) {
575
- const rf = { x, y, width: f.width, height: f.height, src: f.src };
643
+ const rf = {
644
+ x,
645
+ y,
646
+ width: f.width,
647
+ height: f.height,
648
+ src: f.src
649
+ };
576
650
  if (f.pos != null) rf.pos = f.pos;
577
651
  if (f.rotation) rf.rotation = f.rotation;
578
652
  if (f.shape) rf.shape = f.shape;
@@ -618,7 +692,8 @@ function eachCell(rows, ncols, visit) {
618
692
  for (const cell of rows[r].cells) {
619
693
  while (col < ncols && spanned[col] > 0) col++;
620
694
  visit(r, cell, col);
621
- for (let k = 0; k < cell.colspan && col + k < ncols; k++) spanned[col + k] = cell.rowspan;
695
+ for (let k = 0; k < cell.colspan && col + k < ncols; k++)
696
+ spanned[col + k] = cell.rowspan;
622
697
  col += cell.colspan;
623
698
  }
624
699
  for (let i = 0; i < ncols; i++) if (spanned[i] > 0) spanned[i]--;
@@ -628,14 +703,18 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
628
703
  const avail = contentRight - contentLeft;
629
704
  const nrows = table.rows.length;
630
705
  const ncols = table.rows.reduce(
631
- (m, r) => Math.max(m, r.cells.reduce((s, c) => s + c.colspan, 0)),
706
+ (m, r) => Math.max(
707
+ m,
708
+ r.cells.reduce((s, c) => s + c.colspan, 0)
709
+ ),
632
710
  0
633
711
  );
634
712
  const colWidths = new Array(ncols).fill(0);
635
713
  eachCell(table.rows, ncols, (_r, cell, startCol) => {
636
714
  if (cell.colwidth && cell.colwidth.length === cell.colspan) {
637
715
  for (let k = 0; k < cell.colspan && startCol + k < ncols; k++) {
638
- if (colWidths[startCol + k] === 0) colWidths[startCol + k] = cell.colwidth[k];
716
+ if (colWidths[startCol + k] === 0)
717
+ colWidths[startCol + k] = cell.colwidth[k];
639
718
  }
640
719
  }
641
720
  });
@@ -643,7 +722,8 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
643
722
  const unknown = colWidths.filter((w) => w === 0).length;
644
723
  if (unknown > 0) {
645
724
  const share = Math.max(0, (avail - known) / unknown);
646
- for (let i = 0; i < ncols; i++) if (colWidths[i] === 0) colWidths[i] = share;
725
+ for (let i = 0; i < ncols; i++)
726
+ if (colWidths[i] === 0) colWidths[i] = share;
647
727
  }
648
728
  const natural = colWidths.reduce((s, w) => s + w, 0);
649
729
  if (natural > avail && natural > 0) {
@@ -663,9 +743,15 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
663
743
  const cellDrafts = [];
664
744
  eachCell(table.rows, ncols, (r, cell, col) => {
665
745
  let cellWidth = 0;
666
- for (let k = 0; k < cell.colspan && col + k < ncols; k++) cellWidth += colWidths[col + k];
746
+ for (let k = 0; k < cell.colspan && col + k < ncols; k++)
747
+ cellWidth += colWidths[col + k];
667
748
  const cellLeft = colX[col];
668
- const flow = layoutFlow(cell.content, cellLeft + pad.left, cellLeft + cellWidth - pad.right, ctx);
749
+ const flow = layoutFlow(
750
+ cell.content,
751
+ cellLeft + pad.left,
752
+ cellLeft + cellWidth - pad.right,
753
+ ctx
754
+ );
669
755
  cellDrafts.push({
670
756
  startRow: r,
671
757
  startCol: col,
@@ -685,14 +771,18 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
685
771
  const rowHeight = new Array(nrows).fill(0);
686
772
  for (const c of cellDrafts) {
687
773
  if (c.rowspan === 1) {
688
- rowHeight[c.startRow] = Math.max(rowHeight[c.startRow], c.contentHeight + pad.top + pad.bottom);
774
+ rowHeight[c.startRow] = Math.max(
775
+ rowHeight[c.startRow],
776
+ c.contentHeight + pad.top + pad.bottom
777
+ );
689
778
  }
690
779
  }
691
780
  for (const c of cellDrafts) {
692
781
  if (c.rowspan > 1) {
693
782
  const need = c.contentHeight + pad.top + pad.bottom;
694
783
  let span = 0;
695
- for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++) span += rowHeight[r];
784
+ for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++)
785
+ span += rowHeight[r];
696
786
  if (need > span) {
697
787
  const last = Math.min(c.startRow + c.rowspan - 1, nrows - 1);
698
788
  rowHeight[last] += need - span;
@@ -707,7 +797,8 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
707
797
  for (let r = 0; r < nrows; r++) rowY[r + 1] = rowY[r] + rowHeight[r];
708
798
  const cells = cellDrafts.map((c) => {
709
799
  let height = 0;
710
- for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++) height += rowHeight[r];
800
+ for (let r = c.startRow; r < c.startRow + c.rowspan && r < nrows; r++)
801
+ height += rowHeight[r];
711
802
  const slack = Math.max(0, height - pad.top - pad.bottom - c.contentHeight);
712
803
  const vOffset = c.vAlign === "bottom" ? slack : c.vAlign === "center" ? slack / 2 : 0;
713
804
  const dy = rowY[c.startRow] + pad.top + vOffset;
@@ -725,19 +816,30 @@ function layoutTable(table, contentLeft, contentRight, ctx) {
725
816
  if (c.background) cell.background = c.background;
726
817
  if (c.borders) cell.borders = c.borders;
727
818
  if (c.tables.length > 0) cell.tables = c.tables;
728
- if (c.floats.length > 0) cell.floats = c.floats.map((f) => ({ ...f, y: f.y + dy }));
819
+ if (c.floats.length > 0)
820
+ cell.floats = c.floats.map((f) => ({ ...f, y: f.y + dy }));
729
821
  return cell;
730
822
  });
731
- const resolved = { x: contentLeft + xShift, y: 0, width: tableWidth, height: rowY[nrows], cells };
823
+ const resolved = {
824
+ x: contentLeft + xShift,
825
+ y: 0,
826
+ width: tableWidth,
827
+ height: rowY[nrows],
828
+ cells
829
+ };
732
830
  if (table.borders) resolved.borders = table.borders;
733
831
  let headerRows = 0;
734
832
  while (headerRows < nrows && table.rows[headerRows].header) headerRows++;
735
833
  if (headerRows > 0 && headerRows < nrows) {
736
834
  const headerBottom = rowY[headerRows];
737
- const spansOut = cells.some((c) => c.y < headerBottom && c.y + c.height > headerBottom);
835
+ const spansOut = cells.some(
836
+ (c) => c.y < headerBottom && c.y + c.height > headerBottom
837
+ );
738
838
  if (!spansOut) resolved.headerBottom = headerBottom;
739
839
  }
740
- const cantSplitBands = table.rows.map((row, r) => row.cantSplit ? { top: rowY[r], bottom: rowY[r + 1] } : null).filter((b) => b !== null);
840
+ const cantSplitBands = table.rows.map(
841
+ (row, r) => row.cantSplit ? { top: rowY[r], bottom: rowY[r + 1] } : null
842
+ ).filter((b) => b !== null);
741
843
  if (cantSplitBands.length > 0) resolved.cantSplitBands = cantSplitBands;
742
844
  return resolved;
743
845
  }
@@ -770,7 +872,10 @@ function cloneTable(t) {
770
872
  return { ...t, cells: t.cells.map(cloneCell) };
771
873
  }
772
874
  function cloneCell(cell) {
773
- const copy = { ...cell, lines: cell.lines.map((l) => ({ ...l })) };
875
+ const copy = {
876
+ ...cell,
877
+ lines: cell.lines.map((l) => ({ ...l }))
878
+ };
774
879
  if (cell.tables) copy.tables = cell.tables.map(cloneTable);
775
880
  if (cell.floats) copy.floats = cell.floats.map((f) => ({ ...f }));
776
881
  return copy;
@@ -806,11 +911,19 @@ function splitTableAt(table, cut) {
806
911
  } else {
807
912
  const c = straddlers.get(cell);
808
913
  const topLines = cell.lines.filter((l) => l.y + l.height <= cut);
809
- const topTables = (cell.tables ?? []).filter((t) => t.y + t.height <= cut);
810
- const topCell = { ...cell, height: cut - cell.y, lines: topLines };
914
+ const topTables = (cell.tables ?? []).filter(
915
+ (t) => t.y + t.height <= cut
916
+ );
917
+ const topCell = {
918
+ ...cell,
919
+ height: cut - cell.y,
920
+ lines: topLines
921
+ };
811
922
  if (topTables.length > 0) topCell.tables = topTables;
812
923
  else delete topCell.tables;
813
- const topFloats = (cell.floats ?? []).filter((f) => f.y + f.height <= cut);
924
+ const topFloats = (cell.floats ?? []).filter(
925
+ (f) => f.y + f.height <= cut
926
+ );
814
927
  if (topFloats.length > 0) topCell.floats = topFloats;
815
928
  else delete topCell.floats;
816
929
  topCells.push(topCell);
@@ -833,7 +946,13 @@ function splitTableAt(table, cut) {
833
946
  restCells.push(contCell);
834
947
  }
835
948
  }
836
- const top = { x: table.x, y: 0, width: table.width, height: cut, cells: topCells };
949
+ const top = {
950
+ x: table.x,
951
+ y: 0,
952
+ width: table.width,
953
+ height: cut,
954
+ cells: topCells
955
+ };
837
956
  const rest = {
838
957
  x: table.x,
839
958
  y: 0,
@@ -855,10 +974,14 @@ function cloneHeaderCells(table, headerBottom) {
855
974
  tables: void 0,
856
975
  floats: cell.floats?.map((f) => ({ ...f })),
857
976
  lines: cell.lines.map((l) => {
858
- const line = { ...l, segments: l.segments.map((s) => ({ ...s, pos: void 0 })) };
977
+ const line = {
978
+ ...l,
979
+ segments: l.segments.map((s) => ({ ...s, pos: void 0 }))
980
+ };
859
981
  delete line.from;
860
982
  delete line.to;
861
- if (line.images) line.images = line.images.map((im) => ({ ...im, pos: void 0 }));
983
+ if (line.images)
984
+ line.images = line.images.map((im) => ({ ...im, pos: void 0 }));
862
985
  return line;
863
986
  })
864
987
  }));
@@ -935,13 +1058,15 @@ function placeBlocks(items, config, ctx, band, footnotes) {
935
1058
  for (const l of ls)
936
1059
  for (const s of l.segments) {
937
1060
  const n = s.footnoteRef;
938
- if (n != null && footnotes?.has(n) && !pageFnSet.has(n) && !out.includes(n)) out.push(n);
1061
+ if (n != null && footnotes?.has(n) && !pageFnSet.has(n) && !out.includes(n))
1062
+ out.push(n);
939
1063
  }
940
1064
  };
941
1065
  for (const c of t.cells) {
942
1066
  if (c.y >= maxY) continue;
943
1067
  scan(c.lines);
944
- if (c.tables) for (const nt of c.tables) for (const nc of nt.cells) scan(nc.lines);
1068
+ if (c.tables)
1069
+ for (const nt of c.tables) for (const nc of nt.cells) scan(nc.lines);
945
1070
  }
946
1071
  return out;
947
1072
  };
@@ -970,10 +1095,16 @@ function placeBlocks(items, config, ctx, band, footnotes) {
970
1095
  return { separatorY: areaTop + FOOTNOTE_AREA_GAP / 2, lines: out };
971
1096
  };
972
1097
  const finalizePage = () => {
973
- const resolved = { index: pages.length, width: page.width, height: page.height, lines };
1098
+ const resolved = {
1099
+ index: pages.length,
1100
+ width: page.width,
1101
+ height: page.height,
1102
+ lines
1103
+ };
974
1104
  if (tables.length > 0) resolved.tables = tables;
975
1105
  if (pageFloats.length > 0) resolved.floats = pageFloats;
976
- if (pageFnNums.length > 0) resolved.footnotes = buildFootnoteArea(pageFnNums);
1106
+ if (pageFnNums.length > 0)
1107
+ resolved.footnotes = buildFootnoteArea(pageFnNums);
977
1108
  pages.push(resolved);
978
1109
  lines = [];
979
1110
  tables = [];
@@ -1063,7 +1194,9 @@ function placeBlocks(items, config, ctx, band, footnotes) {
1063
1194
  }
1064
1195
  const b = bandAt(y, estH);
1065
1196
  if (b) return b;
1066
- const blockers = exclusions.filter((ex) => ex.top < y + estH && ex.bottom > y);
1197
+ const blockers = exclusions.filter(
1198
+ (ex) => ex.top < y + estH && ex.bottom > y
1199
+ );
1067
1200
  if (blockers.length === 0) return { left: colX0(), right: colX1() };
1068
1201
  y = Math.min(...blockers.map((ex) => ex.bottom));
1069
1202
  }
@@ -1107,7 +1240,9 @@ function placeBlocks(items, config, ctx, band, footnotes) {
1107
1240
  }
1108
1241
  const drafts = item.para.drafts;
1109
1242
  const draftsHeight = drafts?.reduce((s, d) => s + d.height, 0) ?? 0;
1110
- const floatsAhead = exclusions.some((ex) => ex.bottom > y && ex.top < y + draftsHeight);
1243
+ const floatsAhead = exclusions.some(
1244
+ (ex) => ex.bottom > y && ex.top < y + draftsHeight
1245
+ );
1111
1246
  if (drafts && !floatsAhead) {
1112
1247
  for (const d of drafts) emitLine(d);
1113
1248
  } else {
@@ -1226,16 +1361,25 @@ function shiftDrafts(drafts, delta) {
1226
1361
  ...d,
1227
1362
  from: d.from != null ? d.from + delta : d.from,
1228
1363
  to: d.to != null ? d.to + delta : d.to,
1229
- segments: d.segments.map((s) => s.pos != null ? { ...s, pos: s.pos + delta } : s),
1230
- images: d.images.map((im) => im.pos != null ? { ...im, pos: im.pos + delta } : im)
1364
+ segments: d.segments.map(
1365
+ (s) => s.pos != null ? { ...s, pos: s.pos + delta } : s
1366
+ ),
1367
+ images: d.images.map(
1368
+ (im) => im.pos != null ? { ...im, pos: im.pos + delta } : im
1369
+ )
1231
1370
  }));
1232
1371
  }
1233
1372
  function cloneLineShifted(l, delta) {
1234
1373
  const out = {
1235
1374
  ...l,
1236
- segments: l.segments.map((s) => s.pos != null ? { ...s, pos: s.pos + delta } : { ...s })
1375
+ segments: l.segments.map(
1376
+ (s) => s.pos != null ? { ...s, pos: s.pos + delta } : { ...s }
1377
+ )
1237
1378
  };
1238
- if (l.images) out.images = l.images.map((im) => im.pos != null ? { ...im, pos: im.pos + delta } : { ...im });
1379
+ if (l.images)
1380
+ out.images = l.images.map(
1381
+ (im) => im.pos != null ? { ...im, pos: im.pos + delta } : { ...im }
1382
+ );
1239
1383
  if (l.from != null) out.from = l.from + delta;
1240
1384
  if (l.to != null) out.to = l.to + delta;
1241
1385
  return out;
@@ -1278,7 +1422,10 @@ function layVariants(docs, fn) {
1278
1422
  return out;
1279
1423
  }
1280
1424
  function maxBandHeight(bands) {
1281
- return Math.max(0, ...[bands.default, bands.first, bands.even].filter(Boolean).map((b) => b.height));
1425
+ return Math.max(
1426
+ 0,
1427
+ ...[bands.default, bands.first, bands.even].filter(Boolean).map((b) => b.height)
1428
+ );
1282
1429
  }
1283
1430
  function anyBandHasFields(bands) {
1284
1431
  return [bands.default, bands.first, bands.even].some(
@@ -1304,9 +1451,17 @@ function layoutChrome(doc, topY, left, right, ctx) {
1304
1451
  const lines = flow.lines.map((l) => ({ ...l, y: l.y + topY }));
1305
1452
  flow.tables.forEach((t) => offsetTable(t, topY));
1306
1453
  stripPositions(lines, flow.tables);
1307
- const band = { lines, tables: flow.tables, height: flow.height };
1454
+ const band = {
1455
+ lines,
1456
+ tables: flow.tables,
1457
+ height: flow.height
1458
+ };
1308
1459
  if (flow.floats.length > 0)
1309
- band.floats = flow.floats.map((f) => ({ ...f, y: f.y + topY, pos: void 0 }));
1460
+ band.floats = flow.floats.map((f) => ({
1461
+ ...f,
1462
+ y: f.y + topY,
1463
+ pos: void 0
1464
+ }));
1310
1465
  return band;
1311
1466
  }
1312
1467
  function layoutFooterChrome(doc, pageHeight, left, right, ctx) {
@@ -1318,12 +1473,21 @@ function layoutFooterChrome(doc, pageHeight, left, right, ctx) {
1318
1473
  height: flow.height
1319
1474
  };
1320
1475
  band.tables.forEach((t) => offsetTable(t, topY));
1321
- if (flow.floats) band.floats = flow.floats.map((f) => ({ ...f, y: f.y + topY }));
1476
+ if (flow.floats)
1477
+ band.floats = flow.floats.map((f) => ({ ...f, y: f.y + topY }));
1322
1478
  return band;
1323
1479
  }
1324
1480
  function layoutFootnoteBody(doc, left, right, ctx) {
1325
- const fnCtx = { ...ctx, base: { ...ctx.base, sizePt: ctx.base.sizePt * FOOTNOTE_FONT_SCALE } };
1326
- const flow = layoutFlow(toFlowBlocks(doc, fnCtx.base, false), left, right, fnCtx);
1481
+ const fnCtx = {
1482
+ ...ctx,
1483
+ base: { ...ctx.base, sizePt: ctx.base.sizePt * FOOTNOTE_FONT_SCALE }
1484
+ };
1485
+ const flow = layoutFlow(
1486
+ toFlowBlocks(doc, fnCtx.base, false),
1487
+ left,
1488
+ right,
1489
+ fnCtx
1490
+ );
1327
1491
  stripPositions(flow.lines, flow.tables);
1328
1492
  return { lines: flow.lines, height: flow.height };
1329
1493
  }
@@ -1332,10 +1496,24 @@ function layout(doc, config, cache, chrome, footnotes) {
1332
1496
  const { page } = config;
1333
1497
  const left = page.margin.left;
1334
1498
  const right = page.width - page.margin.right;
1335
- const headerDocs = { default: chrome?.header, first: chrome?.headerFirst, even: chrome?.headerEven };
1336
- const footerDocs = { default: chrome?.footer, first: chrome?.footerFirst, even: chrome?.footerEven };
1337
- const layHeaders = (c) => layVariants(headerDocs, (d) => layoutChrome(d, CHROME_DISTANCE, left, right, c));
1338
- const layFooters = (c) => layVariants(footerDocs, (d) => layoutFooterChrome(d, page.height, left, right, c));
1499
+ const headerDocs = {
1500
+ default: chrome?.header,
1501
+ first: chrome?.headerFirst,
1502
+ even: chrome?.headerEven
1503
+ };
1504
+ const footerDocs = {
1505
+ default: chrome?.footer,
1506
+ first: chrome?.footerFirst,
1507
+ even: chrome?.footerEven
1508
+ };
1509
+ const layHeaders = (c) => layVariants(
1510
+ headerDocs,
1511
+ (d) => layoutChrome(d, CHROME_DISTANCE, left, right, c)
1512
+ );
1513
+ const layFooters = (c) => layVariants(
1514
+ footerDocs,
1515
+ (d) => layoutFooterChrome(d, page.height, left, right, c)
1516
+ );
1339
1517
  let headers = layHeaders(ctx);
1340
1518
  let footers = layFooters(ctx);
1341
1519
  let top = page.margin.top;
@@ -1344,25 +1522,46 @@ function layout(doc, config, cache, chrome, footnotes) {
1344
1522
  top = Math.max(top, CHROME_DISTANCE + maxBandHeight(headers));
1345
1523
  }
1346
1524
  if (footers.default || footers.first || footers.even) {
1347
- bottom = Math.min(bottom, page.height - CHROME_DISTANCE - maxBandHeight(footers));
1525
+ bottom = Math.min(
1526
+ bottom,
1527
+ page.height - CHROME_DISTANCE - maxBandHeight(footers)
1528
+ );
1348
1529
  }
1349
- const counter = createNumberingCounter(doc.attrs["numbering"]);
1530
+ const counter = createNumberingCounter(
1531
+ doc.attrs["numbering"]
1532
+ );
1350
1533
  const sections = doc.attrs["sections"] ?? [
1351
- { blockCount: doc.childCount, columns: { count: 1, gap: 0 }, newPage: true }
1534
+ {
1535
+ blockCount: doc.childCount,
1536
+ columns: { count: 1, gap: 0 },
1537
+ newPage: true
1538
+ }
1352
1539
  ];
1353
1540
  const blockSection = [];
1354
1541
  for (const sec of sections) {
1355
1542
  for (let k = 0; k < sec.blockCount; k++) {
1356
- blockSection.push({ columns: sec.columns, start: k === 0, newPage: sec.newPage });
1543
+ blockSection.push({
1544
+ columns: sec.columns,
1545
+ start: k === 0,
1546
+ newPage: sec.newPage
1547
+ });
1357
1548
  }
1358
1549
  }
1359
1550
  const lastSec = sections[sections.length - 1];
1360
1551
  while (blockSection.length < doc.childCount) {
1361
- blockSection.push({ columns: lastSec.columns, start: false, newPage: lastSec.newPage });
1552
+ blockSection.push({
1553
+ columns: lastSec.columns,
1554
+ start: false,
1555
+ newPage: lastSec.newPage
1556
+ });
1362
1557
  }
1363
1558
  const items = [];
1364
1559
  doc.forEach((node, offset, index) => {
1365
- const bs = blockSection[index] ?? { columns: { count: 1, gap: 0 }, start: false, newPage: true };
1560
+ const bs = blockSection[index] ?? {
1561
+ columns: { count: 1, gap: 0 },
1562
+ start: false,
1563
+ newPage: true
1564
+ };
1366
1565
  const colRight = left + columnWidth(right - left, bs.columns);
1367
1566
  const tag = (item) => {
1368
1567
  if (bs.start) item.section = { ...bs.columns, newPage: bs.newPage };
@@ -1395,17 +1594,35 @@ function layout(doc, config, cache, chrome, footnotes) {
1395
1594
  }
1396
1595
  const flow = paragraphToFlow(node, ctx.base, offset, true, marker);
1397
1596
  const drafts = layoutParagraph(flow, left, colRight, ctx);
1398
- cache?.paragraphs.set(node, { left, right: colRight, basePos: contentStart, marker, drafts });
1597
+ cache?.paragraphs.set(node, {
1598
+ left,
1599
+ right: colRight,
1600
+ basePos: contentStart,
1601
+ marker,
1602
+ drafts
1603
+ });
1399
1604
  items.push(tag({ para: { ...para(drafts), getFlow: () => flow } }));
1400
1605
  } else if (node.type.name === "table") {
1401
1606
  const hit = cache?.tables.get(node);
1402
1607
  if (hit && hit.left === left && hit.right === colRight) {
1403
- items.push(tag({ table: cloneTableShifted(hit.table, offset - hit.basePos) }));
1608
+ items.push(
1609
+ tag({ table: cloneTableShifted(hit.table, offset - hit.basePos) })
1610
+ );
1404
1611
  return;
1405
1612
  }
1406
- const table = layoutTable(tableToFlow(node, ctx.base, offset, counter), left, colRight, ctx);
1613
+ const table = layoutTable(
1614
+ tableToFlow(node, ctx.base, offset, counter),
1615
+ left,
1616
+ colRight,
1617
+ ctx
1618
+ );
1407
1619
  if (cache && !tableHasList(node)) {
1408
- cache.tables.set(node, { left, right: colRight, basePos: offset, table });
1620
+ cache.tables.set(node, {
1621
+ left,
1622
+ right: colRight,
1623
+ basePos: offset,
1624
+ table
1625
+ });
1409
1626
  items.push(tag({ table: cloneTableShifted(table, 0) }));
1410
1627
  } else {
1411
1628
  items.push(tag({ table }));
@@ -1423,7 +1640,10 @@ function layout(doc, config, cache, chrome, footnotes) {
1423
1640
  assignSectionHeights(items);
1424
1641
  const resolved = placeBlocks(items, config, ctx, { top, bottom }, fnMap);
1425
1642
  if (anyBandHasFields(headers) || anyBandHasFields(footers)) {
1426
- const fieldCtx = { ...ctx, fieldPlaceholder: String(resolved.pages.length) };
1643
+ const fieldCtx = {
1644
+ ...ctx,
1645
+ fieldPlaceholder: String(resolved.pages.length)
1646
+ };
1427
1647
  headers = layHeaders(fieldCtx);
1428
1648
  footers = layFooters(fieldCtx);
1429
1649
  }
@@ -1434,7 +1654,10 @@ function layout(doc, config, cache, chrome, footnotes) {
1434
1654
  if (footers.first) resolved.pageFooterFirst = footers.first;
1435
1655
  if (footers.even) resolved.pageFooterEven = footers.even;
1436
1656
  if (chrome?.titlePg || chrome?.evenAndOdd) {
1437
- resolved.chromeSelect = { titlePg: !!chrome.titlePg, evenAndOdd: !!chrome.evenAndOdd };
1657
+ resolved.chromeSelect = {
1658
+ titlePg: !!chrome.titlePg,
1659
+ evenAndOdd: !!chrome.evenAndOdd
1660
+ };
1438
1661
  }
1439
1662
  return resolved;
1440
1663
  }