postext 1.46.4 → 1.48.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/__tests__/bundle/designOverflowPin.test.js +1 -1
- package/dist/__tests__/bundle/gridBreakRulesPin.test.js +2 -2
- package/dist/__tests__/bundle/shapingLanguagePin.test.js +3 -3
- package/dist/__tests__/bundle/taskBoxPin.test.js +1 -1
- package/dist/__tests__/bundle.test.js +1 -1
- package/dist/__tests__/codeBlocks.test.js +1 -1
- package/dist/__tests__/comics/config.test.js +20 -0
- package/dist/__tests__/comics/config.test.js.map +1 -1
- package/dist/__tests__/composed/cardShapes.test.d.ts +2 -0
- package/dist/__tests__/composed/cardShapes.test.d.ts.map +1 -0
- package/dist/__tests__/composed/cardShapes.test.js +82 -0
- package/dist/__tests__/composed/cardShapes.test.js.map +1 -0
- package/dist/__tests__/composed/connectors.test.d.ts +2 -0
- package/dist/__tests__/composed/connectors.test.d.ts.map +1 -0
- package/dist/__tests__/composed/connectors.test.js +349 -0
- package/dist/__tests__/composed/connectors.test.js.map +1 -0
- package/dist/__tests__/composed/decorationSidePoints.test.d.ts +2 -0
- package/dist/__tests__/composed/decorationSidePoints.test.d.ts.map +1 -0
- package/dist/__tests__/composed/decorationSidePoints.test.js +164 -0
- package/dist/__tests__/composed/decorationSidePoints.test.js.map +1 -0
- package/dist/__tests__/composed/fit.test.js +2 -1
- package/dist/__tests__/composed/fit.test.js.map +1 -1
- package/dist/__tests__/composed/fixtures/connectors.d.ts +33 -0
- package/dist/__tests__/composed/fixtures/connectors.d.ts.map +1 -0
- package/dist/__tests__/composed/fixtures/connectors.js +142 -0
- package/dist/__tests__/composed/fixtures/connectors.js.map +1 -0
- package/dist/__tests__/composed/fixtures/grid.d.ts +32 -0
- package/dist/__tests__/composed/fixtures/grid.d.ts.map +1 -0
- package/dist/__tests__/composed/fixtures/grid.js +53 -0
- package/dist/__tests__/composed/fixtures/grid.js.map +1 -0
- package/dist/__tests__/composed/fixtures/legendMap.d.ts +24 -0
- package/dist/__tests__/composed/fixtures/legendMap.d.ts.map +1 -0
- package/dist/__tests__/composed/fixtures/legendMap.js +117 -0
- package/dist/__tests__/composed/fixtures/legendMap.js.map +1 -0
- package/dist/__tests__/composed/fixtures/mapParts.d.ts +58 -0
- package/dist/__tests__/composed/fixtures/mapParts.d.ts.map +1 -0
- package/dist/__tests__/composed/fixtures/mapParts.js +192 -0
- package/dist/__tests__/composed/fixtures/mapParts.js.map +1 -0
- package/dist/__tests__/composed/fixtures/modules.d.ts +55 -0
- package/dist/__tests__/composed/fixtures/modules.d.ts.map +1 -0
- package/dist/__tests__/composed/fixtures/modules.js +123 -0
- package/dist/__tests__/composed/fixtures/modules.js.map +1 -0
- package/dist/__tests__/composed/grid.test.d.ts +2 -0
- package/dist/__tests__/composed/grid.test.d.ts.map +1 -0
- package/dist/__tests__/composed/grid.test.js +357 -0
- package/dist/__tests__/composed/grid.test.js.map +1 -0
- package/dist/__tests__/composed/groups.test.js +6 -3
- package/dist/__tests__/composed/groups.test.js.map +1 -1
- package/dist/__tests__/composed/labelLegend.test.d.ts +2 -0
- package/dist/__tests__/composed/labelLegend.test.d.ts.map +1 -0
- package/dist/__tests__/composed/labelLegend.test.js +268 -0
- package/dist/__tests__/composed/labelLegend.test.js.map +1 -0
- package/dist/__tests__/composed/labelsChecks.test.js.map +1 -1
- package/dist/__tests__/composed/leaders.test.d.ts +2 -0
- package/dist/__tests__/composed/leaders.test.d.ts.map +1 -0
- package/dist/__tests__/composed/leaders.test.js +372 -0
- package/dist/__tests__/composed/leaders.test.js.map +1 -0
- package/dist/__tests__/composed/modules.test.d.ts +2 -0
- package/dist/__tests__/composed/modules.test.d.ts.map +1 -0
- package/dist/__tests__/composed/modules.test.js +352 -0
- package/dist/__tests__/composed/modules.test.js.map +1 -0
- package/dist/__tests__/composed/overConnectors.test.d.ts +2 -0
- package/dist/__tests__/composed/overConnectors.test.d.ts.map +1 -0
- package/dist/__tests__/composed/overConnectors.test.js +232 -0
- package/dist/__tests__/composed/overConnectors.test.js.map +1 -0
- package/dist/__tests__/composed/overlap.test.d.ts +2 -0
- package/dist/__tests__/composed/overlap.test.d.ts.map +1 -0
- package/dist/__tests__/composed/overlap.test.js +339 -0
- package/dist/__tests__/composed/overlap.test.js.map +1 -0
- package/dist/__tests__/composed/viewerLeaf.test.d.ts +2 -0
- package/dist/__tests__/composed/viewerLeaf.test.d.ts.map +1 -0
- package/dist/__tests__/composed/viewerLeaf.test.js +106 -0
- package/dist/__tests__/composed/viewerLeaf.test.js.map +1 -0
- package/dist/__tests__/composedTemplates.test.js +1 -1
- package/dist/__tests__/design/boxShape.test.d.ts +2 -0
- package/dist/__tests__/design/boxShape.test.d.ts.map +1 -0
- package/dist/__tests__/design/boxShape.test.js +126 -0
- package/dist/__tests__/design/boxShape.test.js.map +1 -0
- package/dist/__tests__/design/boxShapePaint.test.d.ts +2 -0
- package/dist/__tests__/design/boxShapePaint.test.d.ts.map +1 -0
- package/dist/__tests__/design/boxShapePaint.test.js +130 -0
- package/dist/__tests__/design/boxShapePaint.test.js.map +1 -0
- package/dist/__tests__/design/openerBottomAnchor.test.js.map +1 -1
- package/dist/__tests__/design/pathBlock.test.d.ts +2 -0
- package/dist/__tests__/design/pathBlock.test.d.ts.map +1 -0
- package/dist/__tests__/design/pathBlock.test.js +194 -0
- package/dist/__tests__/design/pathBlock.test.js.map +1 -0
- package/dist/__tests__/design/pathElement.test.d.ts +2 -0
- package/dist/__tests__/design/pathElement.test.d.ts.map +1 -0
- package/dist/__tests__/design/pathElement.test.js +257 -0
- package/dist/__tests__/design/pathElement.test.js.map +1 -0
- package/dist/__tests__/design/svgPath.test.d.ts +2 -0
- package/dist/__tests__/design/svgPath.test.d.ts.map +1 -0
- package/dist/__tests__/design/svgPath.test.js +144 -0
- package/dist/__tests__/design/svgPath.test.js.map +1 -0
- package/dist/__tests__/exports.test.js +53 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/__tests__/fontUsage.test.js +46 -0
- package/dist/__tests__/fontUsage.test.js.map +1 -1
- package/dist/__tests__/hardBreaks.test.js +1 -1
- package/dist/__tests__/headingInlineMarks.test.js +1 -1
- package/dist/__tests__/labelGlyphPaint.test.d.ts +2 -0
- package/dist/__tests__/labelGlyphPaint.test.d.ts.map +1 -0
- package/dist/__tests__/labelGlyphPaint.test.js +86 -0
- package/dist/__tests__/labelGlyphPaint.test.js.map +1 -0
- package/dist/__tests__/mathSizeMigration.test.js +2 -2
- package/dist/__tests__/migrate/labelsOnPictures.test.js +1 -1
- package/dist/__tests__/migrate/labelsOnPictures.test.js.map +1 -1
- package/dist/__tests__/parse/containers.test.js +1 -1
- package/dist/__tests__/parse/containers.test.js.map +1 -1
- package/dist/__tests__/pipeline/calloutInlineResourceGap.test.js +1 -1
- package/dist/__tests__/pipeline/calloutLabelGlyph.test.d.ts +2 -0
- package/dist/__tests__/pipeline/calloutLabelGlyph.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/calloutLabelGlyph.test.js +198 -0
- package/dist/__tests__/pipeline/calloutLabelGlyph.test.js.map +1 -0
- package/dist/__tests__/pipeline/calloutShapes.test.d.ts +2 -0
- package/dist/__tests__/pipeline/calloutShapes.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/calloutShapes.test.js +159 -0
- package/dist/__tests__/pipeline/calloutShapes.test.js.map +1 -0
- package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js +1 -1
- package/dist/__tests__/pipeline/colonListRoom.test.js +1 -1
- package/dist/__tests__/pipeline/compoundBreaks.test.js +1 -1
- package/dist/__tests__/pipeline/dashBreaks.test.js +1 -1
- package/dist/__tests__/pipeline/headingSplitOrphans.test.js +1 -1
- package/dist/__tests__/pipeline/inlineFigureSpace.test.js +1 -1
- package/dist/__tests__/pipeline/paragraphContainerTail.test.js +1 -1
- package/dist/__tests__/pipeline/raggedOptimal.test.js +1 -1
- package/dist/__tests__/prepareFonts.test.js +8 -6
- package/dist/__tests__/prepareFonts.test.js.map +1 -1
- package/dist/__tests__/verseLines.test.js +1 -1
- package/dist/bundle/configVersion.d.ts +12 -3
- package/dist/bundle/configVersion.d.ts.map +1 -1
- package/dist/bundle/configVersion.js +16 -5
- package/dist/bundle/configVersion.js.map +1 -1
- package/dist/canvas-backend/blockRender.js +3 -3
- package/dist/canvas-backend/blockRender.js.map +1 -1
- package/dist/canvas-backend/composed.d.ts +4 -2
- package/dist/canvas-backend/composed.d.ts.map +1 -1
- package/dist/canvas-backend/composed.js +12 -7
- package/dist/canvas-backend/composed.js.map +1 -1
- package/dist/canvas-backend/headerFooter.d.ts +17 -1
- package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
- package/dist/canvas-backend/headerFooter.js +64 -1
- package/dist/canvas-backend/headerFooter.js.map +1 -1
- package/dist/canvas-backend/index.d.ts.map +1 -1
- package/dist/canvas-backend/index.js +7 -1
- package/dist/canvas-backend/index.js.map +1 -1
- package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
- package/dist/canvas-backend/renderResourceBlock.js +17 -6
- package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
- package/dist/canvas-backend/swatch.d.ts +20 -1
- package/dist/canvas-backend/swatch.d.ts.map +1 -1
- package/dist/canvas-backend/swatch.js +51 -1
- package/dist/canvas-backend/swatch.js.map +1 -1
- package/dist/comics/fonts.d.ts +19 -0
- package/dist/comics/fonts.d.ts.map +1 -1
- package/dist/comics/fonts.js +70 -17
- package/dist/comics/fonts.js.map +1 -1
- package/dist/comics/layoutPage.d.ts.map +1 -1
- package/dist/comics/layoutPage.js +6 -1
- package/dist/comics/layoutPage.js.map +1 -1
- package/dist/composed/continuation.d.ts +10 -2
- package/dist/composed/continuation.d.ts.map +1 -1
- package/dist/composed/continuation.js +10 -2
- package/dist/composed/continuation.js.map +1 -1
- package/dist/composed/document.d.ts +45 -1
- package/dist/composed/document.d.ts.map +1 -1
- package/dist/composed/document.js +76 -17
- package/dist/composed/document.js.map +1 -1
- package/dist/composed/labelText.d.ts +9 -1
- package/dist/composed/labelText.d.ts.map +1 -1
- package/dist/composed/labelText.js +23 -1
- package/dist/composed/labelText.js.map +1 -1
- package/dist/composed/labels.d.ts +57 -3
- package/dist/composed/labels.d.ts.map +1 -1
- package/dist/composed/labels.js +261 -12
- package/dist/composed/labels.js.map +1 -1
- package/dist/composed/modules.d.ts +30 -0
- package/dist/composed/modules.d.ts.map +1 -0
- package/dist/composed/modules.js +194 -0
- package/dist/composed/modules.js.map +1 -0
- package/dist/composed/overlap.d.ts +52 -0
- package/dist/composed/overlap.d.ts.map +1 -0
- package/dist/composed/overlap.js +611 -0
- package/dist/composed/overlap.js.map +1 -0
- package/dist/composed/paint.d.ts +28 -5
- package/dist/composed/paint.d.ts.map +1 -1
- package/dist/composed/paint.js +26 -5
- package/dist/composed/paint.js.map +1 -1
- package/dist/composed/reflowLog.d.ts +6 -1
- package/dist/composed/reflowLog.d.ts.map +1 -1
- package/dist/composed/reflowLog.js +43 -0
- package/dist/composed/reflowLog.js.map +1 -1
- package/dist/composed/repeat.d.ts +66 -0
- package/dist/composed/repeat.d.ts.map +1 -0
- package/dist/composed/repeat.js +217 -0
- package/dist/composed/repeat.js.map +1 -0
- package/dist/composed/slotChecks.d.ts +1 -1
- package/dist/composed/slotChecks.d.ts.map +1 -1
- package/dist/composed/slotChecks.js +114 -8
- package/dist/composed/slotChecks.js.map +1 -1
- package/dist/composed/sourceMap.d.ts.map +1 -1
- package/dist/composed/sourceMap.js +16 -4
- package/dist/composed/sourceMap.js.map +1 -1
- package/dist/composed/spread.d.ts.map +1 -1
- package/dist/composed/spread.js +6 -2
- package/dist/composed/spread.js.map +1 -1
- package/dist/composed/templates.d.ts +22 -2
- package/dist/composed/templates.d.ts.map +1 -1
- package/dist/composed/templates.js +159 -9
- package/dist/composed/templates.js.map +1 -1
- package/dist/composed/types.d.ts +140 -7
- package/dist/composed/types.d.ts.map +1 -1
- package/dist/composed/validate.d.ts +1 -1
- package/dist/composed/validate.d.ts.map +1 -1
- package/dist/composed/validate.js +101 -4
- package/dist/composed/validate.js.map +1 -1
- package/dist/composed/wrap.d.ts.map +1 -1
- package/dist/composed/wrap.js +95 -17
- package/dist/composed/wrap.js.map +1 -1
- package/dist/configWarnings.d.ts +7 -1
- package/dist/configWarnings.d.ts.map +1 -1
- package/dist/configWarnings.js +275 -4
- package/dist/configWarnings.js.map +1 -1
- package/dist/contrast.d.ts.map +1 -1
- package/dist/contrast.js +8 -0
- package/dist/contrast.js.map +1 -1
- package/dist/defaults/calloutStyles.d.ts +10 -1
- package/dist/defaults/calloutStyles.d.ts.map +1 -1
- package/dist/defaults/calloutStyles.js +46 -7
- package/dist/defaults/calloutStyles.js.map +1 -1
- package/dist/defaults/comics.d.ts +2 -1
- package/dist/defaults/comics.d.ts.map +1 -1
- package/dist/defaults/comics.js +18 -3
- package/dist/defaults/comics.js.map +1 -1
- package/dist/defaults/headerFooter.d.ts.map +1 -1
- package/dist/defaults/headerFooter.js +38 -0
- package/dist/defaults/headerFooter.js.map +1 -1
- package/dist/design/boxShape.d.ts +101 -0
- package/dist/design/boxShape.d.ts.map +1 -0
- package/dist/design/boxShape.js +398 -0
- package/dist/design/boxShape.js.map +1 -0
- package/dist/design/connector.d.ts +75 -0
- package/dist/design/connector.d.ts.map +1 -0
- package/dist/design/connector.js +325 -0
- package/dist/design/connector.js.map +1 -0
- package/dist/design/layout.d.ts +56 -3
- package/dist/design/layout.d.ts.map +1 -1
- package/dist/design/layout.js +214 -12
- package/dist/design/layout.js.map +1 -1
- package/dist/design/logicalEdges.d.ts +7 -0
- package/dist/design/logicalEdges.d.ts.map +1 -1
- package/dist/design/logicalEdges.js +28 -0
- package/dist/design/logicalEdges.js.map +1 -1
- package/dist/design/pathBlock.d.ts +69 -0
- package/dist/design/pathBlock.d.ts.map +1 -0
- package/dist/design/pathBlock.js +286 -0
- package/dist/design/pathBlock.js.map +1 -0
- package/dist/design/svgPath.d.ts +48 -0
- package/dist/design/svgPath.d.ts.map +1 -0
- package/dist/design/svgPath.js +402 -0
- package/dist/design/svgPath.js.map +1 -0
- package/dist/fonts/usage.d.ts +5 -0
- package/dist/fonts/usage.d.ts.map +1 -1
- package/dist/fonts/usage.js +81 -11
- package/dist/fonts/usage.js.map +1 -1
- package/dist/html-backend.d.ts.map +1 -1
- package/dist/html-backend.js +127 -22
- package/dist/html-backend.js.map +1 -1
- package/dist/index.d.ts +19 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/measure/cache.js +1 -1
- package/dist/measure/cache.js.map +1 -1
- package/dist/measure/inlineIcon.d.ts +34 -0
- package/dist/measure/inlineIcon.d.ts.map +1 -0
- package/dist/measure/inlineIcon.js +89 -0
- package/dist/measure/inlineIcon.js.map +1 -0
- package/dist/measure/rich.d.ts +2 -1
- package/dist/measure/rich.d.ts.map +1 -1
- package/dist/measure/rich.js +6 -0
- package/dist/measure/rich.js.map +1 -1
- package/dist/migrate/pageDesign.d.ts.map +1 -1
- package/dist/migrate/pageDesign.js +4 -2
- package/dist/migrate/pageDesign.js.map +1 -1
- package/dist/migrate/textToMarkdown.js +2 -0
- package/dist/migrate/textToMarkdown.js.map +1 -1
- package/dist/parse/blockParser.d.ts.map +1 -1
- package/dist/parse/blockParser.js +171 -20
- package/dist/parse/blockParser.js.map +1 -1
- package/dist/parse/index.d.ts +1 -1
- package/dist/parse/index.d.ts.map +1 -1
- package/dist/parse/index.js.map +1 -1
- package/dist/parse/inlineFormatting.d.ts +11 -3
- package/dist/parse/inlineFormatting.d.ts.map +1 -1
- package/dist/parse/inlineFormatting.js +63 -5
- package/dist/parse/inlineFormatting.js.map +1 -1
- package/dist/parse/inlineSnippet.d.ts +2 -1
- package/dist/parse/inlineSnippet.d.ts.map +1 -1
- package/dist/parse/inlineSnippet.js +3 -2
- package/dist/parse/inlineSnippet.js.map +1 -1
- package/dist/parse/sourceMapping.d.ts.map +1 -1
- package/dist/parse/sourceMapping.js +8 -1
- package/dist/parse/sourceMapping.js.map +1 -1
- package/dist/parse/types.d.ts +71 -1
- package/dist/parse/types.d.ts.map +1 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +67 -13
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/buildHelpers.d.ts +10 -0
- package/dist/pipeline/buildHelpers.d.ts.map +1 -1
- package/dist/pipeline/buildHelpers.js +17 -0
- package/dist/pipeline/buildHelpers.js.map +1 -1
- package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
- package/dist/pipeline/buildMeasurement.js +23 -11
- package/dist/pipeline/buildMeasurement.js.map +1 -1
- package/dist/pipeline/calloutLayout.d.ts.map +1 -1
- package/dist/pipeline/calloutLayout.js +142 -32
- package/dist/pipeline/calloutLayout.js.map +1 -1
- package/dist/pipeline/composedLayout.d.ts +1 -33
- package/dist/pipeline/composedLayout.d.ts.map +1 -1
- package/dist/pipeline/composedLayout.js +526 -36
- package/dist/pipeline/composedLayout.js.map +1 -1
- package/dist/pipeline/config.d.ts.map +1 -1
- package/dist/pipeline/config.js +12 -0
- package/dist/pipeline/config.js.map +1 -1
- package/dist/pipeline/contentWarnings.d.ts.map +1 -1
- package/dist/pipeline/contentWarnings.js +46 -1
- package/dist/pipeline/contentWarnings.js.map +1 -1
- package/dist/pipeline/continuation.d.ts.map +1 -1
- package/dist/pipeline/continuation.js +3 -2
- package/dist/pipeline/continuation.js.map +1 -1
- package/dist/pipeline/headerFooter.d.ts +19 -1
- package/dist/pipeline/headerFooter.d.ts.map +1 -1
- package/dist/pipeline/headerFooter.js +169 -17
- package/dist/pipeline/headerFooter.js.map +1 -1
- package/dist/pipeline/partPalette.d.ts.map +1 -1
- package/dist/pipeline/partPalette.js +40 -1
- package/dist/pipeline/partPalette.js.map +1 -1
- package/dist/pipeline/resourceLayout.d.ts +1 -1
- package/dist/pipeline/resourceLayout.d.ts.map +1 -1
- package/dist/pipeline/resourceLayout.js +44 -15
- package/dist/pipeline/resourceLayout.js.map +1 -1
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +36 -1
- package/dist/preflight.js.map +1 -1
- package/dist/types.d.ts +319 -22
- package/dist/types.d.ts.map +1 -1
- package/dist/vdt.d.ts +392 -12
- package/dist/vdt.d.ts.map +1 -1
- package/dist/vdt.js.map +1 -1
- package/package.json +1 -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
|