postext 1.47.0 → 1.48.1

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 (336) hide show
  1. package/dist/__tests__/bundle/designOverflowPin.test.js +1 -1
  2. package/dist/__tests__/bundle/gridBreakRulesPin.test.js +2 -2
  3. package/dist/__tests__/bundle/shapingLanguagePin.test.js +3 -3
  4. package/dist/__tests__/bundle/taskBoxPin.test.js +1 -1
  5. package/dist/__tests__/bundle.test.js +1 -1
  6. package/dist/__tests__/codeBlocks.test.js +1 -1
  7. package/dist/__tests__/composed/cardShapes.test.d.ts +2 -0
  8. package/dist/__tests__/composed/cardShapes.test.d.ts.map +1 -0
  9. package/dist/__tests__/composed/cardShapes.test.js +82 -0
  10. package/dist/__tests__/composed/cardShapes.test.js.map +1 -0
  11. package/dist/__tests__/composed/connectors.test.d.ts +2 -0
  12. package/dist/__tests__/composed/connectors.test.d.ts.map +1 -0
  13. package/dist/__tests__/composed/connectors.test.js +349 -0
  14. package/dist/__tests__/composed/connectors.test.js.map +1 -0
  15. package/dist/__tests__/composed/decorationSidePoints.test.d.ts +2 -0
  16. package/dist/__tests__/composed/decorationSidePoints.test.d.ts.map +1 -0
  17. package/dist/__tests__/composed/decorationSidePoints.test.js +164 -0
  18. package/dist/__tests__/composed/decorationSidePoints.test.js.map +1 -0
  19. package/dist/__tests__/composed/fit.test.js +2 -1
  20. package/dist/__tests__/composed/fit.test.js.map +1 -1
  21. package/dist/__tests__/composed/fixtures/connectors.d.ts +33 -0
  22. package/dist/__tests__/composed/fixtures/connectors.d.ts.map +1 -0
  23. package/dist/__tests__/composed/fixtures/connectors.js +142 -0
  24. package/dist/__tests__/composed/fixtures/connectors.js.map +1 -0
  25. package/dist/__tests__/composed/fixtures/grid.d.ts +32 -0
  26. package/dist/__tests__/composed/fixtures/grid.d.ts.map +1 -0
  27. package/dist/__tests__/composed/fixtures/grid.js +53 -0
  28. package/dist/__tests__/composed/fixtures/grid.js.map +1 -0
  29. package/dist/__tests__/composed/fixtures/legendMap.d.ts +24 -0
  30. package/dist/__tests__/composed/fixtures/legendMap.d.ts.map +1 -0
  31. package/dist/__tests__/composed/fixtures/legendMap.js +117 -0
  32. package/dist/__tests__/composed/fixtures/legendMap.js.map +1 -0
  33. package/dist/__tests__/composed/fixtures/mapParts.d.ts +58 -0
  34. package/dist/__tests__/composed/fixtures/mapParts.d.ts.map +1 -0
  35. package/dist/__tests__/composed/fixtures/mapParts.js +192 -0
  36. package/dist/__tests__/composed/fixtures/mapParts.js.map +1 -0
  37. package/dist/__tests__/composed/fixtures/modules.d.ts +55 -0
  38. package/dist/__tests__/composed/fixtures/modules.d.ts.map +1 -0
  39. package/dist/__tests__/composed/fixtures/modules.js +123 -0
  40. package/dist/__tests__/composed/fixtures/modules.js.map +1 -0
  41. package/dist/__tests__/composed/grid.test.d.ts +2 -0
  42. package/dist/__tests__/composed/grid.test.d.ts.map +1 -0
  43. package/dist/__tests__/composed/grid.test.js +357 -0
  44. package/dist/__tests__/composed/grid.test.js.map +1 -0
  45. package/dist/__tests__/composed/groups.test.js +6 -3
  46. package/dist/__tests__/composed/groups.test.js.map +1 -1
  47. package/dist/__tests__/composed/labelLegend.test.d.ts +2 -0
  48. package/dist/__tests__/composed/labelLegend.test.d.ts.map +1 -0
  49. package/dist/__tests__/composed/labelLegend.test.js +268 -0
  50. package/dist/__tests__/composed/labelLegend.test.js.map +1 -0
  51. package/dist/__tests__/composed/labelsChecks.test.js.map +1 -1
  52. package/dist/__tests__/composed/leaders.test.d.ts +2 -0
  53. package/dist/__tests__/composed/leaders.test.d.ts.map +1 -0
  54. package/dist/__tests__/composed/leaders.test.js +372 -0
  55. package/dist/__tests__/composed/leaders.test.js.map +1 -0
  56. package/dist/__tests__/composed/moduleConnectorPage.test.d.ts +2 -0
  57. package/dist/__tests__/composed/moduleConnectorPage.test.d.ts.map +1 -0
  58. package/dist/__tests__/composed/moduleConnectorPage.test.js +76 -0
  59. package/dist/__tests__/composed/moduleConnectorPage.test.js.map +1 -0
  60. package/dist/__tests__/composed/modules.test.d.ts +2 -0
  61. package/dist/__tests__/composed/modules.test.d.ts.map +1 -0
  62. package/dist/__tests__/composed/modules.test.js +352 -0
  63. package/dist/__tests__/composed/modules.test.js.map +1 -0
  64. package/dist/__tests__/composed/overConnectors.test.d.ts +2 -0
  65. package/dist/__tests__/composed/overConnectors.test.d.ts.map +1 -0
  66. package/dist/__tests__/composed/overConnectors.test.js +232 -0
  67. package/dist/__tests__/composed/overConnectors.test.js.map +1 -0
  68. package/dist/__tests__/composed/overlap.test.d.ts +2 -0
  69. package/dist/__tests__/composed/overlap.test.d.ts.map +1 -0
  70. package/dist/__tests__/composed/overlap.test.js +339 -0
  71. package/dist/__tests__/composed/overlap.test.js.map +1 -0
  72. package/dist/__tests__/composedTemplates.test.js +1 -1
  73. package/dist/__tests__/design/boxShape.test.d.ts +2 -0
  74. package/dist/__tests__/design/boxShape.test.d.ts.map +1 -0
  75. package/dist/__tests__/design/boxShape.test.js +126 -0
  76. package/dist/__tests__/design/boxShape.test.js.map +1 -0
  77. package/dist/__tests__/design/boxShapePaint.test.d.ts +2 -0
  78. package/dist/__tests__/design/boxShapePaint.test.d.ts.map +1 -0
  79. package/dist/__tests__/design/boxShapePaint.test.js +130 -0
  80. package/dist/__tests__/design/boxShapePaint.test.js.map +1 -0
  81. package/dist/__tests__/design/openerBottomAnchor.test.js.map +1 -1
  82. package/dist/__tests__/design/pathBlock.test.d.ts +2 -0
  83. package/dist/__tests__/design/pathBlock.test.d.ts.map +1 -0
  84. package/dist/__tests__/design/pathBlock.test.js +194 -0
  85. package/dist/__tests__/design/pathBlock.test.js.map +1 -0
  86. package/dist/__tests__/design/pathElement.test.d.ts +2 -0
  87. package/dist/__tests__/design/pathElement.test.d.ts.map +1 -0
  88. package/dist/__tests__/design/pathElement.test.js +257 -0
  89. package/dist/__tests__/design/pathElement.test.js.map +1 -0
  90. package/dist/__tests__/design/svgPath.test.d.ts +2 -0
  91. package/dist/__tests__/design/svgPath.test.d.ts.map +1 -0
  92. package/dist/__tests__/design/svgPath.test.js +144 -0
  93. package/dist/__tests__/design/svgPath.test.js.map +1 -0
  94. package/dist/__tests__/exports.test.js +52 -0
  95. package/dist/__tests__/exports.test.js.map +1 -1
  96. package/dist/__tests__/hardBreaks.test.js +1 -1
  97. package/dist/__tests__/headingInlineMarks.test.js +1 -1
  98. package/dist/__tests__/labelGlyphPaint.test.d.ts +2 -0
  99. package/dist/__tests__/labelGlyphPaint.test.d.ts.map +1 -0
  100. package/dist/__tests__/labelGlyphPaint.test.js +86 -0
  101. package/dist/__tests__/labelGlyphPaint.test.js.map +1 -0
  102. package/dist/__tests__/mathSizeMigration.test.js +2 -2
  103. package/dist/__tests__/migrate/labelsOnPictures.test.js +1 -1
  104. package/dist/__tests__/migrate/labelsOnPictures.test.js.map +1 -1
  105. package/dist/__tests__/parse/containers.test.js +1 -1
  106. package/dist/__tests__/parse/containers.test.js.map +1 -1
  107. package/dist/__tests__/pipeline/calloutInlineResourceGap.test.js +1 -1
  108. package/dist/__tests__/pipeline/calloutLabelGlyph.test.d.ts +2 -0
  109. package/dist/__tests__/pipeline/calloutLabelGlyph.test.d.ts.map +1 -0
  110. package/dist/__tests__/pipeline/calloutLabelGlyph.test.js +198 -0
  111. package/dist/__tests__/pipeline/calloutLabelGlyph.test.js.map +1 -0
  112. package/dist/__tests__/pipeline/calloutShapes.test.d.ts +2 -0
  113. package/dist/__tests__/pipeline/calloutShapes.test.d.ts.map +1 -0
  114. package/dist/__tests__/pipeline/calloutShapes.test.js +159 -0
  115. package/dist/__tests__/pipeline/calloutShapes.test.js.map +1 -0
  116. package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js +1 -1
  117. package/dist/__tests__/pipeline/colonListRoom.test.js +1 -1
  118. package/dist/__tests__/pipeline/compoundBreaks.test.js +1 -1
  119. package/dist/__tests__/pipeline/dashBreaks.test.js +1 -1
  120. package/dist/__tests__/pipeline/headingSplitOrphans.test.js +1 -1
  121. package/dist/__tests__/pipeline/inlineFigureSpace.test.js +1 -1
  122. package/dist/__tests__/pipeline/paragraphContainerTail.test.js +1 -1
  123. package/dist/__tests__/pipeline/raggedOptimal.test.js +1 -1
  124. package/dist/__tests__/verseLines.test.js +1 -1
  125. package/dist/bundle/configVersion.d.ts +12 -3
  126. package/dist/bundle/configVersion.d.ts.map +1 -1
  127. package/dist/bundle/configVersion.js +16 -5
  128. package/dist/bundle/configVersion.js.map +1 -1
  129. package/dist/canvas-backend/blockRender.js +3 -3
  130. package/dist/canvas-backend/blockRender.js.map +1 -1
  131. package/dist/canvas-backend/composed.d.ts +4 -2
  132. package/dist/canvas-backend/composed.d.ts.map +1 -1
  133. package/dist/canvas-backend/composed.js +12 -7
  134. package/dist/canvas-backend/composed.js.map +1 -1
  135. package/dist/canvas-backend/headerFooter.d.ts +17 -1
  136. package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
  137. package/dist/canvas-backend/headerFooter.js +64 -1
  138. package/dist/canvas-backend/headerFooter.js.map +1 -1
  139. package/dist/canvas-backend/index.d.ts.map +1 -1
  140. package/dist/canvas-backend/index.js +7 -1
  141. package/dist/canvas-backend/index.js.map +1 -1
  142. package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
  143. package/dist/canvas-backend/renderResourceBlock.js +17 -6
  144. package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
  145. package/dist/canvas-backend/swatch.d.ts +20 -1
  146. package/dist/canvas-backend/swatch.d.ts.map +1 -1
  147. package/dist/canvas-backend/swatch.js +51 -1
  148. package/dist/canvas-backend/swatch.js.map +1 -1
  149. package/dist/comics/layoutPage.d.ts.map +1 -1
  150. package/dist/comics/layoutPage.js +6 -1
  151. package/dist/comics/layoutPage.js.map +1 -1
  152. package/dist/composed/continuation.d.ts +10 -2
  153. package/dist/composed/continuation.d.ts.map +1 -1
  154. package/dist/composed/continuation.js +10 -2
  155. package/dist/composed/continuation.js.map +1 -1
  156. package/dist/composed/document.d.ts +45 -1
  157. package/dist/composed/document.d.ts.map +1 -1
  158. package/dist/composed/document.js +76 -17
  159. package/dist/composed/document.js.map +1 -1
  160. package/dist/composed/labelText.d.ts +6 -2
  161. package/dist/composed/labelText.d.ts.map +1 -1
  162. package/dist/composed/labelText.js +19 -3
  163. package/dist/composed/labelText.js.map +1 -1
  164. package/dist/composed/labels.d.ts +57 -3
  165. package/dist/composed/labels.d.ts.map +1 -1
  166. package/dist/composed/labels.js +261 -12
  167. package/dist/composed/labels.js.map +1 -1
  168. package/dist/composed/modules.d.ts +30 -0
  169. package/dist/composed/modules.d.ts.map +1 -0
  170. package/dist/composed/modules.js +194 -0
  171. package/dist/composed/modules.js.map +1 -0
  172. package/dist/composed/overlap.d.ts +52 -0
  173. package/dist/composed/overlap.d.ts.map +1 -0
  174. package/dist/composed/overlap.js +611 -0
  175. package/dist/composed/overlap.js.map +1 -0
  176. package/dist/composed/paint.d.ts +28 -5
  177. package/dist/composed/paint.d.ts.map +1 -1
  178. package/dist/composed/paint.js +26 -5
  179. package/dist/composed/paint.js.map +1 -1
  180. package/dist/composed/reflowLog.d.ts +6 -1
  181. package/dist/composed/reflowLog.d.ts.map +1 -1
  182. package/dist/composed/reflowLog.js +43 -0
  183. package/dist/composed/reflowLog.js.map +1 -1
  184. package/dist/composed/repeat.d.ts +66 -0
  185. package/dist/composed/repeat.d.ts.map +1 -0
  186. package/dist/composed/repeat.js +217 -0
  187. package/dist/composed/repeat.js.map +1 -0
  188. package/dist/composed/slotChecks.d.ts +1 -1
  189. package/dist/composed/slotChecks.d.ts.map +1 -1
  190. package/dist/composed/slotChecks.js +114 -8
  191. package/dist/composed/slotChecks.js.map +1 -1
  192. package/dist/composed/sourceMap.d.ts.map +1 -1
  193. package/dist/composed/sourceMap.js +16 -4
  194. package/dist/composed/sourceMap.js.map +1 -1
  195. package/dist/composed/spread.d.ts.map +1 -1
  196. package/dist/composed/spread.js +6 -2
  197. package/dist/composed/spread.js.map +1 -1
  198. package/dist/composed/templates.d.ts +22 -2
  199. package/dist/composed/templates.d.ts.map +1 -1
  200. package/dist/composed/templates.js +166 -10
  201. package/dist/composed/templates.js.map +1 -1
  202. package/dist/composed/types.d.ts +140 -7
  203. package/dist/composed/types.d.ts.map +1 -1
  204. package/dist/composed/validate.d.ts +1 -1
  205. package/dist/composed/validate.d.ts.map +1 -1
  206. package/dist/composed/validate.js +101 -4
  207. package/dist/composed/validate.js.map +1 -1
  208. package/dist/composed/wrap.d.ts.map +1 -1
  209. package/dist/composed/wrap.js +95 -17
  210. package/dist/composed/wrap.js.map +1 -1
  211. package/dist/configWarnings.d.ts +7 -1
  212. package/dist/configWarnings.d.ts.map +1 -1
  213. package/dist/configWarnings.js +275 -4
  214. package/dist/configWarnings.js.map +1 -1
  215. package/dist/contrast.d.ts.map +1 -1
  216. package/dist/contrast.js +8 -0
  217. package/dist/contrast.js.map +1 -1
  218. package/dist/defaults/calloutStyles.d.ts +10 -1
  219. package/dist/defaults/calloutStyles.d.ts.map +1 -1
  220. package/dist/defaults/calloutStyles.js +46 -7
  221. package/dist/defaults/calloutStyles.js.map +1 -1
  222. package/dist/defaults/headerFooter.d.ts.map +1 -1
  223. package/dist/defaults/headerFooter.js +38 -0
  224. package/dist/defaults/headerFooter.js.map +1 -1
  225. package/dist/design/boxShape.d.ts +101 -0
  226. package/dist/design/boxShape.d.ts.map +1 -0
  227. package/dist/design/boxShape.js +398 -0
  228. package/dist/design/boxShape.js.map +1 -0
  229. package/dist/design/connector.d.ts +75 -0
  230. package/dist/design/connector.d.ts.map +1 -0
  231. package/dist/design/connector.js +325 -0
  232. package/dist/design/connector.js.map +1 -0
  233. package/dist/design/layout.d.ts +56 -3
  234. package/dist/design/layout.d.ts.map +1 -1
  235. package/dist/design/layout.js +214 -12
  236. package/dist/design/layout.js.map +1 -1
  237. package/dist/design/logicalEdges.d.ts +7 -0
  238. package/dist/design/logicalEdges.d.ts.map +1 -1
  239. package/dist/design/logicalEdges.js +28 -0
  240. package/dist/design/logicalEdges.js.map +1 -1
  241. package/dist/design/pathBlock.d.ts +69 -0
  242. package/dist/design/pathBlock.d.ts.map +1 -0
  243. package/dist/design/pathBlock.js +286 -0
  244. package/dist/design/pathBlock.js.map +1 -0
  245. package/dist/design/svgPath.d.ts +48 -0
  246. package/dist/design/svgPath.d.ts.map +1 -0
  247. package/dist/design/svgPath.js +402 -0
  248. package/dist/design/svgPath.js.map +1 -0
  249. package/dist/fonts/usage.d.ts +5 -0
  250. package/dist/fonts/usage.d.ts.map +1 -1
  251. package/dist/fonts/usage.js +36 -3
  252. package/dist/fonts/usage.js.map +1 -1
  253. package/dist/html-backend.d.ts.map +1 -1
  254. package/dist/html-backend.js +127 -22
  255. package/dist/html-backend.js.map +1 -1
  256. package/dist/index.d.ts +19 -9
  257. package/dist/index.d.ts.map +1 -1
  258. package/dist/index.js +13 -5
  259. package/dist/index.js.map +1 -1
  260. package/dist/measure/cache.js +1 -1
  261. package/dist/measure/cache.js.map +1 -1
  262. package/dist/measure/inlineIcon.d.ts +34 -0
  263. package/dist/measure/inlineIcon.d.ts.map +1 -0
  264. package/dist/measure/inlineIcon.js +89 -0
  265. package/dist/measure/inlineIcon.js.map +1 -0
  266. package/dist/measure/rich.d.ts +2 -1
  267. package/dist/measure/rich.d.ts.map +1 -1
  268. package/dist/measure/rich.js +6 -0
  269. package/dist/measure/rich.js.map +1 -1
  270. package/dist/migrate/pageDesign.d.ts.map +1 -1
  271. package/dist/migrate/pageDesign.js +4 -2
  272. package/dist/migrate/pageDesign.js.map +1 -1
  273. package/dist/migrate/textToMarkdown.js +2 -0
  274. package/dist/migrate/textToMarkdown.js.map +1 -1
  275. package/dist/parse/blockParser.d.ts.map +1 -1
  276. package/dist/parse/blockParser.js +171 -20
  277. package/dist/parse/blockParser.js.map +1 -1
  278. package/dist/parse/index.d.ts +1 -1
  279. package/dist/parse/index.d.ts.map +1 -1
  280. package/dist/parse/index.js.map +1 -1
  281. package/dist/parse/inlineFormatting.d.ts +11 -3
  282. package/dist/parse/inlineFormatting.d.ts.map +1 -1
  283. package/dist/parse/inlineFormatting.js +63 -5
  284. package/dist/parse/inlineFormatting.js.map +1 -1
  285. package/dist/parse/inlineSnippet.d.ts +2 -1
  286. package/dist/parse/inlineSnippet.d.ts.map +1 -1
  287. package/dist/parse/inlineSnippet.js +3 -2
  288. package/dist/parse/inlineSnippet.js.map +1 -1
  289. package/dist/parse/sourceMapping.d.ts.map +1 -1
  290. package/dist/parse/sourceMapping.js +8 -1
  291. package/dist/parse/sourceMapping.js.map +1 -1
  292. package/dist/parse/types.d.ts +71 -1
  293. package/dist/parse/types.d.ts.map +1 -1
  294. package/dist/pipeline/build.d.ts.map +1 -1
  295. package/dist/pipeline/build.js +23 -11
  296. package/dist/pipeline/build.js.map +1 -1
  297. package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
  298. package/dist/pipeline/buildMeasurement.js +23 -11
  299. package/dist/pipeline/buildMeasurement.js.map +1 -1
  300. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  301. package/dist/pipeline/calloutLayout.js +142 -32
  302. package/dist/pipeline/calloutLayout.js.map +1 -1
  303. package/dist/pipeline/composedLayout.d.ts +1 -33
  304. package/dist/pipeline/composedLayout.d.ts.map +1 -1
  305. package/dist/pipeline/composedLayout.js +526 -36
  306. package/dist/pipeline/composedLayout.js.map +1 -1
  307. package/dist/pipeline/contentWarnings.d.ts.map +1 -1
  308. package/dist/pipeline/contentWarnings.js +46 -1
  309. package/dist/pipeline/contentWarnings.js.map +1 -1
  310. package/dist/pipeline/continuation.d.ts.map +1 -1
  311. package/dist/pipeline/continuation.js +3 -2
  312. package/dist/pipeline/continuation.js.map +1 -1
  313. package/dist/pipeline/headerFooter.d.ts +19 -1
  314. package/dist/pipeline/headerFooter.d.ts.map +1 -1
  315. package/dist/pipeline/headerFooter.js +145 -5
  316. package/dist/pipeline/headerFooter.js.map +1 -1
  317. package/dist/pipeline/partPalette.d.ts.map +1 -1
  318. package/dist/pipeline/partPalette.js +40 -1
  319. package/dist/pipeline/partPalette.js.map +1 -1
  320. package/dist/pipeline/resourceLayout.d.ts +1 -1
  321. package/dist/pipeline/resourceLayout.d.ts.map +1 -1
  322. package/dist/pipeline/resourceLayout.js +44 -15
  323. package/dist/pipeline/resourceLayout.js.map +1 -1
  324. package/dist/preflight.d.ts.map +1 -1
  325. package/dist/preflight.js +36 -1
  326. package/dist/preflight.js.map +1 -1
  327. package/dist/types.d.ts +305 -22
  328. package/dist/types.d.ts.map +1 -1
  329. package/dist/vdt.d.ts +384 -11
  330. package/dist/vdt.d.ts.map +1 -1
  331. package/dist/vdt.js.map +1 -1
  332. package/package.json +1 -1
  333. package/dist/composed/round2Types.d.ts +0 -185
  334. package/dist/composed/round2Types.d.ts.map +0 -1
  335. package/dist/composed/round2Types.js +0 -2
  336. package/dist/composed/round2Types.js.map +0 -1
@@ -0,0 +1,611 @@
1
+ import { physicalEdge } from '../design/logicalEdges';
2
+ import { dimensionToPx } from '../units';
3
+ import { anchorOn } from './geometry';
4
+ import { frameClips, frameContentRect, frameMatrix } from './paint';
5
+ import { anchorTarget } from './templates';
6
+ const MM_PER_IN = 25.4;
7
+ /** Overlaps thinner than this (mm) are a touch, not a cover: a line box
8
+ * holds its leading, two frames set edge to edge meet without hiding
9
+ * anything. */
10
+ const MIN_DEPTH_MM = 0.3;
11
+ /** The least area covered that is reported (mm²). */
12
+ const MIN_AREA_MM2 = 1;
13
+ /** The least overrun that is reported (mm). */
14
+ const MIN_EXCESS_MM = 0.3;
15
+ /** The box holding `r` once put on the sheet by `m`. */
16
+ function mapRect(r, m) {
17
+ if (!m)
18
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
19
+ const xs = [];
20
+ const ys = [];
21
+ for (const [x, y] of [[r.x, r.y], [r.x + r.width, r.y], [r.x, r.y + r.height], [r.x + r.width, r.y + r.height]]) {
22
+ xs.push(m[0] * x + m[2] * y + m[4]);
23
+ ys.push(m[1] * x + m[3] * y + m[5]);
24
+ }
25
+ const x = Math.min(...xs);
26
+ const y = Math.min(...ys);
27
+ return { x, y, width: Math.max(...xs) - x, height: Math.max(...ys) - y };
28
+ }
29
+ function intersect(a, b) {
30
+ const x = Math.max(a.x, b.x);
31
+ const y = Math.max(a.y, b.y);
32
+ const r = Math.min(a.x + a.width, b.x + b.width);
33
+ const btm = Math.min(a.y + a.height, b.y + b.height);
34
+ return r > x && btm > y ? { x, y, width: r - x, height: btm - y } : undefined;
35
+ }
36
+ /** Area of the union of `rects` (few: a sweep over their edges). */
37
+ function unionArea(rects) {
38
+ if (rects.length === 0)
39
+ return 0;
40
+ if (rects.length === 1)
41
+ return rects[0].width * rects[0].height;
42
+ const xs = [...new Set(rects.flatMap((r) => [r.x, r.x + r.width]))].sort((a, b) => a - b);
43
+ let area = 0;
44
+ for (let i = 0; i + 1 < xs.length; i++) {
45
+ const x0 = xs[i];
46
+ const x1 = xs[i + 1];
47
+ const spans = rects
48
+ .filter((r) => r.x <= x0 && r.x + r.width >= x1)
49
+ .map((r) => [r.y, r.y + r.height])
50
+ .sort((a, b) => a[0] - b[0]);
51
+ let covered = 0;
52
+ let lo = -Infinity;
53
+ let hi = -Infinity;
54
+ for (const [a, b] of spans) {
55
+ if (a > hi) {
56
+ covered += hi - lo > 0 ? hi - lo : 0;
57
+ lo = a;
58
+ hi = b;
59
+ }
60
+ else if (b > hi)
61
+ hi = b;
62
+ }
63
+ covered += hi - lo > 0 ? hi - lo : 0;
64
+ area += covered * (x1 - x0);
65
+ }
66
+ return area;
67
+ }
68
+ /** A colour that hides what is under it: not transparent, and at least
69
+ * half opaque when it carries an alpha (`#rrggbbaa`). */
70
+ function opaque(color) {
71
+ if (!color)
72
+ return false;
73
+ const c = color.trim().toLowerCase();
74
+ if (c === '' || c === 'transparent' || c === 'none')
75
+ return false;
76
+ if (/^#[0-9a-f]{8}$/.test(c))
77
+ return parseInt(c.slice(7, 9), 16) >= 0x80;
78
+ if (/^#[0-9a-f]{4}$/.test(c))
79
+ return parseInt(c.slice(4, 5), 16) >= 8;
80
+ return true;
81
+ }
82
+ /** The size in px a design text's font string names (`bold 12px "X"`). */
83
+ function fontPx(font) {
84
+ const m = /(\d+(?:\.\d+)?)px/.exec(font);
85
+ return m ? Number(m[1]) : 12;
86
+ }
87
+ /** The ink of a design slot's blocks (a box's overlay: its fill, tab,
88
+ * stripe, icon, title). */
89
+ function designInk(blocks, out) {
90
+ for (const b of blocks) {
91
+ if (b.kind === 'box') {
92
+ if (opaque(b.box.backgroundColor))
93
+ out.push({ box: { ...b.bbox }, kind: 'fill' });
94
+ else if (b.box.borderColor && b.box.borderWidthPx > 0)
95
+ out.push({ box: { ...b.bbox }, kind: 'fill' });
96
+ }
97
+ else if (b.kind === 'path' && b.boxPart && b.fill) {
98
+ // A card joined to its tab (#1059), as a box.
99
+ out.push({ box: { ...b.bbox }, kind: 'fill' });
100
+ }
101
+ else if (b.kind === 'image') {
102
+ out.push({ box: { ...b.bbox }, kind: 'picture' });
103
+ }
104
+ else if (b.kind === 'rule') {
105
+ out.push({ box: { ...b.bbox }, kind: 'fill' });
106
+ }
107
+ else if (b.kind === 'text') {
108
+ if (b.vertical) {
109
+ const words = b.lines.map((l) => l.text).join(' ').trim();
110
+ if (words)
111
+ out.push({ box: { ...b.bbox }, kind: 'text', flow: 'fixed', text: words });
112
+ continue;
113
+ }
114
+ const size = fontPx(b.fontString);
115
+ for (const l of b.lines) {
116
+ if (l.text.trim() === '' || l.width <= 0)
117
+ continue;
118
+ out.push({ box: { x: b.bbox.x + l.xOffset, y: l.baselineY - 0.8 * size, width: l.width, height: size }, kind: 'text', flow: 'fixed', text: l.text });
119
+ }
120
+ }
121
+ }
122
+ }
123
+ /** A box's border alone does not hide what is under its middle: the fill
124
+ * pieces that only stroke an outline cover along it. */
125
+ function isOutlineOnly(b) {
126
+ return (b.kind === 'box' && !opaque(b.box.backgroundColor) && !!b.box.borderColor && b.box.borderWidthPx > 0)
127
+ || (b.kind === 'path' && b.boxPart === 'border');
128
+ }
129
+ /** The ink of one frame, in its blocks' own (laid-out) coordinates: what
130
+ * it paints. `covering` leaves out outlines (they hide only a hairline)
131
+ * and keeps what hides what is under it. */
132
+ function frameInk(blocks, covering) {
133
+ const out = [];
134
+ for (const b of blocks) {
135
+ if (b.hidden)
136
+ continue;
137
+ if (b.designOverlay) {
138
+ const overlay = covering ? b.designOverlay.blocks.filter((d) => !isOutlineOnly(d)) : b.designOverlay.blocks;
139
+ designInk(overlay, out);
140
+ // A heading design paints its overlay instead of its lines.
141
+ if (b.type !== 'callout')
142
+ continue;
143
+ }
144
+ const rb = b.resourceBlock;
145
+ if (rb) {
146
+ const body = rb.rotation ? { ...b.bbox } : { x: b.bbox.x + rb.bodyRect.x, y: b.bbox.y + rb.bodyRect.y, width: rb.bodyRect.width, height: rb.bodyRect.height };
147
+ if (rb.kind === 'bitmap' || rb.kind === 'svg' || rb.kind === 'video')
148
+ out.push({ box: body, kind: 'picture', resourceId: rb.resource.id });
149
+ else if (!covering)
150
+ out.push({ box: body, kind: 'text', flow: 'fixed', text: rb.resource.id });
151
+ if (!rb.rotation) {
152
+ for (const l of [...rb.captionLines, ...rb.noteLines]) {
153
+ if (l.text.trim() !== '')
154
+ out.push({ box: { ...l.bbox }, kind: 'text', flow: 'fixed', text: l.text });
155
+ }
156
+ }
157
+ continue;
158
+ }
159
+ for (const l of b.lines) {
160
+ if (l.text.trim() === '' || l.bbox.width <= 0 || l.bbox.height <= 0)
161
+ continue;
162
+ out.push({ box: { ...l.bbox }, kind: 'text', flow: 'line', text: l.text });
163
+ }
164
+ }
165
+ return out;
166
+ }
167
+ const ELEMENT_EDGES = new Set(['right-of', 'left-of', 'below', 'above', 'align-top', 'align-bottom', 'align-left', 'align-right', 'align-start', 'align-end']);
168
+ /** Rounded to 0.1. */
169
+ const r1 = (v) => Math.round(v * 10) / 10;
170
+ /**
171
+ * The overlap warnings of one composed page (or the sheet of a spread),
172
+ * and the reflow log's events for them.
173
+ */
174
+ export function overlapChecks(input) {
175
+ const { template, dpi } = input;
176
+ const mmPx = dpi / MM_PER_IN;
177
+ const resolved = new Map(template.frames.map((f) => [f.name, f]));
178
+ const order = new Map(template.frames.map((f, i) => [f.name, i]));
179
+ const byId = new Map(input.blocks.map((b) => [b.id, b]));
180
+ const live = input.frames.filter((f) => !f.collapsed && !f.facingBlocks && resolved.has(f.name));
181
+ /** Each frame's ink on the sheet, covered side and covering side, clipped
182
+ * to its box when its content overflows (painted clipped). */
183
+ const inkOf = new Map();
184
+ for (const f of live) {
185
+ const blocks = f.blockIds.map((id) => byId.get(id)).filter((b) => b !== undefined);
186
+ const m = frameMatrix(f);
187
+ const clip = frameClips(f) ? frameContentRect(f) : undefined;
188
+ const place = (list) => list.flatMap((ink) => {
189
+ const cut = clip ? intersect(ink.box, clip) : ink.box;
190
+ return cut ? [{ ...ink, box: mapRect(cut, m) }] : [];
191
+ });
192
+ const rules = (f.rules ?? []).map((r) => ({ box: { ...r.bbox }, kind: 'fill' }));
193
+ inkOf.set(f.name, { all: [...place(frameInk(blocks, false)), ...rules], covers: place(frameInk(blocks, true)) });
194
+ }
195
+ const warnings = [];
196
+ const events = [];
197
+ const base = (f) => ({
198
+ template: template.id,
199
+ frame: f.name,
200
+ fenceIndex: input.fenceIndex,
201
+ configPath: f.configPath,
202
+ });
203
+ const where = (f) => ({
204
+ ...(f.sourceStart !== undefined ? { sourceStart: f.sourceStart, sourceEnd: f.sourceEnd } : {}),
205
+ pageIndex: input.pageIndex,
206
+ });
207
+ const locale = input.locale ? { locale: input.locale } : {};
208
+ const depth = MIN_DEPTH_MM * mmPx;
209
+ // frameCovered: each frame against every frame painted after it.
210
+ const paintRank = (f) => [f.layer, order.get(f.name) ?? 0];
211
+ const later = (a, b) => {
212
+ const [la, oa] = paintRank(a);
213
+ const [lb, ob] = paintRank(b);
214
+ return lb > la || (lb === la && ob > oa);
215
+ };
216
+ /** What `over` covers of `under`, by the check's rules: the covered
217
+ * frame's ink that is not fill against the covering frame's opaque ink
218
+ * (its pictures left out when they push with a contour), each read
219
+ * through `ink` (the frames where they lie). `skipLines` leaves out the
220
+ * covered frame's body lines (they run round a pushing frame). */
221
+ const pairInk = (under, over, ink, skipLines = false) => {
222
+ if (over === under || !later(under, over))
223
+ return undefined;
224
+ const ru = resolved.get(under.name);
225
+ const ro = resolved.get(over.name);
226
+ if (ru.overlap === 'allow' || ro.overlap === 'allow')
227
+ return undefined;
228
+ const covered = ink(under.name).all.filter((i) => i.kind !== 'fill' && !(skipLines && i.flow === 'line'));
229
+ // Text set round a frame's pictures (`wrap: 'contour'`) comes into
230
+ // their box by design: the contour, not the box, keeps it clear.
231
+ const contourWrap = ro.exclude === 'push' && ro.wrap === 'contour';
232
+ const covers = ink(over.name).covers.filter((c) => !(contourWrap && c.kind === 'picture'));
233
+ return covered.length > 0 && covers.length > 0 ? { covered, covers } : undefined;
234
+ };
235
+ const here = (name) => inkOf.get(name);
236
+ const found = [];
237
+ for (const under of live) {
238
+ for (const over of live) {
239
+ const pi = pairInk(under, over, here);
240
+ if (!pi)
241
+ continue;
242
+ let area = 0;
243
+ let words;
244
+ let picture;
245
+ let hitLine = false;
246
+ const hitBoxes = [];
247
+ const hitCovers = [];
248
+ for (const ink of pi.covered) {
249
+ const cuts = inkCuts(ink, pi.covers, depth);
250
+ if (cuts.length === 0)
251
+ continue;
252
+ area += unionArea(cuts.map((x) => x.cut));
253
+ hitBoxes.push(ink.box);
254
+ for (const x of cuts)
255
+ hitCovers.push(x.c.box);
256
+ if (ink.kind === 'text') {
257
+ if (ink.flow === 'line')
258
+ hitLine = true;
259
+ if (ink.text !== undefined)
260
+ words = words === undefined ? ink.text : words.length < 40 ? `${words} ${ink.text}` : words;
261
+ }
262
+ else if (picture === undefined && ink.resourceId)
263
+ picture = ink.resourceId;
264
+ }
265
+ if (r1(area / (mmPx * mmPx)) < MIN_AREA_MM2)
266
+ continue;
267
+ found.push({ under, over, area, words, picture, hitLine, hitBoxes, hitCovers });
268
+ }
269
+ }
270
+ // A move is proposed only where it lands clear (#1075).
271
+ const warned = new Set(found.map((x) => pairKey(x.under.name, x.over.name)));
272
+ const minArea = MIN_AREA_MM2 * mmPx * mmPx;
273
+ const byName = new Map(live.map((f) => [f.name, f]));
274
+ /** The frames that move with `name`: it, and those anchored to it. */
275
+ const movers = (name) => {
276
+ const set = new Set([name]);
277
+ for (let grew = true; grew;) {
278
+ grew = false;
279
+ for (const f of live) {
280
+ const rf = resolved.get(f.name);
281
+ const to = rf.grid ? undefined : anchorTarget(rf.placement);
282
+ if (to !== undefined && set.has(to) && !set.has(f.name)) {
283
+ set.add(f.name);
284
+ grew = true;
285
+ }
286
+ }
287
+ }
288
+ return set;
289
+ };
290
+ const hostHere = (name) => {
291
+ const h = byName.get(name);
292
+ return h ? hostRect(h) : input.groupRects.get(name);
293
+ };
294
+ /** How far a frame's ink runs past the page (text past the trim, the
295
+ * rest past the bleed) or past the box it is anchored inside, px. */
296
+ const pastArea = (f, ink, hostOf) => {
297
+ const text = ink.filter((i) => i.kind === 'text').map((i) => i.box);
298
+ const rest = ink.filter((i) => i.kind !== 'text').map((i) => i.box);
299
+ let max = Math.max(text.length ? overrun(text, input.areas.page).max : 0, rest.length ? overrun(rest, input.areas.bleed).max : 0);
300
+ const host = insideHost(resolved.get(f.name), input, hostOf, (n) => resolved.get(n)?.overlap === 'allow');
301
+ if (host && ink.length)
302
+ max = Math.max(max, overrun(ink.map((i) => i.box), host.box).max);
303
+ return max;
304
+ };
305
+ /**
306
+ * The page with the frames of `moved` shifted by (dx, dy) px, read by the
307
+ * check's own rules: whether the pair `target` (`under<over`) is clear,
308
+ * whether each moved frame stays inside what holds it (no further past
309
+ * it than it was), and the pieces of ink of pairs no warning names that
310
+ * would come to cover each other (`m` the moved frame's piece where it
311
+ * lies now, `b` the other frame's).
312
+ */
313
+ const tryMove = (moved, dx, dy, target) => {
314
+ const shift = (list) => list.map((i) => ({ ...i, box: { ...i.box, x: i.box.x + dx, y: i.box.y + dy } }));
315
+ const shifted = new Map();
316
+ for (const name of moved) {
317
+ const ink = inkOf.get(name);
318
+ if (ink)
319
+ shifted.set(name, { all: shift(ink.all), covers: shift(ink.covers) });
320
+ }
321
+ const at = (name) => shifted.get(name) ?? inkOf.get(name);
322
+ const hostAt = (name) => {
323
+ const r = hostHere(name);
324
+ return r && moved.has(name) ? { ...r, x: r.x + dx, y: r.y + dy } : r;
325
+ };
326
+ for (const name of moved) {
327
+ const f = byName.get(name);
328
+ if (!f || resolved.get(name).overlap === 'allow')
329
+ continue;
330
+ const after = pastArea(f, at(name).all, hostAt);
331
+ if (after >= MIN_EXCESS_MM * mmPx && after > pastArea(f, inkOf.get(name).all, hostHere) + 0.5)
332
+ return { clear: false, outside: true, blockers: [] };
333
+ }
334
+ let clear = true;
335
+ const blockers = [];
336
+ for (const under of live) {
337
+ for (const over of live) {
338
+ // Two frames that move together lie as they did to each other.
339
+ if (moved.has(under.name) === moved.has(over.name))
340
+ continue;
341
+ // Lines run round a pushing frame wherever it lies.
342
+ const pi = pairInk(under, over, at, resolved.get(over.name).exclude === 'push');
343
+ if (!pi)
344
+ continue;
345
+ let area = 0;
346
+ const pieces = [];
347
+ for (const ink of pi.covered) {
348
+ const cuts = inkCuts(ink, pi.covers, depth);
349
+ if (cuts.length === 0)
350
+ continue;
351
+ area += unionArea(cuts.map((x) => x.cut));
352
+ for (const x of cuts) {
353
+ const [mv, other] = moved.has(under.name) ? [ink.box, x.c.box] : [x.c.box, ink.box];
354
+ pieces.push({ m: { ...mv, x: mv.x - dx, y: mv.y - dy }, b: other });
355
+ }
356
+ }
357
+ if (area < minArea)
358
+ continue;
359
+ const key = pairKey(under.name, over.name);
360
+ if (key === target)
361
+ clear = false;
362
+ else if (!warned.has(key))
363
+ blockers.push(...pieces);
364
+ }
365
+ }
366
+ return { clear, outside: false, blockers };
367
+ };
368
+ for (const { under, over, area, words, picture, hitLine, hitBoxes, hitCovers } of found) {
369
+ const ro = resolved.get(over.name);
370
+ const areaMm2 = r1(area / (mmPx * mmPx));
371
+ const proposals = [];
372
+ // Painted under it, the covering frame is hidden in turn wherever the
373
+ // covered one is opaque (a fill, a picture): proposed only where the
374
+ // covered frame has nothing but text over it.
375
+ const covers = pairInk(under, over, here).covers;
376
+ const underOpaque = inkOf.get(under.name).covers.filter((c) => c.kind !== 'text');
377
+ const swaps = underOpaque.some((u) => covers.some((c) => {
378
+ const cut = intersect(u.box, c.box);
379
+ return cut !== undefined && cut.width >= depth && cut.height >= depth;
380
+ }));
381
+ if (!swaps)
382
+ proposals.push({ kind: 'layer', path: `${over.configPath}/layer`, value: under.layer - 1 });
383
+ // Body lines run round a frame that pushes; a caption or a tab do not.
384
+ if (hitLine && ro.exclude !== 'push' && ro.rotate === 0 && !over.writingMode)
385
+ proposals.push({ kind: 'exclude', path: `${over.configPath}/exclude`, value: 'push' });
386
+ // The covered frame anchored to the covering one moves with it: no
387
+ // move takes one off the other.
388
+ const moved = movers(over.name);
389
+ const move = moved.has(under.name) ? undefined : clearingMove(hitBoxes, hitCovers, mmPx, (dx, dy) => tryMove(moved, dx, dy, pairKey(under.name, over.name)));
390
+ if (move)
391
+ proposals.push({ kind: 'move', frame: over.name, dxMm: move.dxMm, dyMm: move.dyMm });
392
+ const text = words !== undefined ? words.trim().replace(/\s+/g, ' ').slice(0, 40) : undefined;
393
+ warnings.push({
394
+ kind: 'frameCovered',
395
+ ...base(under),
396
+ coveredBy: over.name,
397
+ coveredByPath: over.configPath,
398
+ overlapMm2: areaMm2,
399
+ ...(text ? { text } : {}),
400
+ ...(picture !== undefined ? { picture } : {}),
401
+ ...locale,
402
+ proposals,
403
+ ...where(under),
404
+ });
405
+ events.push({ frame: under.name, kind: 'covered', cause: over.name, areaMm2 });
406
+ }
407
+ // frameOutsideArea: past the trim (text) or the bleed (fills, pictures),
408
+ // and past the box it is anchored inside.
409
+ const moveIsClear = (name) => (dx, dy) => {
410
+ const t = tryMove(movers(name), dx, dy);
411
+ return t.clear && !t.outside && t.blockers.length === 0;
412
+ };
413
+ for (const f of live) {
414
+ const rf = resolved.get(f.name);
415
+ if (rf.overlap === 'allow')
416
+ continue;
417
+ const ink = inkOf.get(f.name).all;
418
+ if (ink.length === 0)
419
+ continue;
420
+ const textInk = ink.filter((i) => i.kind === 'text').map((i) => i.box);
421
+ const restInk = ink.filter((i) => i.kind !== 'text').map((i) => i.box);
422
+ const overTrim = overrun(textInk, input.areas.page);
423
+ const overBleed = overrun(restInk, input.areas.bleed);
424
+ const pageCase = overTrim.max >= overBleed.max ? { past: 'trim', o: overTrim } : { past: 'bleed', o: overBleed };
425
+ if (pageCase.o.max >= MIN_EXCESS_MM * mmPx) {
426
+ warnings.push(outsideWarning(f, rf, pageCase.past, undefined, pageCase.o, mmPx, base, where, locale, byName, moveIsClear(f.name)));
427
+ events.push({ frame: f.name, kind: 'outside', toMm: r1(pageCase.o.max / mmPx), past: pageCase.past });
428
+ }
429
+ // Anchored inside another frame or a group.
430
+ const host = insideHost(rf, input, hostHere, (n) => resolved.get(n)?.overlap === 'allow');
431
+ if (!host)
432
+ continue;
433
+ const o = overrun(ink.map((i) => i.box), host.box);
434
+ if (o.max < MIN_EXCESS_MM * mmPx)
435
+ continue;
436
+ const past = byName.has(host.target) ? 'frame' : 'group';
437
+ warnings.push(outsideWarning(f, rf, past, host.target, o, mmPx, base, where, locale, byName, moveIsClear(f.name)));
438
+ events.push({ frame: f.name, kind: 'outside', toMm: r1(o.max / mmPx), past: `#${host.target}` });
439
+ }
440
+ return { warnings, events };
441
+ }
442
+ const pairKey = (under, over) => `${under}<${over}`;
443
+ /** The cuts of `ink` by `covers` deeper than `depth` on both sides. */
444
+ function inkCuts(ink, covers, depth) {
445
+ return covers.flatMap((c) => {
446
+ // A line over a picture hides a hairline of it, not the picture:
447
+ // whether the words read on it is the contrast check's matter.
448
+ if (ink.kind === 'picture' && c.kind === 'text')
449
+ return [];
450
+ const cut = intersect(ink.box, c.box);
451
+ return cut && cut.width >= depth && cut.height >= depth ? [{ cut, c }] : [];
452
+ });
453
+ }
454
+ /** The frame or group a frame is anchored inside (a nine-point anchor on
455
+ * `'#name'` whose point, offset added, lies in that box), and its box as
456
+ * `hostOf` gives it. An `'allow'` host is not one. */
457
+ function insideHost(rf, input, hostOf, allows) {
458
+ const target = rf.grid ? undefined : anchorTarget(rf.placement);
459
+ if (!target || !rf.placement)
460
+ return undefined;
461
+ const edge = physicalEdge(rf.placement.anchor.edge, false);
462
+ if (ELEMENT_EDGES.has(edge))
463
+ return undefined;
464
+ const hostBox = hostOf(target);
465
+ if (!hostBox || allows(target))
466
+ return undefined;
467
+ const a = anchorOn(edge, hostBox, true);
468
+ const ax = a.x + lengthPx(rf.placement.offset?.x, input.dpi, input.emPx);
469
+ const ay = a.y + lengthPx(rf.placement.offset?.y, input.dpi, input.emPx);
470
+ const eps = 0.5;
471
+ if (ax < hostBox.x - eps || ax > hostBox.x + hostBox.width + eps || ay < hostBox.y - eps || ay > hostBox.y + hostBox.height + eps)
472
+ return undefined;
473
+ return { target, box: hostBox };
474
+ }
475
+ /** A frame's box on the sheet: its content box put there by its matrix. */
476
+ function hostRect(f) {
477
+ return mapRect(frameContentRect(f), frameMatrix(f));
478
+ }
479
+ const lengthPx = (d, dpi, emPx) => (d ? dimensionToPx(d, dpi, emPx) : 0);
480
+ /** How far the union of `boxes` runs past `limit` on each side, px. */
481
+ function overrun(boxes, limit) {
482
+ let top = 0;
483
+ let right = 0;
484
+ let bottom = 0;
485
+ let left = 0;
486
+ let x0 = Infinity;
487
+ let y0 = Infinity;
488
+ let x1 = -Infinity;
489
+ let y1 = -Infinity;
490
+ for (const b of boxes) {
491
+ x0 = Math.min(x0, b.x);
492
+ y0 = Math.min(y0, b.y);
493
+ x1 = Math.max(x1, b.x + b.width);
494
+ y1 = Math.max(y1, b.y + b.height);
495
+ top = Math.max(top, limit.y - b.y);
496
+ left = Math.max(left, limit.x - b.x);
497
+ bottom = Math.max(bottom, b.y + b.height - (limit.y + limit.height));
498
+ right = Math.max(right, b.x + b.width - (limit.x + limit.width));
499
+ }
500
+ return { top, right, bottom, left, max: Math.max(top, right, bottom, left), fitsX: x1 - x0 <= limit.width + 0.5, fitsY: y1 - y0 <= limit.height + 0.5 };
501
+ }
502
+ function outsideWarning(f, rf, past, target, o, mmPx, base, where, locale, byName,
503
+ /** Whether a shift (px) of the frame lands clear of the page's other
504
+ * frames (#1075). */
505
+ moveIsClear) {
506
+ const mm = (px) => (px >= MIN_EXCESS_MM * mmPx ? r1(px / mmPx) : undefined);
507
+ const sides = {};
508
+ for (const side of ['top', 'right', 'bottom', 'left']) {
509
+ const v = mm(o[side]);
510
+ if (v !== undefined)
511
+ sides[side] = v;
512
+ }
513
+ const proposals = [];
514
+ // Which side of its box the frame's placement holds: a smaller height
515
+ // brings a frame held by its top in at the foot, half as much one held
516
+ // by its middle, and none held by its foot.
517
+ const pinY = rf.grid || !rf.placement ? 'start' : anchorOn(physicalEdge(rf.placement.anchor.edge, false), { x: 0, y: 0, width: 1, height: 1 }, anchorTarget(rf.placement) !== undefined).pinY;
518
+ const min = MIN_EXCESS_MM * mmPx;
519
+ if (o.bottom >= min && !f.rotate && pinY !== 'end') {
520
+ // The frame held to the room it has: its height less what runs past,
521
+ // in whole millimetres down.
522
+ const room = Math.floor((f.rect.height - (pinY === 'middle' ? 2 : 1) * o.bottom) / mmPx);
523
+ if (room > 0) {
524
+ proposals.push({ kind: 'maxHeight', path: `${f.configPath}/maxHeight`, value: mmDim(room) });
525
+ const holdsText = f.blockIds.length > 1;
526
+ if (holdsText && !rf.overflow.continueIn && !rf.next)
527
+ proposals.push({ kind: 'continueNextPage', path: `${f.configPath}/overflow/continueIn`, value: 'next-page' });
528
+ }
529
+ // The frame it is anchored inside grown to hold it.
530
+ const host = target !== undefined ? byName.get(target) : undefined;
531
+ if (host && !host.rotate) {
532
+ const need = Math.ceil((host.rect.height + o.bottom) / mmPx);
533
+ proposals.push({ kind: 'minHeight', path: `${host.configPath}/minHeight`, value: mmDim(need), frame: host.name });
534
+ }
535
+ }
536
+ // The shift that brings it in, when only one side of each axis runs
537
+ // past (data only).
538
+ const dx = !o.fitsX ? 0 : o.left >= min && o.right < min ? o.left : o.right >= min && o.left < min ? -o.right : 0;
539
+ const dy = !o.fitsY ? 0 : o.top >= min && o.bottom < min ? o.top : o.bottom >= min && o.top < min ? -o.bottom : 0;
540
+ // Proposed only where it lands clear of the page's other frames (#1075).
541
+ const dxMm = r1(dx / mmPx) + 0;
542
+ const dyMm = r1(dy / mmPx) + 0;
543
+ if ((dx !== 0 || dy !== 0) && moveIsClear(dxMm * mmPx, dyMm * mmPx))
544
+ proposals.push({ kind: 'move', frame: f.name, dxMm, dyMm });
545
+ return {
546
+ kind: 'frameOutsideArea',
547
+ ...base(f),
548
+ past,
549
+ ...(target !== undefined ? { target } : {}),
550
+ excessMm: r1(o.max / mmPx),
551
+ sides,
552
+ ...locale,
553
+ proposals,
554
+ ...where(f),
555
+ };
556
+ }
557
+ const mmDim = (value) => ({ value, unit: 'mm' });
558
+ /** Up to this many times a move is pushed on past the frame it would land
559
+ * on before the direction is given up. */
560
+ const MAX_MOVE_STEPS = 8;
561
+ /** `mm` rounded away from zero to 0.1 mm: a proposal never falls short. */
562
+ const ceil1 = (mm) => Math.ceil(mm * 10 - 1e-6) / 10;
563
+ /**
564
+ * The smallest shift of the covering frame along one axis that takes its
565
+ * ink off the covered ink and lands clear (#1075), in mm; undefined when no
566
+ * direction does. Each of the four directions starts at the distance that
567
+ * takes the covering boxes off the covered ones; where `test` finds that the
568
+ * moved frames would come to cover another frame (or be covered by one), the
569
+ * move goes on past that frame's ink and is tested again; a direction stops
570
+ * when the pair is not cleared or a moved frame runs past what holds it.
571
+ */
572
+ function clearingMove(covered, covers, mmPx, test) {
573
+ if (covered.length === 0 || covers.length === 0)
574
+ return undefined;
575
+ const u = (rs) => {
576
+ const x = Math.min(...rs.map((r) => r.x));
577
+ const y = Math.min(...rs.map((r) => r.y));
578
+ return { x, y, width: Math.max(...rs.map((r) => r.x + r.width)) - x, height: Math.max(...rs.map((r) => r.y + r.height)) - y };
579
+ };
580
+ const a = u(covered);
581
+ const c = u(covers);
582
+ /** Each direction: its unit vector, the distance that takes the covers
583
+ * off the covered ink, and the distance that takes a moved piece `m`
584
+ * past a piece `b` (px). */
585
+ const directions = [
586
+ { ux: 1, uy: 0, start: a.x + a.width - c.x, past: (m, b) => b.x + b.width - m.x },
587
+ { ux: -1, uy: 0, start: c.x + c.width - a.x, past: (m, b) => m.x + m.width - b.x },
588
+ { ux: 0, uy: 1, start: a.y + a.height - c.y, past: (m, b) => b.y + b.height - m.y },
589
+ { ux: 0, uy: -1, start: c.y + c.height - a.y, past: (m, b) => m.y + m.height - b.y },
590
+ ];
591
+ let best;
592
+ for (const d of directions) {
593
+ let mm = ceil1(Math.max(0, d.start) / mmPx);
594
+ for (let step = 0; step < MAX_MOVE_STEPS && mm > 0 && (!best || mm < best.mm); step++) {
595
+ const t = test(d.ux * mm * mmPx, d.uy * mm * mmPx);
596
+ if (!t.clear || t.outside)
597
+ break;
598
+ if (t.blockers.length === 0) {
599
+ best = { mm, dxMm: d.ux * mm, dyMm: d.uy * mm };
600
+ break;
601
+ }
602
+ const next = ceil1(Math.max(...t.blockers.map((p) => d.past(p.m, p.b))) / mmPx);
603
+ if (!(next > mm))
604
+ break;
605
+ mm = next;
606
+ }
607
+ }
608
+ // `+ 0` turns a -0 into 0.
609
+ return best ? { dxMm: best.dxMm + 0, dyMm: best.dyMm + 0 } : undefined;
610
+ }
611
+ //# sourceMappingURL=overlap.js.map