postext 1.34.0 → 1.35.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.test.js +33 -1
- package/dist/__tests__/bundle.test.js.map +1 -1
- package/dist/__tests__/codeBlocks.test.js +88 -0
- package/dist/__tests__/codeBlocks.test.js.map +1 -1
- package/dist/__tests__/composed/fixtures/page8.d.ts +20 -0
- package/dist/__tests__/composed/fixtures/page8.d.ts.map +1 -0
- package/dist/__tests__/composed/fixtures/page8.js +162 -0
- package/dist/__tests__/composed/fixtures/page8.js.map +1 -0
- package/dist/__tests__/composed/fixtures/timeline.d.ts +26 -0
- package/dist/__tests__/composed/fixtures/timeline.d.ts.map +1 -0
- package/dist/__tests__/composed/fixtures/timeline.js +153 -0
- package/dist/__tests__/composed/fixtures/timeline.js.map +1 -0
- package/dist/__tests__/composed/groups.test.d.ts +2 -0
- package/dist/__tests__/composed/groups.test.d.ts.map +1 -0
- package/dist/__tests__/composed/groups.test.js +361 -0
- package/dist/__tests__/composed/groups.test.js.map +1 -0
- package/dist/__tests__/composed/layout.test.d.ts +2 -0
- package/dist/__tests__/composed/layout.test.d.ts.map +1 -0
- package/dist/__tests__/composed/layout.test.js +387 -0
- package/dist/__tests__/composed/layout.test.js.map +1 -0
- package/dist/__tests__/composed/outsidePrint.test.d.ts +2 -0
- package/dist/__tests__/composed/outsidePrint.test.d.ts.map +1 -0
- package/dist/__tests__/composed/outsidePrint.test.js +116 -0
- package/dist/__tests__/composed/outsidePrint.test.js.map +1 -0
- package/dist/__tests__/composed/slotChecks.test.js +6 -3
- package/dist/__tests__/composed/slotChecks.test.js.map +1 -1
- package/dist/__tests__/composed/spread.test.d.ts +2 -0
- package/dist/__tests__/composed/spread.test.d.ts.map +1 -0
- package/dist/__tests__/composed/spread.test.js +475 -0
- package/dist/__tests__/composed/spread.test.js.map +1 -0
- package/dist/__tests__/composedPaint.test.d.ts +2 -0
- package/dist/__tests__/composedPaint.test.d.ts.map +1 -0
- package/dist/__tests__/composedPaint.test.js +199 -0
- package/dist/__tests__/composedPaint.test.js.map +1 -0
- package/dist/__tests__/defaults/stripRoundTrip.test.js +3 -2
- package/dist/__tests__/defaults/stripRoundTrip.test.js.map +1 -1
- package/dist/__tests__/exports.test.js +25 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/__tests__/highlightMarks.test.d.ts +2 -0
- package/dist/__tests__/highlightMarks.test.d.ts.map +1 -0
- package/dist/__tests__/highlightMarks.test.js +169 -0
- package/dist/__tests__/highlightMarks.test.js.map +1 -0
- package/dist/__tests__/tocPartLeader.test.d.ts +2 -0
- package/dist/__tests__/tocPartLeader.test.d.ts.map +1 -0
- package/dist/__tests__/tocPartLeader.test.js +133 -0
- package/dist/__tests__/tocPartLeader.test.js.map +1 -0
- package/dist/bundle/api.d.ts +8 -0
- package/dist/bundle/api.d.ts.map +1 -1
- package/dist/bundle/api.js +6 -3
- package/dist/bundle/api.js.map +1 -1
- package/dist/bundle/codec.d.ts +5 -0
- package/dist/bundle/codec.d.ts.map +1 -1
- package/dist/bundle/codec.js +4 -0
- package/dist/bundle/codec.js.map +1 -1
- package/dist/bundle/index.d.ts +2 -2
- package/dist/bundle/index.d.ts.map +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/index.js.map +1 -1
- package/dist/bundle/manifest.d.ts +14 -0
- package/dist/bundle/manifest.d.ts.map +1 -1
- package/dist/bundle/manifest.js +13 -0
- package/dist/bundle/manifest.js.map +1 -1
- package/dist/bundle/types.d.ts +7 -0
- package/dist/bundle/types.d.ts.map +1 -1
- package/dist/canvas-backend/annotations.d.ts +6 -0
- package/dist/canvas-backend/annotations.d.ts.map +1 -1
- package/dist/canvas-backend/annotations.js +39 -0
- package/dist/canvas-backend/annotations.js.map +1 -1
- package/dist/canvas-backend/blockRender.d.ts.map +1 -1
- package/dist/canvas-backend/blockRender.js +6 -1
- package/dist/canvas-backend/blockRender.js.map +1 -1
- package/dist/canvas-backend/composed.d.ts +19 -0
- package/dist/canvas-backend/composed.d.ts.map +1 -0
- package/dist/canvas-backend/composed.js +68 -0
- package/dist/canvas-backend/composed.js.map +1 -0
- package/dist/canvas-backend/index.d.ts.map +1 -1
- package/dist/canvas-backend/index.js +15 -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 +4 -1
- package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
- package/dist/composed/geometry.d.ts +108 -0
- package/dist/composed/geometry.d.ts.map +1 -0
- package/dist/composed/geometry.js +241 -0
- package/dist/composed/geometry.js.map +1 -0
- package/dist/composed/groups.d.ts +95 -0
- package/dist/composed/groups.d.ts.map +1 -0
- package/dist/composed/groups.js +359 -0
- package/dist/composed/groups.js.map +1 -0
- package/dist/composed/labelText.d.ts +15 -0
- package/dist/composed/labelText.d.ts.map +1 -0
- package/dist/composed/labelText.js +16 -0
- package/dist/composed/labelText.js.map +1 -0
- package/dist/composed/paint.d.ts +64 -0
- package/dist/composed/paint.d.ts.map +1 -0
- package/dist/composed/paint.js +128 -0
- package/dist/composed/paint.js.map +1 -0
- package/dist/composed/reflowLog.d.ts +39 -0
- package/dist/composed/reflowLog.d.ts.map +1 -0
- package/dist/composed/reflowLog.js +123 -0
- package/dist/composed/reflowLog.js.map +1 -0
- package/dist/composed/slotChecks.d.ts +7 -2
- package/dist/composed/slotChecks.d.ts.map +1 -1
- package/dist/composed/slotChecks.js +21 -0
- package/dist/composed/slotChecks.js.map +1 -1
- package/dist/composed/spread.d.ts +106 -0
- package/dist/composed/spread.d.ts.map +1 -0
- package/dist/composed/spread.js +178 -0
- package/dist/composed/spread.js.map +1 -0
- package/dist/composed/types.d.ts +1 -44
- package/dist/composed/types.d.ts.map +1 -1
- package/dist/composed/wrap.d.ts +52 -0
- package/dist/composed/wrap.d.ts.map +1 -0
- package/dist/composed/wrap.js +234 -0
- package/dist/composed/wrap.js.map +1 -0
- package/dist/configWarnings.js +1 -1
- package/dist/configWarnings.js.map +1 -1
- package/dist/defaults/codeStyle.d.ts.map +1 -1
- package/dist/defaults/codeStyle.js +1 -0
- package/dist/defaults/codeStyle.js.map +1 -1
- package/dist/defaults/headerFooter.d.ts.map +1 -1
- package/dist/defaults/headerFooter.js +4 -0
- package/dist/defaults/headerFooter.js.map +1 -1
- package/dist/defaults/index.d.ts +1 -0
- package/dist/defaults/index.d.ts.map +1 -1
- package/dist/defaults/index.js +9 -0
- package/dist/defaults/index.js.map +1 -1
- package/dist/defaults/markStyles.d.ts +23 -0
- package/dist/defaults/markStyles.d.ts.map +1 -0
- package/dist/defaults/markStyles.js +80 -0
- package/dist/defaults/markStyles.js.map +1 -0
- package/dist/defaults/shared.d.ts.map +1 -1
- package/dist/defaults/shared.js +12 -0
- package/dist/defaults/shared.js.map +1 -1
- package/dist/design/bidiText.d.ts +4 -1
- package/dist/design/bidiText.d.ts.map +1 -1
- package/dist/design/bidiText.js +5 -2
- package/dist/design/bidiText.js.map +1 -1
- package/dist/design/layout.d.ts +19 -0
- package/dist/design/layout.d.ts.map +1 -1
- package/dist/design/layout.js +110 -8
- package/dist/design/layout.js.map +1 -1
- package/dist/design/placeholders.d.ts +28 -2
- package/dist/design/placeholders.d.ts.map +1 -1
- package/dist/design/placeholders.js +24 -1
- package/dist/design/placeholders.js.map +1 -1
- package/dist/design/richText.d.ts +2 -0
- package/dist/design/richText.d.ts.map +1 -1
- package/dist/design/richText.js.map +1 -1
- package/dist/highlightMarks.d.ts +33 -0
- package/dist/highlightMarks.d.ts.map +1 -0
- package/dist/highlightMarks.js +209 -0
- package/dist/highlightMarks.js.map +1 -0
- package/dist/html-backend.d.ts.map +1 -1
- package/dist/html-backend.js +96 -9
- package/dist/html-backend.js.map +1 -1
- package/dist/htmlAnnotations.d.ts +5 -0
- package/dist/htmlAnnotations.d.ts.map +1 -1
- package/dist/htmlAnnotations.js +16 -0
- package/dist/htmlAnnotations.js.map +1 -1
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/knuthPlass/richAdapter.d.ts +3 -0
- package/dist/knuthPlass/richAdapter.d.ts.map +1 -1
- package/dist/knuthPlass/richAdapter.js +3 -2
- package/dist/knuthPlass/richAdapter.js.map +1 -1
- package/dist/measure/cache.js +3 -3
- package/dist/measure/cache.js.map +1 -1
- package/dist/measure/chipEdges.d.ts +13 -1
- package/dist/measure/chipEdges.d.ts.map +1 -1
- package/dist/measure/chipEdges.js +59 -1
- package/dist/measure/chipEdges.js.map +1 -1
- package/dist/measure/links.d.ts.map +1 -1
- package/dist/measure/links.js +78 -5
- package/dist/measure/links.js.map +1 -1
- package/dist/measure/rich.d.ts +3 -0
- package/dist/measure/rich.d.ts.map +1 -1
- package/dist/measure/rich.js +19 -4
- package/dist/measure/rich.js.map +1 -1
- package/dist/parse/inlineFormatting.d.ts +14 -0
- package/dist/parse/inlineFormatting.d.ts.map +1 -1
- package/dist/parse/inlineFormatting.js +104 -5
- package/dist/parse/inlineFormatting.js.map +1 -1
- package/dist/parse/links.js +1 -1
- package/dist/parse/links.js.map +1 -1
- package/dist/parse/softBreaks.js +1 -1
- package/dist/parse/softBreaks.js.map +1 -1
- package/dist/parse/sourceMapping.d.ts.map +1 -1
- package/dist/parse/sourceMapping.js +19 -3
- package/dist/parse/sourceMapping.js.map +1 -1
- package/dist/parse/types.d.ts +24 -0
- package/dist/parse/types.d.ts.map +1 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +213 -301
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/buildMeasurement.d.ts +4 -1
- package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
- package/dist/pipeline/buildMeasurement.js +19 -1
- package/dist/pipeline/buildMeasurement.js.map +1 -1
- package/dist/pipeline/calloutLayout.d.ts +36 -1
- package/dist/pipeline/calloutLayout.d.ts.map +1 -1
- package/dist/pipeline/calloutLayout.js +93 -3
- package/dist/pipeline/calloutLayout.js.map +1 -1
- package/dist/pipeline/codeInline.d.ts +10 -1
- package/dist/pipeline/codeInline.d.ts.map +1 -1
- package/dist/pipeline/codeInline.js +96 -15
- package/dist/pipeline/codeInline.js.map +1 -1
- package/dist/pipeline/composedLayout.d.ts +93 -0
- package/dist/pipeline/composedLayout.d.ts.map +1 -0
- package/dist/pipeline/composedLayout.js +520 -0
- package/dist/pipeline/composedLayout.js.map +1 -0
- package/dist/pipeline/config.d.ts.map +1 -1
- package/dist/pipeline/config.js +2 -1
- package/dist/pipeline/config.js.map +1 -1
- package/dist/pipeline/contentWarnings.d.ts.map +1 -1
- package/dist/pipeline/contentWarnings.js +39 -2
- package/dist/pipeline/contentWarnings.js.map +1 -1
- package/dist/pipeline/floatSlots.js +1 -1
- package/dist/pipeline/floatSlots.js.map +1 -1
- package/dist/pipeline/frameLayout.d.ts +120 -0
- package/dist/pipeline/frameLayout.d.ts.map +1 -0
- package/dist/pipeline/frameLayout.js +279 -0
- package/dist/pipeline/frameLayout.js.map +1 -0
- package/dist/pipeline/headerFooter.d.ts.map +1 -1
- package/dist/pipeline/headerFooter.js +96 -3
- package/dist/pipeline/headerFooter.js.map +1 -1
- package/dist/pipeline/pageRoles.d.ts +1 -0
- package/dist/pipeline/pageRoles.d.ts.map +1 -1
- package/dist/pipeline/pageRoles.js +3 -0
- package/dist/pipeline/pageRoles.js.map +1 -1
- package/dist/pipeline/placement.js +1 -1
- package/dist/pipeline/placement.js.map +1 -1
- package/dist/pipeline/resourceLayout.d.ts.map +1 -1
- package/dist/pipeline/resourceLayout.js +5 -3
- package/dist/pipeline/resourceLayout.js.map +1 -1
- package/dist/pipeline/tabs.js +1 -1
- package/dist/pipeline/tabs.js.map +1 -1
- package/dist/types.d.ts +89 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/vdt.d.ts +247 -1
- package/dist/vdt.d.ts.map +1 -1
- package/dist/vdt.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lay out one composed page (#855, DESIGN §5.1–5.2): place the frames of
|
|
3
|
+
* its template, pour each story (`composed/wrap.ts`) into its frames with
|
|
4
|
+
* the box typesetter (`frameLayout.ts`), and hand back the blocks for the
|
|
5
|
+
* page's floats with the page's `VDTComposedPage`.
|
|
6
|
+
*
|
|
7
|
+
* Per frame, in {@link frameOrder}: its box ({@link placeBox}, an `'auto'`
|
|
8
|
+
* height measured with the content the frame will hold), then its content:
|
|
9
|
+
* the story from where the frame before it in the chain stopped, cut at the
|
|
10
|
+
* frame's foot when a `next` frame takes the rest, else laid whole and
|
|
11
|
+
* clipped at the foot (`frameOverflow`). Text runs round the frames that
|
|
12
|
+
* push it (`exclude: 'push'`) already placed. The groups' negotiation
|
|
13
|
+
* (#856), the reflow ladder (#858) and continuation on other pages (#859)
|
|
14
|
+
* build on this.
|
|
15
|
+
*/
|
|
16
|
+
import type { ComposedPageFence, ContentBlock } from '../parse/types';
|
|
17
|
+
import type { ResolvedCalloutStyleConfig } from '../types';
|
|
18
|
+
import type { ContentWarning, VDTBlock, VDTComposedPage, VDTPage } from '../vdt';
|
|
19
|
+
import { dimensionToPx } from '../units';
|
|
20
|
+
import { type FrameAreas, type Rect } from '../composed/geometry';
|
|
21
|
+
import type { ResolvedFrame, ResolvedPageTemplate } from '../composed/types';
|
|
22
|
+
import { type PageTemplateSource } from '../composed/templates';
|
|
23
|
+
import { type PlannedCallout } from './calloutLayout';
|
|
24
|
+
import { type FrameLayoutPass } from './frameLayout';
|
|
25
|
+
/** A story of the page: the box `composed/wrap.ts` made of a chain's
|
|
26
|
+
* content, by the name of the chain's first frame. */
|
|
27
|
+
export interface ComposedStory {
|
|
28
|
+
startIdx: number;
|
|
29
|
+
plan: PlannedCallout;
|
|
30
|
+
}
|
|
31
|
+
export interface ComposedPageInput {
|
|
32
|
+
pass: FrameLayoutPass;
|
|
33
|
+
page: VDTPage;
|
|
34
|
+
template: ResolvedPageTemplate;
|
|
35
|
+
fence: ComposedPageFence;
|
|
36
|
+
/** Content index of the page's opening and closing markers. */
|
|
37
|
+
startIdx: number;
|
|
38
|
+
endIdx: number;
|
|
39
|
+
/** The page's stories by head frame name. */
|
|
40
|
+
stories: ReadonlyMap<string, ComposedStory>;
|
|
41
|
+
/** The style a frame is drawn with: its `style`, or frameless. */
|
|
42
|
+
styleOf(frame: ResolvedFrame): ResolvedCalloutStyleConfig;
|
|
43
|
+
areas: FrameAreas;
|
|
44
|
+
dpi: number;
|
|
45
|
+
emPx: number;
|
|
46
|
+
/** Source offset of the body in the chapter file. */
|
|
47
|
+
bodyOffset: number;
|
|
48
|
+
/** The page swaps its mirrored margins (an `'outer'` corner icon). */
|
|
49
|
+
mirrored: boolean;
|
|
50
|
+
/** The gap text keeps from a frame that pushes it. */
|
|
51
|
+
pushGapPx: number;
|
|
52
|
+
/** The box a frame takes given the one its placement gives: on a spread
|
|
53
|
+
* (#861, `composed/spread.ts`), off the spine band unless the frame
|
|
54
|
+
* crosses the gutter. An `'auto'` height is measured at the width it
|
|
55
|
+
* returns. */
|
|
56
|
+
fitBox?: (frame: ResolvedFrame, rect: Rect) => Rect;
|
|
57
|
+
}
|
|
58
|
+
export interface ComposedPageLayout {
|
|
59
|
+
composed: VDTComposedPage;
|
|
60
|
+
/** Frame boxes and their content, in paint-independent page order (each
|
|
61
|
+
* frame's box first): for `page.floats` and `doc.blocks`. */
|
|
62
|
+
blocks: VDTBlock[];
|
|
63
|
+
warnings: ContentWarning[];
|
|
64
|
+
/** Story heads laid in a frame of this page. A story left out (its frame
|
|
65
|
+
* is missing on this side) is set in the flow after the page. */
|
|
66
|
+
laid: Set<string>;
|
|
67
|
+
}
|
|
68
|
+
export declare function layoutComposedPage(input: ComposedPageInput): ComposedPageLayout;
|
|
69
|
+
/** The callout style a frame is drawn with: `base` (its `style`, or the
|
|
70
|
+
* frameless frame style) with what a frame sets of its own: its padding
|
|
71
|
+
* (side by side) and a measure that is the frame's. A style's placement,
|
|
72
|
+
* span, width and margins do not apply to a frame. */
|
|
73
|
+
export declare function frameStyleOf(base: ResolvedCalloutStyleConfig, frame: ResolvedFrame): ResolvedCalloutStyleConfig;
|
|
74
|
+
/** The story heads of a composed page's stories, by the head frame's
|
|
75
|
+
* name, read from the boxes `wrapComposedPages` made (`FRAME_ATTR`). */
|
|
76
|
+
export declare function composedStories(startIdx: number, endIdx: number, plans: ReadonlyMap<number, PlannedCallout>): Map<string, ComposedStory>;
|
|
77
|
+
/** `d` in px, 0 when unset. */
|
|
78
|
+
export declare function lengthPx(d: Parameters<typeof dimensionToPx>[0] | undefined, dpi: number, emPx: number): number;
|
|
79
|
+
/** A composed page of the pass whose template is known: its markers and
|
|
80
|
+
* its stories. */
|
|
81
|
+
export interface PlannedComposedPage {
|
|
82
|
+
startIdx: number;
|
|
83
|
+
endIdx: number;
|
|
84
|
+
stories: Map<string, ComposedStory>;
|
|
85
|
+
/** The story box holding block `idx`, if any. */
|
|
86
|
+
storyAt(idx: number): ComposedStory | undefined;
|
|
87
|
+
}
|
|
88
|
+
/** The composed pages of `blocks` whose template `source` has, by their
|
|
89
|
+
* opening marker's index. */
|
|
90
|
+
export declare function planComposedPages(blocks: readonly ContentBlock[], plans: ReadonlyMap<number, PlannedCallout>, source: PageTemplateSource): Map<number, PlannedComposedPage>;
|
|
91
|
+
/** The planned composed page whose markers enclose block `idx`. */
|
|
92
|
+
export declare function composedPageAt(pages: ReadonlyMap<number, PlannedComposedPage>, idx: number): PlannedComposedPage | undefined;
|
|
93
|
+
//# sourceMappingURL=composedLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composedLayout.d.ts","sourceRoot":"","sources":["../../src/pipeline/composedLayout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAe,QAAQ,EAAE,eAAe,EAAY,OAAO,EAAE,MAAM,QAAQ,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAoE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAIpI,OAAO,KAAK,EAAE,aAAa,EAAsB,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAqD,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACzG,OAAO,EAAoI,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAEvL;uDACuD;AACvD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,KAAK,EAAE,iBAAiB,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC5C,kEAAkE;IAClE,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,0BAA0B,CAAC;IAC1D,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB;;;mBAGe;IACf,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,eAAe,CAAC;IAC1B;kEAC8D;IAC9D,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B;sEACkE;IAClE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnB;AAiBD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CA4W/E;AAgFD;;;uDAGuD;AACvD,wBAAgB,YAAY,CAAC,IAAI,EAAE,0BAA0B,EAAE,KAAK,EAAE,aAAa,GAAG,0BAA0B,CAW/G;AAED;yEACyE;AACzE,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,GACzC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAU5B;AAED,+BAA+B;AAC/B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9G;AAED;mBACmB;AACnB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACpC,iDAAiD;IACjD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;CACjD;AAED;8BAC8B;AAC9B,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAC1C,MAAM,EAAE,kBAAkB,GACzB,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAqBlC;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAG5H"}
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { dimensionToPx } from '../units';
|
|
2
|
+
import { frameBounds } from '../composed/paint';
|
|
3
|
+
import { FRAME_ATTR } from '../composed/wrap';
|
|
4
|
+
import { framePlaceable, nextFrameOf, groupPlaceable, placeBox, unionRect } from '../composed/geometry';
|
|
5
|
+
import { composedOrder, groupOfFrames, layoutGroup } from '../composed/groups';
|
|
6
|
+
import { reflowEvents } from '../composed/reflowLog';
|
|
7
|
+
import { anchorTarget } from '../composed/templates';
|
|
8
|
+
import { resolvePageTemplate } from '../composed/templates';
|
|
9
|
+
import { offsetCalloutToAbsolute } from './calloutLayout';
|
|
10
|
+
import { CUT_START, fragmentRange, makeCalloutLayouter, splitCalloutFragment } from './frameLayout';
|
|
11
|
+
const MM_PER_IN = 25.4;
|
|
12
|
+
export function layoutComposedPage(input) {
|
|
13
|
+
const { pass, page, template, fence, dpi } = input;
|
|
14
|
+
const fi = fence.fenceIndex;
|
|
15
|
+
const frameIdOf = (name) => `cp${fi}:${name}`;
|
|
16
|
+
const byName = new Map(template.frames.map((f) => [f.name, f]));
|
|
17
|
+
const prev = new Map();
|
|
18
|
+
for (const f of template.frames) {
|
|
19
|
+
const n = nextFrameOf(f);
|
|
20
|
+
if (n && byName.has(n) && !prev.has(n))
|
|
21
|
+
prev.set(n, f.name);
|
|
22
|
+
}
|
|
23
|
+
/** The head of the chain a frame belongs to. */
|
|
24
|
+
const headOf = (name) => {
|
|
25
|
+
let at = name;
|
|
26
|
+
const seen = new Set([at]);
|
|
27
|
+
for (let p = prev.get(at); p !== undefined && !seen.has(p); p = prev.get(at)) {
|
|
28
|
+
seen.add(p);
|
|
29
|
+
at = p;
|
|
30
|
+
}
|
|
31
|
+
return at;
|
|
32
|
+
};
|
|
33
|
+
/** Place and fill every frame. `seed`: the boxes of the frames that push
|
|
34
|
+
* text, from a first run, so a frame placed before one that pushes it
|
|
35
|
+
* (the photo anchored to its box) still runs round it. */
|
|
36
|
+
const run = (seed) => {
|
|
37
|
+
const pushRects = new Map();
|
|
38
|
+
const states = new Map();
|
|
39
|
+
const stateOf = (frame) => {
|
|
40
|
+
const head = headOf(frame.name);
|
|
41
|
+
const known = states.get(head);
|
|
42
|
+
if (known)
|
|
43
|
+
return known;
|
|
44
|
+
const story = input.stories.get(head);
|
|
45
|
+
const headFrame = byName.get(head);
|
|
46
|
+
if (!story || !headFrame)
|
|
47
|
+
return undefined;
|
|
48
|
+
const st = {
|
|
49
|
+
story,
|
|
50
|
+
L: makeCalloutLayouter(pass, story.startIdx, story.plan, input.styleOf(frame)),
|
|
51
|
+
cut: CUT_START,
|
|
52
|
+
pieces: 0,
|
|
53
|
+
headBlockId: frameIdOf(head),
|
|
54
|
+
headFrameId: frameIdOf(head),
|
|
55
|
+
};
|
|
56
|
+
states.set(head, st);
|
|
57
|
+
return st;
|
|
58
|
+
};
|
|
59
|
+
const atEnd = (st) => st.cut.child >= st.L.end.child && st.cut.line === 0 && !st.cut.group;
|
|
60
|
+
/** The frames' boxes as laid, and as the template declares them. */
|
|
61
|
+
const rects = new Map();
|
|
62
|
+
const declared = new Map();
|
|
63
|
+
/** Groups' boxes once their step is laid. */
|
|
64
|
+
const groupRects = new Map();
|
|
65
|
+
const groupDeclared = new Map();
|
|
66
|
+
const groupRect = (name, boxes, solved, refs) => {
|
|
67
|
+
const done = solved.get(name);
|
|
68
|
+
if (done)
|
|
69
|
+
return done;
|
|
70
|
+
const g = template.groups.find((gr) => gr.name === name);
|
|
71
|
+
if (!g)
|
|
72
|
+
return undefined;
|
|
73
|
+
const own = groupPlaceable(g);
|
|
74
|
+
if (own)
|
|
75
|
+
return placeBox(own, template, input, refs, () => 0);
|
|
76
|
+
return unionRect(g.frames.flatMap((m) => (boxes.has(m) ? [boxes.get(m)] : [])));
|
|
77
|
+
};
|
|
78
|
+
const refOf = (name) => rects.get(name) ?? groupRect(name, rects, groupRects, refOf);
|
|
79
|
+
const declaredRefOf = (name) => declared.get(name) ?? groupRect(name, declared, groupDeclared, declaredRefOf);
|
|
80
|
+
/** Pinned frames laid so far: a group's frames flow round them. */
|
|
81
|
+
const pinned = [];
|
|
82
|
+
const frames = [];
|
|
83
|
+
const vdtByName = new Map();
|
|
84
|
+
const blocks = [];
|
|
85
|
+
const warnings = [];
|
|
86
|
+
const overflowLog = [];
|
|
87
|
+
const laid = new Set();
|
|
88
|
+
const pushed = seed ? [...seed].map(([name, box]) => ({ name, box })) : [];
|
|
89
|
+
/** The rectangles of the pushing frames placed so far that `rect`
|
|
90
|
+
* meets, in the frame block's coordinates. */
|
|
91
|
+
const exclusionsFor = (frame, rect, open) => {
|
|
92
|
+
const out = [];
|
|
93
|
+
const g = input.pushGapPx;
|
|
94
|
+
for (const p of pushed) {
|
|
95
|
+
if (p.name === frame.name)
|
|
96
|
+
continue;
|
|
97
|
+
const b = p.box;
|
|
98
|
+
const below = open ? true : b.y < rect.y + rect.height;
|
|
99
|
+
if (b.x - g >= rect.x + rect.width || b.x + b.width + g <= rect.x || !below || b.y + b.height + g <= rect.y)
|
|
100
|
+
continue;
|
|
101
|
+
out.push({ x: b.x - g - rect.x, y: b.y - g - rect.y, width: b.width + 2 * g, height: b.height + 2 * g });
|
|
102
|
+
}
|
|
103
|
+
return out.length > 0 ? out : undefined;
|
|
104
|
+
};
|
|
105
|
+
const prepare = (frame) => {
|
|
106
|
+
const st = stateOf(frame);
|
|
107
|
+
// Each frame of a chain sets the story in its own style: the cuts are
|
|
108
|
+
// positions in the story's blocks, the same in any.
|
|
109
|
+
if (st)
|
|
110
|
+
st.L = makeCalloutLayouter(pass, st.story.startIdx, st.story.plan, input.styleOf(frame));
|
|
111
|
+
// A frame continues its story only once the frame before it in the
|
|
112
|
+
// chain was filled (a frame placed before it, through an anchor, starts
|
|
113
|
+
// empty).
|
|
114
|
+
const before = prev.get(frame.name);
|
|
115
|
+
const reached = st !== undefined && (before === undefined || vdtByName.has(before));
|
|
116
|
+
const holds = reached && !atEnd(st);
|
|
117
|
+
const continuation = st !== undefined && st.pieces > 0;
|
|
118
|
+
const blockId = st && st.pieces > 0 ? `${st.headBlockId}-cont-${st.pieces}` : frameIdOf(frame.name);
|
|
119
|
+
return { frame, st, before, holds, continuation, blockId };
|
|
120
|
+
};
|
|
121
|
+
/** The content's height at `width`, running round the pushing frames
|
|
122
|
+
* below the top of `at` (the frame's box as first placed). */
|
|
123
|
+
const naturalOf = (p, at) => {
|
|
124
|
+
const memo = new Map();
|
|
125
|
+
return (width) => {
|
|
126
|
+
if (!p.holds)
|
|
127
|
+
return 0;
|
|
128
|
+
const key = Math.round(width * 1000);
|
|
129
|
+
const known = memo.get(key);
|
|
130
|
+
if (known !== undefined)
|
|
131
|
+
return known;
|
|
132
|
+
const exclusions = at ? exclusionsFor(p.frame, { ...at, width }, true) : undefined;
|
|
133
|
+
const r = p.st.L.layoutRange(p.st.cut, p.st.L.end, width, p.blockId, p.continuation, input.mirrored, exclusions ? { exclusions } : undefined);
|
|
134
|
+
memo.set(key, r.totalHeight);
|
|
135
|
+
return r.totalHeight;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
/** `placeBox`, then the box the page lets the frame take (`fitBox`:
|
|
139
|
+
* off a spread's spine band, #861), its `'auto'` height measured at the
|
|
140
|
+
* width it is left with. Declared and final boxes alike: the band is
|
|
141
|
+
* the template's, not a reflow. */
|
|
142
|
+
const placeFitted = (frame, placeable, ctx, refs, nat) => {
|
|
143
|
+
const r = placeBox(placeable, template, ctx, refs, nat);
|
|
144
|
+
if (!input.fitBox)
|
|
145
|
+
return r;
|
|
146
|
+
const fitted = input.fitBox(frame, r);
|
|
147
|
+
if (Math.abs(fitted.width - r.width) < 0.01)
|
|
148
|
+
return fitted;
|
|
149
|
+
return input.fitBox(frame, placeBox(placeable, template, ctx, refs, () => nat(fitted.width)));
|
|
150
|
+
};
|
|
151
|
+
/** A frame's height as its template declares it: its `minHeight` where
|
|
152
|
+
* the height follows the content, else the content's (`natural`). */
|
|
153
|
+
const declaredNatural = (frame, natural) => (width) => (frame.minHeight ? 0 : natural(width));
|
|
154
|
+
/** Place a frame outside any group: its box, placed with the content's
|
|
155
|
+
* own height, then again with the height it takes running round the
|
|
156
|
+
* frames that push it there; a pinned frame where the template puts
|
|
157
|
+
* it. */
|
|
158
|
+
const placeFrame = (p) => {
|
|
159
|
+
const frame = p.frame;
|
|
160
|
+
const placeable = framePlaceable(frame);
|
|
161
|
+
const natural = naturalOf(p);
|
|
162
|
+
const at = (refs) => {
|
|
163
|
+
const r0 = placeFitted(frame, placeable, input, refs, natural);
|
|
164
|
+
if (!p.holds || !exclusionsFor(frame, r0, true))
|
|
165
|
+
return { rect: r0, natural };
|
|
166
|
+
const round = naturalOf(p, r0);
|
|
167
|
+
return { rect: placeFitted(frame, placeable, input, refs, round), natural: round };
|
|
168
|
+
};
|
|
169
|
+
const decl = frame.pin ? at(declaredRefOf) : undefined;
|
|
170
|
+
const fin = decl ?? at(refOf);
|
|
171
|
+
const declRect = placeFitted(frame, placeable, input, declaredRefOf, declaredNatural(frame, fin.natural));
|
|
172
|
+
const rect = frame.pin ? declRect : fin.rect;
|
|
173
|
+
declared.set(frame.name, declRect);
|
|
174
|
+
rects.set(frame.name, rect);
|
|
175
|
+
if (frame.pin)
|
|
176
|
+
pinned.push({ name: frame.name, rect });
|
|
177
|
+
return rect;
|
|
178
|
+
};
|
|
179
|
+
/** Lay a group: its frames' boxes as the template declares them and as
|
|
180
|
+
* their content needs (`composed/groups.ts`). */
|
|
181
|
+
const placeGroup = (group, members) => {
|
|
182
|
+
const own = groupPlaceable(group);
|
|
183
|
+
const mmPx = dpi / MM_PER_IN;
|
|
184
|
+
const preps = members.map(prepare);
|
|
185
|
+
const solve = (mode, naturals) => {
|
|
186
|
+
const refs = mode === 'final' ? refOf : declaredRefOf;
|
|
187
|
+
const ownBox = own ? placeBox(own, template, input, refs, () => 0) : undefined;
|
|
188
|
+
const ownRects = new Map();
|
|
189
|
+
const memberRefs = (n) => ownRects.get(n) ?? (n === group.name ? ownBox : refs(n));
|
|
190
|
+
const items = members.map((f, k) => {
|
|
191
|
+
// A frame placed nowhere stands in its group's box.
|
|
192
|
+
const ctx = ownBox && !f.placement && !f.grid ? { ...input, areas: { ...input.areas, area: ownBox } } : input;
|
|
193
|
+
const natural = naturals[k];
|
|
194
|
+
const placeable = framePlaceable(f);
|
|
195
|
+
// On a spread the member's own box keeps off the spine band, and
|
|
196
|
+
// the negotiation starts from it (#861).
|
|
197
|
+
const box = placeFitted(f, placeable, ctx, memberRefs, declaredNatural(f, natural));
|
|
198
|
+
ownRects.set(f.name, box);
|
|
199
|
+
const auto = f.height === 'auto' && !(f.grid && !placeable.heightSet);
|
|
200
|
+
const fill = f.height === 'fill';
|
|
201
|
+
const minH = f.minHeight ? dimensionToPx(f.minHeight, dpi, input.emPx) : 0;
|
|
202
|
+
const want = fill ? minH : auto ? (mode === 'final' ? natural(box.width) : declaredNatural(f, natural)(box.width)) : box.height;
|
|
203
|
+
return {
|
|
204
|
+
name: f.name,
|
|
205
|
+
own: box,
|
|
206
|
+
want,
|
|
207
|
+
min: minH,
|
|
208
|
+
max: f.maxHeight ? dimensionToPx(f.maxHeight, dpi, input.emPx) : Infinity,
|
|
209
|
+
minWidth: f.minWidth ? dimensionToPx(f.minWidth, dpi, input.emPx) : 0,
|
|
210
|
+
maxWidth: f.maxWidth ? dimensionToPx(f.maxWidth, dpi, input.emPx) : Infinity,
|
|
211
|
+
grow: fill ? Math.max(1, f.grow) : f.grow,
|
|
212
|
+
shrink: f.shrink,
|
|
213
|
+
priority: f.priority,
|
|
214
|
+
pin: f.pin,
|
|
215
|
+
fixedHeight: !auto && !fill,
|
|
216
|
+
need: natural,
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
const firstFree = items.find((it) => !it.pin) ?? items[0];
|
|
220
|
+
const start = firstFree?.own ?? input.areas.area;
|
|
221
|
+
const box = ownBox ?? { x: start.x, y: start.y, width: 0, height: 0 };
|
|
222
|
+
const out = layoutGroup({
|
|
223
|
+
kind: group.kind,
|
|
224
|
+
box,
|
|
225
|
+
elastic: !ownBox,
|
|
226
|
+
limit: input.areas.area,
|
|
227
|
+
gap: dimensionToPx(group.gap, dpi, input.emPx),
|
|
228
|
+
align: group.align,
|
|
229
|
+
items,
|
|
230
|
+
obstacles: pinned.filter((q) => !members.some((m) => m.name === q.name)).map((q) => q.rect),
|
|
231
|
+
mmPx,
|
|
232
|
+
negotiate: mode === 'final',
|
|
233
|
+
});
|
|
234
|
+
// A pinned frame of the group stands where the template puts it.
|
|
235
|
+
for (const it of items)
|
|
236
|
+
if (it.pin)
|
|
237
|
+
out.set(it.name, it.own);
|
|
238
|
+
return { rects: out, box: ownBox ?? unionRect([...out.values()]) ?? box };
|
|
239
|
+
};
|
|
240
|
+
let naturals = preps.map((p) => naturalOf(p));
|
|
241
|
+
let fin = solve('final', naturals);
|
|
242
|
+
// Text that runs round a pushing frame is taller: measured at the box
|
|
243
|
+
// first found, then laid again.
|
|
244
|
+
const round = preps.map((p) => (p.holds && exclusionsFor(p.frame, fin.rects.get(p.frame.name), true) ? naturalOf(p, fin.rects.get(p.frame.name)) : undefined));
|
|
245
|
+
if (round.some((r) => r !== undefined)) {
|
|
246
|
+
naturals = naturals.map((n, k) => round[k] ?? n);
|
|
247
|
+
fin = solve('final', naturals);
|
|
248
|
+
}
|
|
249
|
+
const decl = solve('declared', naturals);
|
|
250
|
+
for (const m of members) {
|
|
251
|
+
rects.set(m.name, fin.rects.get(m.name));
|
|
252
|
+
declared.set(m.name, decl.rects.get(m.name));
|
|
253
|
+
if (m.pin)
|
|
254
|
+
pinned.push({ name: m.name, rect: fin.rects.get(m.name) });
|
|
255
|
+
}
|
|
256
|
+
groupRects.set(group.name, fin.box);
|
|
257
|
+
groupDeclared.set(group.name, decl.box);
|
|
258
|
+
return fin.rects;
|
|
259
|
+
};
|
|
260
|
+
/** Pour a frame's content into its box and record the frame. */
|
|
261
|
+
const fill = (p, rect) => {
|
|
262
|
+
const { frame, st, holds, continuation, blockId, before } = p;
|
|
263
|
+
const style = input.styleOf(frame);
|
|
264
|
+
let result;
|
|
265
|
+
let overflowPx = 0;
|
|
266
|
+
const from = st?.cut ?? CUT_START;
|
|
267
|
+
if (holds) {
|
|
268
|
+
const opts = {
|
|
269
|
+
boxHeight: rect.height,
|
|
270
|
+
verticalAlign: frame.verticalAlign,
|
|
271
|
+
...(exclusionsFor(frame, rect, false) ? { exclusions: exclusionsFor(frame, rect, false) } : {}),
|
|
272
|
+
};
|
|
273
|
+
const whole = st.L.layoutRange(from, st.L.end, rect.width, blockId, continuation, input.mirrored, opts);
|
|
274
|
+
const nextName = nextFrameOf(frame);
|
|
275
|
+
const nextFrame = nextName !== undefined ? byName.get(nextName) : undefined;
|
|
276
|
+
if ((whole.overflowPx ?? 0) > 0.5 && nextFrame && !vdtByName.has(nextFrame.name)) {
|
|
277
|
+
// The rest goes on in the next frame of the chain.
|
|
278
|
+
const minLines = Math.max(1, style.splitMinLines);
|
|
279
|
+
const frag = splitCalloutFragment(pass, st.L, from, rect.width, rect.height, blockId, continuation, minLines, input.mirrored, opts.exclusions ? { exclusions: opts.exclusions } : undefined);
|
|
280
|
+
const to = frag?.to ?? from;
|
|
281
|
+
result = frag
|
|
282
|
+
? st.L.layoutRange(from, to, rect.width, blockId, continuation, input.mirrored, opts)
|
|
283
|
+
: undefined;
|
|
284
|
+
st.cut = to;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
result = whole;
|
|
288
|
+
overflowPx = whole.overflowPx ?? 0;
|
|
289
|
+
st.cut = st.L.end;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else if (st && frame.style) {
|
|
293
|
+
// A styled frame with nothing (left) to hold still draws its box.
|
|
294
|
+
result = st.L.layoutRange(st.L.end, st.L.end, rect.width, blockId, true, input.mirrored, { boxHeight: rect.height });
|
|
295
|
+
}
|
|
296
|
+
const vdt = {
|
|
297
|
+
id: frameIdOf(frame.name),
|
|
298
|
+
name: frame.name,
|
|
299
|
+
rect: { ...rect },
|
|
300
|
+
rotate: frame.rotate,
|
|
301
|
+
layer: frame.layer,
|
|
302
|
+
...(frame.style ? { styleId: frame.style } : {}),
|
|
303
|
+
scale: 1,
|
|
304
|
+
overflowPx,
|
|
305
|
+
blockIds: [],
|
|
306
|
+
configPath: frame.configPath,
|
|
307
|
+
...(frame.exclude === 'push' ? { push: true } : {}),
|
|
308
|
+
};
|
|
309
|
+
const decl = declared.get(frame.name);
|
|
310
|
+
if (decl && !sameRect(decl, rect))
|
|
311
|
+
vdt.declaredRect = { ...decl };
|
|
312
|
+
if (before && vdtByName.has(before) && st && st.lastFrameId) {
|
|
313
|
+
vdt.continuedFrom = st.lastFrameId;
|
|
314
|
+
const q = frames.find((f) => f.id === st.lastFrameId);
|
|
315
|
+
if (q)
|
|
316
|
+
q.continuesTo = vdt.id;
|
|
317
|
+
}
|
|
318
|
+
if (result && st) {
|
|
319
|
+
const range = fragmentRange(st.L, from, st.cut);
|
|
320
|
+
commitFrame(result, rect, st.story, range, input, vdt, blocks);
|
|
321
|
+
st.pieces++;
|
|
322
|
+
st.lastFrameId = vdt.id;
|
|
323
|
+
laid.add(headOf(frame.name));
|
|
324
|
+
}
|
|
325
|
+
if (overflowPx > 0.5) {
|
|
326
|
+
const overflowMm = Math.round((overflowPx / dpi) * MM_PER_IN * 10) / 10;
|
|
327
|
+
overflowLog.push({ frame: frame.name, kind: 'overflow', toMm: overflowMm });
|
|
328
|
+
warnings.push({
|
|
329
|
+
kind: 'frameOverflow',
|
|
330
|
+
template: template.id,
|
|
331
|
+
frame: frame.name,
|
|
332
|
+
fenceIndex: fi,
|
|
333
|
+
overflowMm,
|
|
334
|
+
configPath: frame.configPath,
|
|
335
|
+
...(vdt.sourceStart !== undefined ? { sourceStart: vdt.sourceStart, sourceEnd: vdt.sourceEnd } : {}),
|
|
336
|
+
pageIndex: page.index,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (frame.exclude === 'push') {
|
|
340
|
+
const box = frameBounds({ rect, rotate: frame.rotate });
|
|
341
|
+
pushRects.set(frame.name, box);
|
|
342
|
+
if (!seed)
|
|
343
|
+
pushed.push({ name: frame.name, box });
|
|
344
|
+
}
|
|
345
|
+
frames.push(vdt);
|
|
346
|
+
vdtByName.set(frame.name, vdt);
|
|
347
|
+
};
|
|
348
|
+
for (const step of composedOrder(template)) {
|
|
349
|
+
if (step.kind === 'frame') {
|
|
350
|
+
const p = prepare(step.frame);
|
|
351
|
+
fill(p, placeFrame(p));
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
const solved = placeGroup(step.group, step.frames);
|
|
355
|
+
// A frame of a chain inside the group is reached once the frame
|
|
356
|
+
// before it was filled: each is prepared again as it is filled.
|
|
357
|
+
for (const f of step.frames)
|
|
358
|
+
fill(prepare(f), solved.get(f.name));
|
|
359
|
+
}
|
|
360
|
+
const log = mergeLog(reflowEvents(motionsOf(template, rects, declared), dpi / MM_PER_IN), overflowLog, template);
|
|
361
|
+
return { frames, blocks, warnings, log, laid, pushRects };
|
|
362
|
+
};
|
|
363
|
+
const first = run();
|
|
364
|
+
const { frames, blocks, warnings, log, laid } = first.pushRects.size > 0 ? run(first.pushRects) : first;
|
|
365
|
+
// Template order on the page record.
|
|
366
|
+
const order = new Map(template.frames.map((f, i) => [f.name, i]));
|
|
367
|
+
frames.sort((a, b) => order.get(a.name) - order.get(b.name));
|
|
368
|
+
const contentBlocks = pass.contentBlocks;
|
|
369
|
+
const composed = {
|
|
370
|
+
template: template.id,
|
|
371
|
+
...(template.variant ? { variant: template.variant } : {}),
|
|
372
|
+
fenceIndex: fi,
|
|
373
|
+
role: template.role,
|
|
374
|
+
attrs: { ...fence.attrs },
|
|
375
|
+
attrSources: Object.fromEntries(Object.entries(fence.attrSources).map(([k, v]) => [k, { sourceStart: v.sourceStart + input.bodyOffset, sourceEnd: v.sourceEnd + input.bodyOffset }])),
|
|
376
|
+
frames,
|
|
377
|
+
log,
|
|
378
|
+
configPath: template.configPath,
|
|
379
|
+
sourceStart: contentBlocks[input.startIdx].sourceStart + input.bodyOffset,
|
|
380
|
+
sourceEnd: contentBlocks[input.endIdx].sourceEnd + input.bodyOffset,
|
|
381
|
+
};
|
|
382
|
+
return { composed, blocks, warnings, laid };
|
|
383
|
+
}
|
|
384
|
+
const sameRect = (a, b) => Math.abs(a.x - b.x) < 0.01 && Math.abs(a.y - b.y) < 0.01 && Math.abs(a.width - b.width) < 0.01 && Math.abs(a.height - b.height) < 0.01;
|
|
385
|
+
/** Each laid frame's declared and final boxes, in template order, with
|
|
386
|
+
* what moves it: what it anchors to (a group: its frames, last first),
|
|
387
|
+
* then, in a group, the frames before it (nearest first), what the group
|
|
388
|
+
* anchors to, and the frames after it. */
|
|
389
|
+
function motionsOf(template, rects, declared) {
|
|
390
|
+
const groupOf = groupOfFrames(template);
|
|
391
|
+
const groups = new Map(template.groups.map((g) => [g.name, g]));
|
|
392
|
+
const expand = (target) => {
|
|
393
|
+
if (!target)
|
|
394
|
+
return [];
|
|
395
|
+
const g = groups.get(target);
|
|
396
|
+
return g && !rects.has(target) ? [...g.frames].reverse() : [target];
|
|
397
|
+
};
|
|
398
|
+
const out = [];
|
|
399
|
+
for (const f of template.frames) {
|
|
400
|
+
const fin = rects.get(f.name);
|
|
401
|
+
const decl = declared.get(f.name);
|
|
402
|
+
if (!fin || !decl)
|
|
403
|
+
continue;
|
|
404
|
+
const deps = f.grid ? [] : expand(anchorTarget(f.placement));
|
|
405
|
+
const g = groupOf.get(f.name);
|
|
406
|
+
if (g) {
|
|
407
|
+
const k = g.frames.indexOf(f.name);
|
|
408
|
+
deps.push(...g.frames.slice(0, k).reverse());
|
|
409
|
+
if (!g.grid)
|
|
410
|
+
deps.push(...expand(anchorTarget(g.placement)));
|
|
411
|
+
deps.push(...g.frames.slice(k + 1));
|
|
412
|
+
}
|
|
413
|
+
out.push({ name: f.name, declared: decl, final: fin, deps });
|
|
414
|
+
}
|
|
415
|
+
return out;
|
|
416
|
+
}
|
|
417
|
+
/** The page's log: each frame's events in template order, what groups and
|
|
418
|
+
* anchors changed first, then its overflow. */
|
|
419
|
+
function mergeLog(reflow, overflow, template) {
|
|
420
|
+
const order = new Map(template.frames.map((f, i) => [f.name, i]));
|
|
421
|
+
const all = [...reflow.map((e, i) => ({ e, i })), ...overflow.map((e, i) => ({ e, i: reflow.length + i }))];
|
|
422
|
+
all.sort((a, b) => (order.get(a.e.frame) ?? 0) - (order.get(b.e.frame) ?? 0) || a.i - b.i);
|
|
423
|
+
return all.map((x) => x.e);
|
|
424
|
+
}
|
|
425
|
+
/** Stamp a frame's laid-out box with its source and page, move it to the
|
|
426
|
+
* frame's place and add it (box first) to `out` and to the frame's ids. */
|
|
427
|
+
function commitFrame(result, rect, story, range, input, vdt, out) {
|
|
428
|
+
const { pass, page, bodyOffset } = input;
|
|
429
|
+
const blocks = pass.contentBlocks;
|
|
430
|
+
const box = result.frame;
|
|
431
|
+
box.contentIndex = story.startIdx;
|
|
432
|
+
const first = blocks[Math.max(story.startIdx + 1, Math.min(range.firstChildIdx, story.plan.endIdx - 1))];
|
|
433
|
+
const last = blocks[Math.max(story.startIdx + 1, Math.min(range.lastChildIdx, story.plan.endIdx - 1))];
|
|
434
|
+
if (first && last && range.lastChildIdx >= range.firstChildIdx) {
|
|
435
|
+
box.sourceStart = first.sourceStart + bodyOffset;
|
|
436
|
+
box.sourceEnd = last.sourceEnd + bodyOffset;
|
|
437
|
+
vdt.sourceStart = box.sourceStart;
|
|
438
|
+
vdt.sourceEnd = box.sourceEnd;
|
|
439
|
+
}
|
|
440
|
+
box.pageIndex = page.index;
|
|
441
|
+
box.columnIndex = 0;
|
|
442
|
+
offsetCalloutToAbsolute(result, rect.x, rect.y);
|
|
443
|
+
out.push(box);
|
|
444
|
+
vdt.blockIds.push(box.id);
|
|
445
|
+
for (const child of result.children) {
|
|
446
|
+
child.pageIndex = page.index;
|
|
447
|
+
child.columnIndex = 0;
|
|
448
|
+
out.push(child);
|
|
449
|
+
vdt.blockIds.push(child.id);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
/** The callout style a frame is drawn with: `base` (its `style`, or the
|
|
453
|
+
* frameless frame style) with what a frame sets of its own: its padding
|
|
454
|
+
* (side by side) and a measure that is the frame's. A style's placement,
|
|
455
|
+
* span, width and margins do not apply to a frame. */
|
|
456
|
+
export function frameStyleOf(base, frame) {
|
|
457
|
+
const padding = frame.padding ? { ...base.padding, ...frame.padding } : base.padding;
|
|
458
|
+
return {
|
|
459
|
+
...base,
|
|
460
|
+
padding,
|
|
461
|
+
width: 'fill',
|
|
462
|
+
placement: 'here',
|
|
463
|
+
span: 'column',
|
|
464
|
+
marginTop: { value: 0, unit: 'px' },
|
|
465
|
+
marginBottom: { value: 0, unit: 'px' },
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/** The story heads of a composed page's stories, by the head frame's
|
|
469
|
+
* name, read from the boxes `wrapComposedPages` made (`FRAME_ATTR`). */
|
|
470
|
+
export function composedStories(startIdx, endIdx, plans) {
|
|
471
|
+
const out = new Map();
|
|
472
|
+
for (let i = startIdx + 1; i < endIdx; i++) {
|
|
473
|
+
const plan = plans.get(i);
|
|
474
|
+
if (!plan)
|
|
475
|
+
continue;
|
|
476
|
+
const head = plan.attrs[FRAME_ATTR];
|
|
477
|
+
if (head !== undefined && !out.has(head))
|
|
478
|
+
out.set(head, { startIdx: i, plan });
|
|
479
|
+
i = plan.endIdx;
|
|
480
|
+
}
|
|
481
|
+
return out;
|
|
482
|
+
}
|
|
483
|
+
/** `d` in px, 0 when unset. */
|
|
484
|
+
export function lengthPx(d, dpi, emPx) {
|
|
485
|
+
return d ? dimensionToPx(d, dpi, emPx) : 0;
|
|
486
|
+
}
|
|
487
|
+
/** The composed pages of `blocks` whose template `source` has, by their
|
|
488
|
+
* opening marker's index. */
|
|
489
|
+
export function planComposedPages(blocks, plans, source) {
|
|
490
|
+
const out = new Map();
|
|
491
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
492
|
+
const b = blocks[i];
|
|
493
|
+
if (b.type !== 'containerStart' || b.containerName !== 'composedPage' || !b.composedPage)
|
|
494
|
+
continue;
|
|
495
|
+
let end = i + 1;
|
|
496
|
+
while (end < blocks.length && !(blocks[end].type === 'containerEnd' && blocks[end].containerId === b.containerId))
|
|
497
|
+
end++;
|
|
498
|
+
end = Math.min(end, blocks.length - 1);
|
|
499
|
+
if (resolvePageTemplate(source, b.composedPage.template)) {
|
|
500
|
+
const stories = composedStories(i, end, plans);
|
|
501
|
+
const list = [...stories.values()];
|
|
502
|
+
out.set(i, {
|
|
503
|
+
startIdx: i,
|
|
504
|
+
endIdx: end,
|
|
505
|
+
stories,
|
|
506
|
+
storyAt: (idx) => list.find((s) => idx > s.startIdx && idx < s.plan.endIdx),
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
i = end;
|
|
510
|
+
}
|
|
511
|
+
return out;
|
|
512
|
+
}
|
|
513
|
+
/** The planned composed page whose markers enclose block `idx`. */
|
|
514
|
+
export function composedPageAt(pages, idx) {
|
|
515
|
+
for (const p of pages.values())
|
|
516
|
+
if (idx > p.startIdx && idx < p.endIdx)
|
|
517
|
+
return p;
|
|
518
|
+
return undefined;
|
|
519
|
+
}
|
|
520
|
+
//# sourceMappingURL=composedLayout.js.map
|