postext 1.35.1 → 1.37.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 (273) hide show
  1. package/dist/__bench__/composedPage.bench.test.d.ts +2 -0
  2. package/dist/__bench__/composedPage.bench.test.d.ts.map +1 -0
  3. package/dist/__bench__/composedPage.bench.test.js +95 -0
  4. package/dist/__bench__/composedPage.bench.test.js.map +1 -0
  5. package/dist/__tests__/composed/continuation.test.d.ts +2 -0
  6. package/dist/__tests__/composed/continuation.test.d.ts.map +1 -0
  7. package/dist/__tests__/composed/continuation.test.js +352 -0
  8. package/dist/__tests__/composed/continuation.test.js.map +1 -0
  9. package/dist/__tests__/composed/contrast.test.d.ts +2 -0
  10. package/dist/__tests__/composed/contrast.test.d.ts.map +1 -0
  11. package/dist/__tests__/composed/contrast.test.js +124 -0
  12. package/dist/__tests__/composed/contrast.test.js.map +1 -0
  13. package/dist/__tests__/composed/corpus.test.js +7 -1
  14. package/dist/__tests__/composed/corpus.test.js.map +1 -1
  15. package/dist/__tests__/composed/fit.test.d.ts +2 -0
  16. package/dist/__tests__/composed/fit.test.d.ts.map +1 -0
  17. package/dist/__tests__/composed/fit.test.js +408 -0
  18. package/dist/__tests__/composed/fit.test.js.map +1 -0
  19. package/dist/__tests__/composed/groups.test.js +14 -0
  20. package/dist/__tests__/composed/groups.test.js.map +1 -1
  21. package/dist/__tests__/composed/headingDesigns.test.d.ts +2 -0
  22. package/dist/__tests__/composed/headingDesigns.test.d.ts.map +1 -0
  23. package/dist/__tests__/composed/headingDesigns.test.js +262 -0
  24. package/dist/__tests__/composed/headingDesigns.test.js.map +1 -0
  25. package/dist/__tests__/composed/labels.test.d.ts +2 -0
  26. package/dist/__tests__/composed/labels.test.d.ts.map +1 -0
  27. package/dist/__tests__/composed/labels.test.js +326 -0
  28. package/dist/__tests__/composed/labels.test.js.map +1 -0
  29. package/dist/__tests__/composed/layout.test.js +2 -1
  30. package/dist/__tests__/composed/layout.test.js.map +1 -1
  31. package/dist/__tests__/composed/outsidePrint.test.js +5 -2
  32. package/dist/__tests__/composed/outsidePrint.test.js.map +1 -1
  33. package/dist/__tests__/composed/pageMemo.test.d.ts +2 -0
  34. package/dist/__tests__/composed/pageMemo.test.d.ts.map +1 -0
  35. package/dist/__tests__/composed/pageMemo.test.js +128 -0
  36. package/dist/__tests__/composed/pageMemo.test.js.map +1 -0
  37. package/dist/__tests__/composed/sourceMap.test.d.ts +2 -0
  38. package/dist/__tests__/composed/sourceMap.test.d.ts.map +1 -0
  39. package/dist/__tests__/composed/sourceMap.test.js +395 -0
  40. package/dist/__tests__/composed/sourceMap.test.js.map +1 -0
  41. package/dist/__tests__/composed/spreadLabels.test.d.ts +2 -0
  42. package/dist/__tests__/composed/spreadLabels.test.d.ts.map +1 -0
  43. package/dist/__tests__/composed/spreadLabels.test.js +131 -0
  44. package/dist/__tests__/composed/spreadLabels.test.js.map +1 -0
  45. package/dist/__tests__/composed/templateFrameRects.test.d.ts +2 -0
  46. package/dist/__tests__/composed/templateFrameRects.test.d.ts.map +1 -0
  47. package/dist/__tests__/composed/templateFrameRects.test.js +37 -0
  48. package/dist/__tests__/composed/templateFrameRects.test.js.map +1 -0
  49. package/dist/__tests__/design/imageAltText.test.js +2 -1
  50. package/dist/__tests__/design/imageAltText.test.js.map +1 -1
  51. package/dist/__tests__/exports.test.js +33 -0
  52. package/dist/__tests__/exports.test.js.map +1 -1
  53. package/dist/__tests__/migrate/fixtures/textbookPort.d.ts +14 -0
  54. package/dist/__tests__/migrate/fixtures/textbookPort.d.ts.map +1 -0
  55. package/dist/__tests__/migrate/fixtures/textbookPort.js +116 -0
  56. package/dist/__tests__/migrate/fixtures/textbookPort.js.map +1 -0
  57. package/dist/__tests__/migrate/textToMarkdown.test.d.ts +2 -0
  58. package/dist/__tests__/migrate/textToMarkdown.test.d.ts.map +1 -0
  59. package/dist/__tests__/migrate/textToMarkdown.test.js +268 -0
  60. package/dist/__tests__/migrate/textToMarkdown.test.js.map +1 -0
  61. package/dist/__tests__/paragraphStyleLetterSpacing.test.d.ts +2 -0
  62. package/dist/__tests__/paragraphStyleLetterSpacing.test.d.ts.map +1 -0
  63. package/dist/__tests__/paragraphStyleLetterSpacing.test.js +89 -0
  64. package/dist/__tests__/paragraphStyleLetterSpacing.test.js.map +1 -0
  65. package/dist/__tests__/pictureBelowPrintSize.test.d.ts +2 -0
  66. package/dist/__tests__/pictureBelowPrintSize.test.d.ts.map +1 -0
  67. package/dist/__tests__/pictureBelowPrintSize.test.js +82 -0
  68. package/dist/__tests__/pictureBelowPrintSize.test.js.map +1 -0
  69. package/dist/__tests__/pipeline/contourWrap.test.d.ts +2 -0
  70. package/dist/__tests__/pipeline/contourWrap.test.d.ts.map +1 -0
  71. package/dist/__tests__/pipeline/contourWrap.test.js +412 -0
  72. package/dist/__tests__/pipeline/contourWrap.test.js.map +1 -0
  73. package/dist/__tests__/pipeline/paragraphStyleFaces.test.js +1 -1
  74. package/dist/__tests__/pipeline/paragraphStyleFaces.test.js.map +1 -1
  75. package/dist/__tests__/toc.test.js +3 -2
  76. package/dist/__tests__/toc.test.js.map +1 -1
  77. package/dist/bundle/codec.d.ts +16 -0
  78. package/dist/bundle/codec.d.ts.map +1 -1
  79. package/dist/bundle/codec.js +44 -2
  80. package/dist/bundle/codec.js.map +1 -1
  81. package/dist/bundle/index.d.ts +1 -1
  82. package/dist/bundle/index.d.ts.map +1 -1
  83. package/dist/bundle/index.js +1 -1
  84. package/dist/bundle/index.js.map +1 -1
  85. package/dist/canvas-backend/composed.d.ts +5 -2
  86. package/dist/canvas-backend/composed.d.ts.map +1 -1
  87. package/dist/canvas-backend/composed.js +10 -5
  88. package/dist/canvas-backend/composed.js.map +1 -1
  89. package/dist/canvas-backend/index.d.ts.map +1 -1
  90. package/dist/canvas-backend/index.js +37 -19
  91. package/dist/canvas-backend/index.js.map +1 -1
  92. package/dist/canvas-backend/renderResourceBlock.d.ts +5 -1
  93. package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
  94. package/dist/canvas-backend/renderResourceBlock.js +60 -1
  95. package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
  96. package/dist/composed/continuation.d.ts +102 -0
  97. package/dist/composed/continuation.d.ts.map +1 -0
  98. package/dist/composed/continuation.js +87 -0
  99. package/dist/composed/continuation.js.map +1 -0
  100. package/dist/composed/contour.d.ts +21 -0
  101. package/dist/composed/contour.d.ts.map +1 -0
  102. package/dist/composed/contour.js +34 -0
  103. package/dist/composed/contour.js.map +1 -0
  104. package/dist/composed/geometry.d.ts +8 -0
  105. package/dist/composed/geometry.d.ts.map +1 -1
  106. package/dist/composed/geometry.js +26 -0
  107. package/dist/composed/geometry.js.map +1 -1
  108. package/dist/composed/ids.d.ts +22 -0
  109. package/dist/composed/ids.d.ts.map +1 -0
  110. package/dist/composed/ids.js +32 -0
  111. package/dist/composed/ids.js.map +1 -0
  112. package/dist/composed/labels.d.ts +154 -0
  113. package/dist/composed/labels.d.ts.map +1 -0
  114. package/dist/composed/labels.js +524 -0
  115. package/dist/composed/labels.js.map +1 -0
  116. package/dist/composed/pageMemo.d.ts +73 -0
  117. package/dist/composed/pageMemo.d.ts.map +1 -0
  118. package/dist/composed/pageMemo.js +289 -0
  119. package/dist/composed/pageMemo.js.map +1 -0
  120. package/dist/composed/paint.d.ts +29 -9
  121. package/dist/composed/paint.d.ts.map +1 -1
  122. package/dist/composed/paint.js +41 -7
  123. package/dist/composed/paint.js.map +1 -1
  124. package/dist/composed/reflowLog.d.ts +14 -2
  125. package/dist/composed/reflowLog.d.ts.map +1 -1
  126. package/dist/composed/reflowLog.js +64 -7
  127. package/dist/composed/reflowLog.js.map +1 -1
  128. package/dist/composed/slotChecks.d.ts.map +1 -1
  129. package/dist/composed/slotChecks.js +3 -1
  130. package/dist/composed/slotChecks.js.map +1 -1
  131. package/dist/composed/sourceMap.d.ts +97 -0
  132. package/dist/composed/sourceMap.d.ts.map +1 -0
  133. package/dist/composed/sourceMap.js +748 -0
  134. package/dist/composed/sourceMap.js.map +1 -0
  135. package/dist/composed/spread.d.ts +3 -0
  136. package/dist/composed/spread.d.ts.map +1 -1
  137. package/dist/composed/spread.js +11 -12
  138. package/dist/composed/spread.js.map +1 -1
  139. package/dist/composed/templates.d.ts +1 -0
  140. package/dist/composed/templates.d.ts.map +1 -1
  141. package/dist/composed/templates.js +4 -0
  142. package/dist/composed/templates.js.map +1 -1
  143. package/dist/composed/types.d.ts +15 -32
  144. package/dist/composed/types.d.ts.map +1 -1
  145. package/dist/composed/validate.d.ts.map +1 -1
  146. package/dist/composed/validate.js +3 -2
  147. package/dist/composed/validate.js.map +1 -1
  148. package/dist/composed/wrap.d.ts.map +1 -1
  149. package/dist/composed/wrap.js +7 -1
  150. package/dist/composed/wrap.js.map +1 -1
  151. package/dist/configWarnings.d.ts +15 -0
  152. package/dist/configWarnings.d.ts.map +1 -1
  153. package/dist/configWarnings.js +29 -17
  154. package/dist/configWarnings.js.map +1 -1
  155. package/dist/contour/index.d.ts +134 -0
  156. package/dist/contour/index.d.ts.map +1 -0
  157. package/dist/contour/index.js +354 -0
  158. package/dist/contour/index.js.map +1 -0
  159. package/dist/contour/png.d.ts +16 -0
  160. package/dist/contour/png.d.ts.map +1 -0
  161. package/dist/contour/png.js +173 -0
  162. package/dist/contour/png.js.map +1 -0
  163. package/dist/contrast.d.ts +5 -3
  164. package/dist/contrast.d.ts.map +1 -1
  165. package/dist/contrast.js +46 -5
  166. package/dist/contrast.js.map +1 -1
  167. package/dist/defaults/paragraphStyles.d.ts +1 -1
  168. package/dist/defaults/paragraphStyles.d.ts.map +1 -1
  169. package/dist/defaults/paragraphStyles.js +5 -1
  170. package/dist/defaults/paragraphStyles.js.map +1 -1
  171. package/dist/design/slots.d.ts +12 -10
  172. package/dist/design/slots.d.ts.map +1 -1
  173. package/dist/design/slots.js +26 -2
  174. package/dist/design/slots.js.map +1 -1
  175. package/dist/fonts/faces.d.ts.map +1 -1
  176. package/dist/fonts/faces.js +6 -0
  177. package/dist/fonts/faces.js.map +1 -1
  178. package/dist/highlightMarks.d.ts.map +1 -1
  179. package/dist/highlightMarks.js +6 -0
  180. package/dist/highlightMarks.js.map +1 -1
  181. package/dist/html-backend.d.ts.map +1 -1
  182. package/dist/html-backend.js +42 -4
  183. package/dist/html-backend.js.map +1 -1
  184. package/dist/index.d.ts +18 -7
  185. package/dist/index.d.ts.map +1 -1
  186. package/dist/index.js +18 -4
  187. package/dist/index.js.map +1 -1
  188. package/dist/measure/rich.d.ts.map +1 -1
  189. package/dist/measure/rich.js +2 -0
  190. package/dist/measure/rich.js.map +1 -1
  191. package/dist/migrate/markdownRuns.d.ts +70 -0
  192. package/dist/migrate/markdownRuns.d.ts.map +1 -0
  193. package/dist/migrate/markdownRuns.js +215 -0
  194. package/dist/migrate/markdownRuns.js.map +1 -0
  195. package/dist/migrate/pageDesign.d.ts +119 -0
  196. package/dist/migrate/pageDesign.d.ts.map +1 -0
  197. package/dist/migrate/pageDesign.js +446 -0
  198. package/dist/migrate/pageDesign.js.map +1 -0
  199. package/dist/migrate/textToMarkdown.d.ts +124 -0
  200. package/dist/migrate/textToMarkdown.d.ts.map +1 -0
  201. package/dist/migrate/textToMarkdown.js +716 -0
  202. package/dist/migrate/textToMarkdown.js.map +1 -0
  203. package/dist/parse/blockParser.d.ts.map +1 -1
  204. package/dist/parse/blockParser.js +44 -3
  205. package/dist/parse/blockParser.js.map +1 -1
  206. package/dist/parse/types.d.ts +20 -0
  207. package/dist/parse/types.d.ts.map +1 -1
  208. package/dist/pipeline/build.d.ts.map +1 -1
  209. package/dist/pipeline/build.js +298 -30
  210. package/dist/pipeline/build.js.map +1 -1
  211. package/dist/pipeline/buildMeasurement.d.ts +7 -2
  212. package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
  213. package/dist/pipeline/buildMeasurement.js +21 -5
  214. package/dist/pipeline/buildMeasurement.js.map +1 -1
  215. package/dist/pipeline/calloutLayout.d.ts +39 -14
  216. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  217. package/dist/pipeline/calloutLayout.js +50 -4
  218. package/dist/pipeline/calloutLayout.js.map +1 -1
  219. package/dist/pipeline/composedLayout.d.ts +51 -6
  220. package/dist/pipeline/composedLayout.d.ts.map +1 -1
  221. package/dist/pipeline/composedLayout.js +633 -78
  222. package/dist/pipeline/composedLayout.js.map +1 -1
  223. package/dist/pipeline/contentWarnings.d.ts +15 -0
  224. package/dist/pipeline/contentWarnings.d.ts.map +1 -1
  225. package/dist/pipeline/contentWarnings.js +98 -4
  226. package/dist/pipeline/contentWarnings.js.map +1 -1
  227. package/dist/pipeline/floatPlacement.d.ts +2 -0
  228. package/dist/pipeline/floatPlacement.d.ts.map +1 -1
  229. package/dist/pipeline/floatPlacement.js +1 -0
  230. package/dist/pipeline/floatPlacement.js.map +1 -1
  231. package/dist/pipeline/frameLayout.d.ts +7 -4
  232. package/dist/pipeline/frameLayout.d.ts.map +1 -1
  233. package/dist/pipeline/frameLayout.js +5 -2
  234. package/dist/pipeline/frameLayout.js.map +1 -1
  235. package/dist/pipeline/headerFooter.d.ts +20 -1
  236. package/dist/pipeline/headerFooter.d.ts.map +1 -1
  237. package/dist/pipeline/headerFooter.js +225 -70
  238. package/dist/pipeline/headerFooter.js.map +1 -1
  239. package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
  240. package/dist/pipeline/measureContentBlock.js +1 -0
  241. package/dist/pipeline/measureContentBlock.js.map +1 -1
  242. package/dist/pipeline/mirrorFrame.d.ts.map +1 -1
  243. package/dist/pipeline/mirrorFrame.js +25 -2
  244. package/dist/pipeline/mirrorFrame.js.map +1 -1
  245. package/dist/pipeline/outline.d.ts.map +1 -1
  246. package/dist/pipeline/outline.js +2 -0
  247. package/dist/pipeline/outline.js.map +1 -1
  248. package/dist/pipeline/resourceLayout.d.ts +28 -0
  249. package/dist/pipeline/resourceLayout.d.ts.map +1 -1
  250. package/dist/pipeline/resourceLayout.js +21 -0
  251. package/dist/pipeline/resourceLayout.js.map +1 -1
  252. package/dist/pipeline/styles.d.ts +1 -1
  253. package/dist/pipeline/styles.d.ts.map +1 -1
  254. package/dist/pipeline/styles.js +4 -0
  255. package/dist/pipeline/styles.js.map +1 -1
  256. package/dist/pipeline/textWrap.d.ts +4 -1
  257. package/dist/pipeline/textWrap.d.ts.map +1 -1
  258. package/dist/pipeline/textWrap.js +17 -3
  259. package/dist/pipeline/textWrap.js.map +1 -1
  260. package/dist/pipeline/toc.d.ts.map +1 -1
  261. package/dist/pipeline/toc.js +1 -0
  262. package/dist/pipeline/toc.js.map +1 -1
  263. package/dist/types.d.ts +77 -2
  264. package/dist/types.d.ts.map +1 -1
  265. package/dist/vdt.d.ts +290 -15
  266. package/dist/vdt.d.ts.map +1 -1
  267. package/dist/vdt.js.map +1 -1
  268. package/dist/word/toDocx.d.ts.map +1 -1
  269. package/dist/word/toDocx.js +14 -0
  270. package/dist/word/toDocx.js.map +1 -1
  271. package/dist/word/word.test.js +11 -1
  272. package/dist/word/word.test.js.map +1 -1
  273. package/package.json +1 -1
@@ -3,6 +3,8 @@ import { plainTitleBreaks } from '../parse/inlineFormatting';
3
3
  import { dimensionToPx } from '../units';
4
4
  import { createVDTDocument, createVDTBlock, createBoundingBox, createVDTColumn, pageIsMirrored, pageIsVertical, flowRectToPage, } from '../vdt';
5
5
  import { figureLabels } from './buildMeasurement';
6
+ import { contourOnPage } from '../contour';
7
+ import { figureLabelWarnings, layOutFigureLabels, stampFigureLabelRects } from '../composed/labels';
6
8
  import { anchorBox } from '../design/layout';
7
9
  import { parseMarkdownMemo, spaceDirectiveLines } from '../parse';
8
10
  import { buildPageLabels, computeHeadingNumbering, parseNumberFormat, } from '../numbering';
@@ -38,7 +40,11 @@ import { flowColumnsStyles, isFlowColumnsStyle, wrapFlowColumns } from './flowCo
38
40
  import { FRAME_STYLE_ID, frameBoxStyle, wrapComposedPages } from '../composed/wrap';
39
41
  import { resolvePageTemplate } from '../composed/templates';
40
42
  import { layoutComposedSpread } from '../composed/spread';
43
+ import { assignReceivers, continuationTarget, MAX_CONTINUATION_PAGES } from '../composed/continuation';
44
+ import { frameElementId } from '../composed/ids';
45
+ import { nextFrameOf } from '../composed/geometry';
41
46
  import { composedPageAt, frameStyleOf, layoutComposedPage, planComposedPages } from './composedLayout';
47
+ import { configKeyOf, layoutComposedPageMemo } from '../composed/pageMemo';
42
48
  import { anchorOutline, computeOutline, hasIndexDirective, hasTocDirective, headingNumberingOptions, headingTemplatesOf, outlineFromDoc, sameOutline } from './outline';
43
49
  import { expandTocDirectives } from './toc';
44
50
  import { expandIndexDirectives, locateIndexMarks } from './indexDirective';
@@ -73,7 +79,7 @@ import { chapterNumberCounter, leadingBoldText } from './placeholders';
73
79
  import { proposeBalanceLines, GRID_LINE_LEVERS, collectColumnGaps, firstDivergentColumn, gapLinesIn, boxRoomIn, boxLeverKeys, pageSegments, MAX_BALANCING_PASSES, MAX_BALANCING_PASSES_PER_DOCUMENT, balanceKey, candidateKey, flexFigureKey, flexFloatKey } from './columnBalancing';
74
80
  import { applyBandCap, uncapBand, columnBottom, bandCapLines, bandTop, bareBandTop, resolveBandCapsGen, drainPasses, resolveTrailingCapsGen, bandCapLinesAroundZone, bandLinePitch, capRetryLimit, } from './bandCaps';
75
81
  import { raggedLooseLines } from './raggedLines';
76
- import { cjkLooseLineWarnings, raggedLineWarnings, collectContentWarnings, designTruncationWarnings, dropCapWarnings, floatShrinkWarnings, joiningLetterSpacingWarnings, locateContentWarnings, wordOverflowWarnings } from './contentWarnings';
82
+ import { cjkLooseLineWarnings, raggedLineWarnings, collectContentWarnings, designTruncationWarnings, dropCapWarnings, floatShrinkWarnings, joiningLetterSpacingWarnings, pictureBelowPrintSizeWarnings, locateContentWarnings, wordOverflowWarnings } from './contentWarnings';
77
83
  import { dropCapSinkAfter } from './dropCap';
78
84
  import { mostlyJoiningScript } from '../measure/joining';
79
85
  import { composesAsCjk } from '../measure/cjkCompose';
@@ -277,6 +283,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
277
283
  // their own `resolution` from here on (#631); under the default policy
278
284
  // the content is untouched.
279
285
  const stampedResources = content.resources && withBitmapResolutions(content.resources, resolved.layout.bitmapResolution);
286
+ /** The resources as given: whose print size is the author's (#901). */
287
+ const givenResources = content.resources;
280
288
  if (stampedResources && stampedResources !== content.resources)
281
289
  content = { ...content, resources: stampedResources };
282
290
  // Tracking rungs a loose paragraph may climb: none, then 5‰ steps up to
@@ -532,9 +540,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
532
540
  // floats is laid out by its id alone.
533
541
  const figureLabelsById = new Map();
534
542
  for (const b of contentBlocks) {
535
- const labels = b.resourceId !== undefined && !figureLabelsById.has(b.resourceId) ? figureLabels(b) : undefined;
543
+ const labels = b.resourceId !== undefined && !figureLabelsById.has(b.resourceId) ? figureLabels(b, bodyOffset) : undefined;
536
544
  if (labels)
537
- figureLabelsById.set(b.resourceId, labels);
545
+ figureLabelsById.set(b.resourceId, { labels, parsed: b.figure.labels });
538
546
  }
539
547
  // Resolve styles
540
548
  const bodyStyle = resolveBodyStyle(resolved);
@@ -1255,7 +1263,11 @@ function placeDocumentPass(content, config, cache, options, hints) {
1255
1263
  const { block: rb, totalHeight } = laid;
1256
1264
  const id = slice && slice.startRow > 0 ? `float-${resourceId}-cont-${slice.startRow}` : `float-${resourceId}`;
1257
1265
  const blk = createVDTBlock(id, 'resource', bodyStyle.fontString, bodyStyle.color, bodyStyle.textAlign);
1258
- const labels = figureLabelsById.get(resourceId);
1266
+ // A floated figure's labels, laid out on its picture as set (#860).
1267
+ const figure = figureLabelsById.get(resourceId);
1268
+ const labels = figure
1269
+ ? layOutFigureLabels(figure.labels, figure.parsed, rb, { resolved, resourceNumbering, resourceTypes, resources, ...(cache ? { cache } : {}) })
1270
+ : undefined;
1259
1271
  blk.resourceBlock = labels ? { ...rb, labels } : rb;
1260
1272
  blk.dirty = false;
1261
1273
  blk.snappedToGrid = false;
@@ -1302,6 +1314,29 @@ function placeDocumentPass(content, config, cache, options, hints) {
1302
1314
  };
1303
1315
  /** The `textWrap` warnings of this pass (#627). */
1304
1316
  const textWrapNotes = [];
1317
+ /** Resources whose contour wrap fell back to the box this pass (#883):
1318
+ * said once each. */
1319
+ const contourFallbacks = new Set();
1320
+ /** The shape a contour wrap (#883) of `resource`, set as `rb` in the
1321
+ * figure `box`, runs round on `page`: its polygon or traced alpha
1322
+ * channel through the picture's crop and scale, the contour's margin
1323
+ * round it (else the wrap's gap), its insets in whole body characters
1324
+ * under a CJK grid; `rb.bodyRect` is relative to `origin`, `box` is in
1325
+ * page px. `undefined` (and a `noContour` note) when the shape is not
1326
+ * known: the text runs round the box. */
1327
+ const wrapContourOf = (resource, rb, box, gapPx, page, origin, source) => {
1328
+ const own = resource.contour?.margin;
1329
+ const margin = own ? Math.max(0, dimensionToPx(own, dpi, bodyStyle.fontSizePx)) : gapPx;
1330
+ const quantum = resolved.cjk.grid.enabled && bodyStyle.fontSizePx > 0 ? bodyStyle.fontSizePx : undefined;
1331
+ const c = contourOnPage(resource, rb, box, { margin, mirrored: pageIsMirrored(page), originX: origin.x, originY: origin.y, ...(quantum ? { quantum } : {}) });
1332
+ if (c)
1333
+ return c;
1334
+ if (!contourFallbacks.has(resource.id)) {
1335
+ contourFallbacks.add(resource.id);
1336
+ textWrapNotes.push({ kind: 'textWrap', reason: 'noContour', resourceId: resource.id, ...(source ?? {}), pageIndex: page.index });
1337
+ }
1338
+ return undefined;
1339
+ };
1305
1340
  const floatWraps = new Map();
1306
1341
  /** Give the bands of the wrapped floats of `col` back to the flow, as
1307
1342
  * exclusions the text runs beside: a float at the head of a column the
@@ -1944,6 +1979,15 @@ function placeDocumentPass(content, config, cache, options, hints) {
1944
1979
  gap: exWidth - width,
1945
1980
  ownerId: built.block.id,
1946
1981
  };
1982
+ // A contour wrap (#883): the picture's shape where its block is
1983
+ // set (`commitFloatBlock` puts it at `xLeft`, `y`).
1984
+ const fRes = f.contour ? resourceById.get(f.resourceId) : undefined;
1985
+ const fRb = built.block.resourceBlock;
1986
+ if (fRes && fRb) {
1987
+ const c = wrapContourOf(fRes, fRb, { x: xLeft, y, width, height: built.height }, wrapGap, page, { x: xLeft, y });
1988
+ if (c)
1989
+ ex.contour = c;
1990
+ }
1947
1991
  if (underOpener) {
1948
1992
  // The band was taken from the flow: the text placed next takes
1949
1993
  // it back and runs beside the float, as it does beside an inline
@@ -3075,7 +3119,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
3075
3119
  blk.direction = raw.direction;
3076
3120
  const tocContinued = raw.toc?.group?.role === 'continuation' ? { continued: true } : {};
3077
3121
  if (raw.toc?.kind === 'entry') {
3078
- blk.tocEntry = { ...(raw.toc.pageIndex !== undefined ? { pageIndex: raw.toc.pageIndex } : {}), ...tocContinued };
3122
+ blk.tocEntry = { ...(raw.toc.pageIndex !== undefined ? { pageIndex: raw.toc.pageIndex } : {}), ...(raw.toc.headingSource !== undefined ? { headingSource: raw.toc.headingSource } : {}), ...tocContinued };
3079
3123
  }
3080
3124
  if (raw.toc?.kind === 'part') {
3081
3125
  blk.tocPart = {
@@ -3966,6 +4010,18 @@ function placeDocumentPass(content, config, cache, options, hints) {
3966
4010
  withStripPlaceholder(blk, stripGeometry(idx, raw.comic, width, contentArea.height - 2 * floatGapPx, pageIsVertical(doc.pages[cursor.pageIndex])));
3967
4011
  return blk;
3968
4012
  };
4013
+ /** The room a heading's design takes in a box or a frame (#906): as in
4014
+ * a column (see the heading placement below), against the heading's
4015
+ * box; a `span: 'page'` heading is laid out at the box's width too. */
4016
+ const boxHeadingDesign = (raw, blockIdx, lines, pref, headingNumber, width) => {
4017
+ const lvl = headingLevels.forBlock(raw);
4018
+ if (!lvl?.advancedDesign.enabled)
4019
+ return undefined;
4020
+ const { titleText, marked } = defaultOpenerTitle(lines, pref, raw.titleBreaks, raw.text.length, lvl.numberSeparator);
4021
+ const info = { titleText, ...(marked !== undefined ? { titleMarked: marked } : {}), formattedNumber: pref, numericValue: headingNumber, locale: resolvedLocale(resolved), ...(resolved.numerals ? { numerals: resolved.numerals } : {}), chapterNumber: chapterNumberByBlock[blockIdx] ?? '', attrs: raw.attrs };
4022
+ const design = measureHeadingDesign(lvl, info, width, resolved.page.dpi, doc.metadata, cursor.pageIndex, undefined, undefined, resourceById);
4023
+ return Math.max(design.height, design.textFloor);
4024
+ };
3969
4025
  /** What the box typesetter (`frameLayout.ts`) reads of this pass. */
3970
4026
  const framePass = {
3971
4027
  contentBlocks,
@@ -3979,6 +4035,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
3979
4035
  : measureCtx),
3980
4036
  stripBlock: calloutStripBlock,
3981
4037
  columnHeight: () => contentArea.height,
4038
+ headingDesign: (raw, blockIdx, heading, width) => boxHeadingDesign(raw, blockIdx, heading.lines, heading.numberPrefix, heading.headingNumber, width),
3982
4039
  };
3983
4040
  const makeCalloutLayouter = (startIdx, plan, style) => makeCalloutLayouterIn(framePass, startIdx, plan, style);
3984
4041
  /** Whether a page swaps its mirrored margins (a verso of a left-bound
@@ -5853,6 +5910,51 @@ function placeDocumentPass(content, config, cache, options, hints) {
5853
5910
  const composedLaid = new Set();
5854
5911
  /** The composed pages' layout warnings (`frameOverflow`). */
5855
5912
  const composedNotes = [];
5913
+ /** What the composed pages' memo (#857) reads of this pass: the
5914
+ * numbers, part, section and pictures the blocks of a page are set
5915
+ * with, and the notes a page's layout leaves. */
5916
+ const composedMemo = {
5917
+ markdown: markdownBody,
5918
+ bodyOffset,
5919
+ configKey: () => configKeyOf(calloutResolved),
5920
+ contextKey: (from, to) => {
5921
+ const ids = new Set();
5922
+ for (let i = from; i <= to; i++) {
5923
+ const b = contentBlocks[i];
5924
+ if (b.resourceId)
5925
+ ids.add(b.resourceId);
5926
+ }
5927
+ const pictures = [...ids].sort().map((id) => {
5928
+ const r = resourceById.get(id);
5929
+ return [id, r ?? null, r ? resourceTypeById.get(r.typeId) ?? null : null, resourceNumberById.get(id) ?? null, floatedIds.has(id), captionCitations?.get(id) ?? null];
5930
+ });
5931
+ const parts = [];
5932
+ const sections = [];
5933
+ const out = [];
5934
+ for (let i = from; i <= to; i++) {
5935
+ const part = partPlan.byBlock[i];
5936
+ parts.push(part ? [part.number, part.title, part.palette] : 0);
5937
+ sections.push(sectionPlan.byBlock[i]?.id ?? 0);
5938
+ if (calloutsOutOfFlow.has(i))
5939
+ out.push(i - from);
5940
+ }
5941
+ return JSON.stringify([
5942
+ headingPrefixes.slice(from, to + 1),
5943
+ headingNumbers.slice(from, to + 1),
5944
+ parts,
5945
+ sections,
5946
+ out,
5947
+ paragraphContainers.byBlock.slice(from, to + 1).map((c) => (c ? c.style : 0)),
5948
+ pictures,
5949
+ ]);
5950
+ },
5951
+ sideEffectsIn: (from, to) => {
5952
+ for (let i = from; i <= to; i++)
5953
+ if (dropCapNotes.has(i) || joiningLetterSpacing.has(i))
5954
+ return true;
5955
+ return false;
5956
+ },
5957
+ };
5856
5958
  /** Set the composed page `planned` on a fresh page (#855), or a spread
5857
5959
  * template on the two facing pages from the next verso (#861). */
5858
5960
  const placeComposedPage = (planned, fence) => {
@@ -5861,7 +5963,11 @@ function placeDocumentPass(content, config, cache, options, hints) {
5861
5963
  leaveCurrentPage();
5862
5964
  cursor.columnIndex = 0;
5863
5965
  const frameless = calloutStyles.find((st) => st.id === FRAME_STYLE_ID);
5864
- const common = (page) => ({
5966
+ /** What every composed page or spread reads; `current` names the
5967
+ * template laid, so a `useTemplate` proposal (#858) tries the book's
5968
+ * other templates of the same kind (single pages for this side, or
5969
+ * spreads). */
5970
+ const common = (page, current) => ({
5865
5971
  pass: framePass,
5866
5972
  fence,
5867
5973
  startIdx: planned.startIdx,
@@ -5873,13 +5979,21 @@ function placeDocumentPass(content, config, cache, options, hints) {
5873
5979
  bodyOffset,
5874
5980
  mirrored: mirroredOf(page),
5875
5981
  pushGapPx: wrapGapPx(resolved.layout.wrap?.gap, dpi, bodyStyle.fontSizePx, floatGapPx),
5982
+ locale: resolvedLocale(resolved),
5983
+ // The book's other templates, for a `useTemplate` proposal (#858).
5984
+ alternatives: () => [...new Set((resolved.pageTemplates ?? []).map((t) => t?.id))].flatMap((id) => {
5985
+ if (typeof id !== 'string' || id === current.id)
5986
+ return [];
5987
+ const alt = resolvePageTemplate(templateSource, id, current.spread ? { spread: true } : { parity: current.parity });
5988
+ return alt && alt.spread === current.spread ? [alt] : [];
5989
+ }),
5876
5990
  });
5877
5991
  const placed = [];
5878
5992
  let laid;
5879
- const sheet = resolvePageTemplate(templateSource, fence.template, { spread: true });
5880
- if (sheet?.spread) {
5881
- // A spread opens on a verso, a parity blank before it when needed,
5882
- // as a comic spread does; the recto after it takes the other half.
5993
+ /** Lay a spread template over the next verso and the recto after it
5994
+ * (`breakToEvenPage` opens the verso, a parity blank before it when
5995
+ * needed, as a comic spread does). */
5996
+ const laySpread = (sheet, extra) => {
5883
5997
  breakToEvenPage();
5884
5998
  const verso = doc.pages[cursor.pageIndex];
5885
5999
  verso.columns = [createVDTColumn(0, verso.contentArea)];
@@ -5897,7 +6011,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
5897
6011
  const left = versoIsLeft ? verso : recto;
5898
6012
  const right = versoIsLeft ? recto : verso;
5899
6013
  const out = layoutComposedSpread({
5900
- ...common(flowMirrored ? right : left),
6014
+ ...common(flowMirrored ? right : left, { id: sheet.id, spread: true }),
6015
+ ...extra,
5901
6016
  template: sheet,
5902
6017
  first: flowMirrored ? right : left,
5903
6018
  second: flowMirrored ? left : right,
@@ -5905,34 +6020,169 @@ function placeDocumentPass(content, config, cache, options, hints) {
5905
6020
  trim: pageMetrics.physical.trimBox,
5906
6021
  bleed: pageMetrics.physical.bleedBox,
5907
6022
  });
6023
+ return { sides: out.sides, warnings: out.warnings, laid: out.laid, continuations: out.continuations };
6024
+ };
6025
+ /** The template `id` for the current page's side, and the boxes its
6026
+ * `area` reads. */
6027
+ const singleOn = (page, id) => {
6028
+ page.columns = [createVDTColumn(0, page.contentArea)];
6029
+ // The physical side: a recto has an odd folio (in either binding).
6030
+ const parity = (page.index + pageIndexOffset) % 2 === 0 ? 'recto' : 'verso';
6031
+ const template = resolvePageTemplate(templateSource, id, { parity });
6032
+ const frames = designFramesOn(page);
6033
+ const area = template.area === 'trim' ? frames.page : template.area === 'bleed' ? frames.bleed : page.contentArea;
6034
+ return { parity, template, areas: { area, page: frames.page, bleed: frames.bleed } };
6035
+ };
6036
+ let continuations;
6037
+ const sheet = resolvePageTemplate(templateSource, fence.template, { spread: true });
6038
+ if (sheet?.spread) {
6039
+ const out = laySpread(sheet, {});
5908
6040
  placed.push(...out.sides);
5909
6041
  composedNotes.push(...out.warnings);
5910
6042
  laid = out.laid;
6043
+ continuations = out.continuations;
5911
6044
  }
5912
6045
  else {
5913
6046
  const page = doc.pages[cursor.pageIndex];
5914
- page.columns = [createVDTColumn(0, page.contentArea)];
5915
- // The physical side: a recto has an odd folio (in either binding).
5916
- const parity = (page.index + pageIndexOffset) % 2 === 0 ? 'recto' : 'verso';
5917
- const template = resolvePageTemplate(templateSource, fence.template, { parity });
5918
- const frames = designFramesOn(page);
5919
- const area = template.area === 'trim' ? frames.page : template.area === 'bleed' ? frames.bleed : page.contentArea;
5920
- const out = layoutComposedPage({
5921
- ...common(page),
6047
+ const { parity, template, areas } = singleOn(page, fence.template);
6048
+ // Kept by what it reads (#857): a page met again is not set again.
6049
+ // A spread is laid out afresh each time (its two sides are one sheet).
6050
+ const out = layoutComposedPageMemo({
6051
+ ...common(page, { id: template.id, spread: false, parity }),
5922
6052
  page,
5923
6053
  template,
5924
- areas: { area, page: frames.page, bleed: frames.bleed },
5925
- });
6054
+ areas,
6055
+ }, composedMemo);
5926
6056
  placed.push({ page, composed: out.composed, blocks: out.blocks });
5927
6057
  composedNotes.push(...out.warnings);
5928
6058
  laid = out.laid;
6059
+ continuations = out.continuations;
5929
6060
  }
5930
- for (const { page, composed, blocks } of placed) {
5931
- page.composed = composed;
5932
- const floats = (page.floats ??= []);
5933
- for (const b of blocks) {
5934
- floats.push(b);
5935
- doc.blocks.push(b);
6061
+ const commit = (list) => {
6062
+ for (const { page, composed, blocks } of list) {
6063
+ page.composed = composed;
6064
+ const floats = (page.floats ??= []);
6065
+ for (const b of blocks) {
6066
+ floats.push(b);
6067
+ doc.blocks.push(b);
6068
+ }
6069
+ }
6070
+ };
6071
+ commit(placed);
6072
+ // Content that goes on on pages added after this one (#859): one page
6073
+ // (or spread) per template it goes on to, generation after generation,
6074
+ // each laid afresh after the pages before it. The added pages are
6075
+ // ordinary pages (numbered, with running heads, sides kept).
6076
+ const frameAt = new Map();
6077
+ const indexFrames = (list) => {
6078
+ for (const s of list)
6079
+ for (const f of s.composed.frames)
6080
+ if (!f.facingBlocks)
6081
+ frameAt.set(f.id, { page: s.page, frame: f });
6082
+ };
6083
+ indexFrames(placed);
6084
+ const overflowTemplateOf = (id) => resolvePageTemplate(templateSource, id)?.overflowTemplate;
6085
+ const firstPage = placed[0]?.page.index ?? cursor.pageIndex;
6086
+ let pending = continuations ?? [];
6087
+ for (let generation = 1; pending.length > 0; generation++) {
6088
+ const last = generation >= MAX_CONTINUATION_PAGES;
6089
+ let queue = pending;
6090
+ pending = [];
6091
+ while (queue.length > 0) {
6092
+ const target = continuationTarget(queue[0], overflowTemplateOf);
6093
+ const same = (c) => {
6094
+ const t = continuationTarget(c, overflowTemplateOf);
6095
+ return t.template === target.template && t.collapse === target.collapse;
6096
+ };
6097
+ const batch = queue.filter(same);
6098
+ queue = queue.filter((c) => !same(c));
6099
+ const spreadSheetT = resolvePageTemplate(templateSource, target.template, { spread: true });
6100
+ // A template with no frames takes nothing.
6101
+ if (!spreadSheetT || spreadSheetT.frames.length === 0)
6102
+ continue;
6103
+ // A fresh page after the last one laid.
6104
+ const start = cursor.pageIndex;
6105
+ do {
6106
+ advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx);
6107
+ } while (cursor.pageIndex === start);
6108
+ cursor.columnIndex = 0;
6109
+ const storiesOf = (receivers) => new Map([...receivers].map(([name, c]) => [name, c.story]));
6110
+ let sides;
6111
+ let notes;
6112
+ let more;
6113
+ let receivers;
6114
+ let laidTemplate;
6115
+ if (spreadSheetT.spread) {
6116
+ const assigned = assignReceivers(spreadSheetT, batch);
6117
+ receivers = assigned.receivers;
6118
+ queue = [...assigned.left, ...queue];
6119
+ laidTemplate = spreadSheetT;
6120
+ const out = laySpread(spreadSheetT, { stories: storiesOf(receivers), continuing: { receivers, generation, collapse: target.collapse, last } });
6121
+ sides = out.sides;
6122
+ notes = out.warnings;
6123
+ more = out.continuations;
6124
+ }
6125
+ else {
6126
+ const page = doc.pages[cursor.pageIndex];
6127
+ const { parity, template, areas } = singleOn(page, target.template);
6128
+ const assigned = assignReceivers(template, batch);
6129
+ receivers = assigned.receivers;
6130
+ queue = [...assigned.left, ...queue];
6131
+ laidTemplate = template;
6132
+ const out = layoutComposedPage({
6133
+ ...common(page, { id: template.id, spread: false, parity }),
6134
+ page,
6135
+ template,
6136
+ areas,
6137
+ stories: storiesOf(receivers),
6138
+ continuing: { receivers, generation, collapse: target.collapse, last },
6139
+ });
6140
+ sides = [{ page, composed: out.composed, blocks: out.blocks }];
6141
+ notes = out.warnings;
6142
+ more = out.continuations;
6143
+ }
6144
+ for (const s of sides)
6145
+ s.composed.continuationOf = firstPage;
6146
+ // On the last page allowed, a frame whose content would still go on
6147
+ // says so (it is cut at its foot).
6148
+ if (last) {
6149
+ const chained = new Set();
6150
+ const nextOf = (n) => {
6151
+ const f = laidTemplate.frames.find((x) => x.name === n);
6152
+ return f ? nextFrameOf(f) : undefined;
6153
+ };
6154
+ for (const name of receivers.keys()) {
6155
+ for (let n = name; n !== undefined && !chained.has(n); n = nextOf(n))
6156
+ chained.add(n);
6157
+ }
6158
+ notes = notes.map((w) => (w.kind === 'frameOverflow' && chained.has(w.frame)
6159
+ ? { kind: 'frameContinuationLimit', template: w.template, frame: w.frame, fenceIndex: w.fenceIndex, pages: generation, overflowMm: w.overflowMm, configPath: w.configPath, ...(w.sourceStart !== undefined ? { sourceStart: w.sourceStart, sourceEnd: w.sourceEnd } : {}), ...(w.pageIndex !== undefined ? { pageIndex: w.pageIndex } : {}) }
6160
+ : w));
6161
+ }
6162
+ commit(sides);
6163
+ indexFrames(sides);
6164
+ composedNotes.push(...notes);
6165
+ // Each frame that sent content on points to the frame that took it,
6166
+ // and its page's log says where it went.
6167
+ for (const c of receivers.values()) {
6168
+ const to = frameElementId(fence.fenceIndex, c.slot, generation);
6169
+ const src = frameAt.get(c.fromFrameId);
6170
+ const dst = frameAt.get(to);
6171
+ if (!src || !dst)
6172
+ continue;
6173
+ src.frame.continuesTo = to;
6174
+ const log = src.page.composed.log;
6175
+ let at = log.length;
6176
+ for (let i = log.length - 1; i >= 0; i--) {
6177
+ if (log[i].frame === c.frame) {
6178
+ at = i + 1;
6179
+ break;
6180
+ }
6181
+ }
6182
+ log.splice(at, 0, { frame: c.frame, kind: 'continued', toPage: dst.page.index, toFrame: to });
6183
+ }
6184
+ if (more)
6185
+ pending.push(...more);
5936
6186
  }
5937
6187
  }
5938
6188
  for (const [head, story] of planned.stories) {
@@ -6669,6 +6919,12 @@ function placeDocumentPass(content, config, cache, options, hints) {
6669
6919
  pendingSpacing = 0;
6670
6920
  inlineGapOwed = null;
6671
6921
  const exWidth = wrapExclusionWidth(rCol.bbox.width, rCol.bbox.width * wrapSpec.width, wrapGap);
6922
+ // A contour wrap (#883): the picture's shape where it was set.
6923
+ const slotWidth = rCol.bbox.width * wrapSpec.width;
6924
+ const slot = { x: wrapSpec.side === 'left' ? rCol.bbox.x : rCol.bbox.x + rCol.bbox.width - slotWidth, y: top, width: slotWidth, height: groupHeight };
6925
+ const contour = wrapSpec.contour
6926
+ ? wrapContourOf(kind.resource, resourceBlock, slot, wrapGap, doc.pages[cursor.pageIndex], { x: blk.bbox.x, y: blk.bbox.y }, { sourceStart: rawBlock.sourceStart + bodyOffset, sourceEnd: rawBlock.sourceEnd + bodyOffset })
6927
+ : undefined;
6672
6928
  pendingWrap = {
6673
6929
  col: rCol,
6674
6930
  blocks: rCol.blocks.length,
@@ -6681,6 +6937,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
6681
6937
  side: wrapSpec.side,
6682
6938
  gap: exWidth - rCol.bbox.width * wrapSpec.width,
6683
6939
  ownerId: blk.id,
6940
+ ...(contour ? { contour } : {}),
6684
6941
  },
6685
6942
  };
6686
6943
  flushPendingNumberingAtBoundary();
@@ -8212,6 +8469,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
8212
8469
  // reverse of their visual order.
8213
8470
  if (doc.pages.some((p) => pageIsMirrored(p)))
8214
8471
  orientLinesToFrames(doc);
8472
+ // Figure labels (#860): where each one is painted, for the source map.
8473
+ stampFigureLabelRects(doc);
8215
8474
  doc.converged = true;
8216
8475
  doc.iterationCount = 1;
8217
8476
  if (joiningLetterSpacing.size > 0)
@@ -8223,8 +8482,13 @@ function placeDocumentPass(content, config, cache, options, hints) {
8223
8482
  const b = contentBlocks[idx];
8224
8483
  return b ? { start: b.sourceStart + bodyOffset, end: b.sourceEnd + bodyOffset } : undefined;
8225
8484
  });
8226
- if (shrunk.length > 0)
8227
- floatShrinkWarningsByDoc.set(doc, shrunk);
8485
+ // Pictures whose column holds them under half their print size (#901).
8486
+ const belowPrint = pictureBelowPrintSizeWarnings(doc, givenResources, (idx) => {
8487
+ const b = contentBlocks[idx];
8488
+ return b ? { start: b.sourceStart + bodyOffset, end: b.sourceEnd + bodyOffset } : undefined;
8489
+ });
8490
+ if (shrunk.length > 0 || belowPrint.length > 0)
8491
+ floatShrinkWarningsByDoc.set(doc, [...shrunk, ...belowPrint]);
8228
8492
  if (textWrapNotes.length > 0 || columnsNotes.length > 0)
8229
8493
  textWrapWarningsByDoc.set(doc, [...textWrapNotes, ...columnsNotes]);
8230
8494
  // Composed pages (#855): frames whose content does not fit.
@@ -8310,6 +8574,9 @@ export function* buildDocumentGen(content, config, cache, options) {
8310
8574
  loose.push(...afterTextWarnings(doc), ...(unplacedByDoc.get(doc) ?? []));
8311
8575
  // Design texts cut to fit their width (#628).
8312
8576
  loose.push(...designTruncationWarnings(doc));
8577
+ // Figure labels at anchors their picture lacks, anchors left without a
8578
+ // word in this locale (#860).
8579
+ loose.push(...figureLabelWarnings(doc, (b) => (b.sourceStart !== undefined && b.sourceEnd !== undefined ? { start: b.sourceStart, end: b.sourceEnd } : undefined)));
8313
8580
  // Comic panels whose cell cannot hold their picture's safe area (#556).
8314
8581
  for (const page of doc.pages) {
8315
8582
  if (page.comic)
@@ -8360,7 +8627,8 @@ const indexWarnings = new WeakMap();
8360
8627
  const joiningSpacingWarnings = new WeakMap();
8361
8628
  /** The `dropCap` warnings of the last pass, per document (#623). */
8362
8629
  const dropCapWarningsByDoc = new WeakMap();
8363
- /** The `floatShrunk` warnings of a build (#626), found by its last pass. */
8630
+ /** The `floatShrunk` (#626) and `pictureBelowPrintSize` (#901) warnings
8631
+ * of a build, found by its last pass. */
8364
8632
  const floatShrinkWarningsByDoc = new WeakMap();
8365
8633
  /** The `textWrap` warnings of a build (#627) and its `columnsTooNarrow`
8366
8634
  * ones (#634), found by its last pass. */