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
package/dist/pipeline/build.js
CHANGED
|
@@ -2,6 +2,7 @@ import { withBitmapResolutions } from '../bitmapResolution';
|
|
|
2
2
|
import { plainTitleBreaks } from '../parse/inlineFormatting';
|
|
3
3
|
import { dimensionToPx } from '../units';
|
|
4
4
|
import { createVDTDocument, createVDTBlock, createBoundingBox, createVDTColumn, pageIsMirrored, pageIsVertical, flowRectToPage, } from '../vdt';
|
|
5
|
+
import { figureLabels } from './buildMeasurement';
|
|
5
6
|
import { anchorBox } from '../design/layout';
|
|
6
7
|
import { parseMarkdownMemo, spaceDirectiveLines } from '../parse';
|
|
7
8
|
import { buildPageLabels, computeHeadingNumbering, parseNumberFormat, } from '../numbering';
|
|
@@ -34,6 +35,10 @@ import { anchorTargetsOf, hasAnchorRefs, printsAnchorPages } from './crossRefs';
|
|
|
34
35
|
import { applyStatementNumbering, numberStatements, outlineLookup } from './statementNumbering';
|
|
35
36
|
import { SPAN_EMBED_STYLE_ID, isPageSpanStrip, spanEmbedStyle, wrapPageSpanEmbeds } from './spanEmbeds';
|
|
36
37
|
import { flowColumnsStyles, isFlowColumnsStyle, wrapFlowColumns } from './flowColumns';
|
|
38
|
+
import { FRAME_STYLE_ID, frameBoxStyle, wrapComposedPages } from '../composed/wrap';
|
|
39
|
+
import { resolvePageTemplate } from '../composed/templates';
|
|
40
|
+
import { layoutComposedSpread } from '../composed/spread';
|
|
41
|
+
import { composedPageAt, frameStyleOf, layoutComposedPage, planComposedPages } from './composedLayout';
|
|
37
42
|
import { anchorOutline, computeOutline, hasIndexDirective, hasTocDirective, headingNumberingOptions, headingTemplatesOf, outlineFromDoc, sameOutline } from './outline';
|
|
38
43
|
import { expandTocDirectives } from './toc';
|
|
39
44
|
import { expandIndexDirectives, locateIndexMarks } from './indexDirective';
|
|
@@ -49,8 +54,8 @@ import { measureContentBlock } from './measureContentBlock';
|
|
|
49
54
|
import { containerStyle, paragraphStyleIdOf, planParagraphContainers } from './paragraphContainers';
|
|
50
55
|
import { appendChapterEndNotes, footnoteIdsOfLines, footnoteParagraphStyle, noteContentBlock, noteNumberPositionOf, numberFootnotes, footnoteFormatOf, numberFootnotesByPlacement, sameFootnoteNumbers, splitFootnoteDefinitions, withFootnoteStyle, } from './footnotes';
|
|
51
56
|
import { planParts, derivePartMeasureContext } from './parts';
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
57
|
+
import { offsetBlock, offsetCalloutToAbsolute, pickCalloutStyle, planCallouts, resolveCalloutAttrs, } from './calloutLayout';
|
|
58
|
+
import { CUT_START, fragmentRange, makeCalloutLayouter as makeCalloutLayouterIn, splitCalloutFragment as splitCalloutFragmentIn, tallerThanColumn as tallerThanColumnIn, } from './frameLayout';
|
|
54
59
|
import { chooseTableSlice, layoutCaptionText, layoutResourceBlock, MIN_TAIL_ROWS } from './resourceLayout';
|
|
55
60
|
import { computeFloatPlan, floatedResourceIds, floatColumnCount, resolveResourcePlacement, } from './floatPlacement';
|
|
56
61
|
import { enumerateCurrentPageSlots, measureFloatBand, floatGapAbove, floatGapBelow, measureSideStack, clearSideObstacles, columnHasFloatBand, fitsStrict, trueBottom, } from './floatSlots';
|
|
@@ -77,6 +82,7 @@ import { annotateArabicMarks } from '../arabicMarks';
|
|
|
77
82
|
import { literalBreaksFor } from './hardBreaks';
|
|
78
83
|
import { tashkilFor } from './tashkil';
|
|
79
84
|
import { overlineEmphasis } from '../emphasisOverline';
|
|
85
|
+
import { highlightDocument } from '../highlightMarks';
|
|
80
86
|
import { withBookTitleBrackets } from './annotations';
|
|
81
87
|
import { paperByBlock, stampPagePaper } from './paper';
|
|
82
88
|
import { headingLineSpanBand } from './lineSpan';
|
|
@@ -479,7 +485,13 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
479
485
|
// set by the span-block path like any other.
|
|
480
486
|
// A `:::columns` group in the running text (#634): each in a frameless
|
|
481
487
|
// box the callout machinery places, cuts and splits.
|
|
482
|
-
|
|
488
|
+
// Composed pages (#855): each page's content regrouped into the stories
|
|
489
|
+
// its template's frames receive, one frameless box each (set at the
|
|
490
|
+
// page's template, below). Before the main-flow groups: a `:::columns`
|
|
491
|
+
// in a frame is a group of its box.
|
|
492
|
+
const templateSource = { pageTemplates: resolved.pageTemplates, calloutStyles: resolved.calloutStyles };
|
|
493
|
+
const composedWrap = wrapComposedPages(numberedBlocks, templateSource);
|
|
494
|
+
const flowGroups = resolved.layout.flowColumns ? wrapFlowColumns(composedWrap.blocks) : { blocks: composedWrap.blocks, wrapped: false };
|
|
483
495
|
const spanEmbeds = wrapPageSpanEmbeds(flowGroups.blocks, content.resources ?? [], effectiveResourceTypes(config, content.resources ?? []));
|
|
484
496
|
// Code listings (#624): each in a box of the code style, which the
|
|
485
497
|
// callout machinery places and splits.
|
|
@@ -516,6 +528,14 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
516
528
|
for (const [id, entry] of Object.entries(resourceNumbering)) {
|
|
517
529
|
resourceNumberById.set(id, entry.number);
|
|
518
530
|
}
|
|
531
|
+
// The labels of each `:::figure` (#862), by resource: a figure that
|
|
532
|
+
// floats is laid out by its id alone.
|
|
533
|
+
const figureLabelsById = new Map();
|
|
534
|
+
for (const b of contentBlocks) {
|
|
535
|
+
const labels = b.resourceId !== undefined && !figureLabelsById.has(b.resourceId) ? figureLabels(b) : undefined;
|
|
536
|
+
if (labels)
|
|
537
|
+
figureLabelsById.set(b.resourceId, labels);
|
|
538
|
+
}
|
|
519
539
|
// Resolve styles
|
|
520
540
|
const bodyStyle = resolveBodyStyle(resolved);
|
|
521
541
|
// The callout styles, with the frameless box of the page-span embeds
|
|
@@ -525,6 +545,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
525
545
|
const syntheticBoxes = [
|
|
526
546
|
...(spanEmbeds.wrapped ? [spanEmbedStyle(bodyStyle.lineHeightPx, resolved.layout.inlineResourceGap !== 'above')] : []),
|
|
527
547
|
...(codeBoxes.wrapped ? [codeBoxStyle(resolved)] : []),
|
|
548
|
+
// The frameless box of a composed page's story (#855).
|
|
549
|
+
...(composedWrap.wrapped ? [frameBoxStyle(Math.max(resolved.bodyText.avoidOrphans ? resolved.bodyText.orphanMinLines : 1, resolved.bodyText.avoidWidows ? resolved.bodyText.widowMinLines : 1))] : []),
|
|
528
550
|
// The boxes of main-flow groups: sub-columns a body line apart in the
|
|
529
551
|
// text column, a gutter apart across the page.
|
|
530
552
|
...(flowGroups.wrapped
|
|
@@ -536,7 +558,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
536
558
|
: resolved.calloutStyles;
|
|
537
559
|
// A box nested in another looks its style up in the configuration it is
|
|
538
560
|
// laid out with: the listings' box among them.
|
|
539
|
-
const calloutResolved = codeBoxes.wrapped || flowGroups.wrapped ? { ...resolved, calloutStyles } : resolved;
|
|
561
|
+
const calloutResolved = codeBoxes.wrapped || flowGroups.wrapped || composedWrap.wrapped ? { ...resolved, calloutStyles } : resolved;
|
|
540
562
|
const blockquoteStyle = resolveBlockquoteStyle(resolved);
|
|
541
563
|
const listLevelIndentsPx = computeLevelIndentsPx(resolved, bodyStyle.fontSizePx);
|
|
542
564
|
const orderedMetrics = computeOrderedListRunMetrics(contentBlocks, resolved, bodyStyle.fontSizePx);
|
|
@@ -568,6 +590,23 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
568
590
|
// mode of the styled section the reference sits in (a horizontal
|
|
569
591
|
// appendix of a vertical book turns its figures as asked).
|
|
570
592
|
const floatPlan = computeFloatPlan(contentBlocks, resources, resourceTypes, incorporated, (blockIdx) => sectionWritingMode(sectionPlan, resolved, blockIdx) === 'vertical-rl', resolved.layout.floatShrink, resolved.layout.wrap, resolved.layout.floatsAtCitingPage);
|
|
593
|
+
// A composed page's pictures are set in its frames: a `::resource` a
|
|
594
|
+
// story holds does not float. A reference in a frame to a picture set
|
|
595
|
+
// elsewhere floats from the page's end, to the pages after it.
|
|
596
|
+
const composedPlans = planComposedPages(contentBlocks, calloutPlan, templateSource);
|
|
597
|
+
if (composedPlans.size > 0) {
|
|
598
|
+
for (let k = floatPlan.length - 1; k >= 0; k--) {
|
|
599
|
+
const f = floatPlan[k];
|
|
600
|
+
const page = composedPageAt(composedPlans, f.firstBlockIdx);
|
|
601
|
+
if (!page)
|
|
602
|
+
continue;
|
|
603
|
+
const raw = contentBlocks[f.firstBlockIdx];
|
|
604
|
+
if (raw?.type === 'resourceBlock' && raw.resourceId === f.resourceId && page.storyAt(f.firstBlockIdx))
|
|
605
|
+
floatPlan.splice(k, 1);
|
|
606
|
+
else
|
|
607
|
+
f.firstBlockIdx = page.endIdx;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
571
610
|
const floatedIds = floatedResourceIds(floatPlan, incorporated, resources, resourceTypes);
|
|
572
611
|
const floatsByFirstBlock = new Map();
|
|
573
612
|
for (const f of floatPlan) {
|
|
@@ -1216,7 +1255,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
1216
1255
|
const { block: rb, totalHeight } = laid;
|
|
1217
1256
|
const id = slice && slice.startRow > 0 ? `float-${resourceId}-cont-${slice.startRow}` : `float-${resourceId}`;
|
|
1218
1257
|
const blk = createVDTBlock(id, 'resource', bodyStyle.fontString, bodyStyle.color, bodyStyle.textAlign);
|
|
1219
|
-
|
|
1258
|
+
const labels = figureLabelsById.get(resourceId);
|
|
1259
|
+
blk.resourceBlock = labels ? { ...rb, labels } : rb;
|
|
1220
1260
|
blk.dirty = false;
|
|
1221
1261
|
blk.snappedToGrid = false;
|
|
1222
1262
|
blk.bbox = createBoundingBox(x, 0, width, totalHeight);
|
|
@@ -2986,7 +3026,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
2986
3026
|
// A page still empty takes the geometry right away — the document (or
|
|
2987
3027
|
// a chapter laid out on its own) opening with a styled heading.
|
|
2988
3028
|
const page = doc.pages[cursor.pageIndex];
|
|
2989
|
-
if (page && !page.partInfo && !page.comic && cursor.columnIndex === 0
|
|
3029
|
+
if (page && !page.partInfo && !page.comic && !page.composed && cursor.columnIndex === 0
|
|
2990
3030
|
&& !pageHasContent(page) && !(page.floats && page.floats.length > 0)) {
|
|
2991
3031
|
const fresh = createPageWithColumns(page.index, geomResolved, contentArea, pageWidthPx, pageHeightPx, pageIndexOffset);
|
|
2992
3032
|
if (page.blankForParity)
|
|
@@ -3368,7 +3408,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3368
3408
|
*/
|
|
3369
3409
|
const openSpanHeadingHere = (blockIdx, rawBlock, level) => {
|
|
3370
3410
|
const page = doc.pages[cursor.pageIndex];
|
|
3371
|
-
if (page.partInfo || page.comic || currentColumn(doc, cursor).kind === 'span')
|
|
3411
|
+
if (page.partInfo || page.comic || page.composed || currentColumn(doc, cursor).kind === 'span')
|
|
3372
3412
|
return false;
|
|
3373
3413
|
const band = currentBand(page, cursor);
|
|
3374
3414
|
const cols = bandColumns(page, band);
|
|
@@ -3502,7 +3542,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3502
3542
|
if (!balancingCfg.enabled || !balancingCfg.trailing)
|
|
3503
3543
|
return;
|
|
3504
3544
|
const page = doc.pages[cursor.pageIndex];
|
|
3505
|
-
if (page.columns[cursor.columnIndex]?.kind === 'span' || page.partInfo || page.comic)
|
|
3545
|
+
if (page.columns[cursor.columnIndex]?.kind === 'span' || page.partInfo || page.comic || page.composed)
|
|
3506
3546
|
return;
|
|
3507
3547
|
const band = currentBand(page, cursor);
|
|
3508
3548
|
const cols = bandColumns(page, band).filter((c) => c.bbox.height > 0.5);
|
|
@@ -3708,8 +3748,11 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3708
3748
|
/** A closed `:::paper` still owes a page break before the next placed
|
|
3709
3749
|
* block. */
|
|
3710
3750
|
let pendingPaperBreak = false;
|
|
3711
|
-
/** A composed page (`::::page`, #854)
|
|
3712
|
-
*
|
|
3751
|
+
/** A composed page (`::::page`, #854) owes a page break before the next
|
|
3752
|
+
* placed block: `'page'` once its template was laid on the current page
|
|
3753
|
+
* (nothing flowed on it), `'flow'` after content set in the flow (a page
|
|
3754
|
+
* of unknown template, or what no frame took), which closes as a
|
|
3755
|
+
* `:::paper` run does. */
|
|
3713
3756
|
let pendingComposedBreak = false;
|
|
3714
3757
|
/** A comic page (`:::page`) was laid out on the current page: the next
|
|
3715
3758
|
* placed block opens a new one (a page that ends the document leaves no
|
|
@@ -3740,7 +3783,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3740
3783
|
let pendingNumberingPage = 0;
|
|
3741
3784
|
/** A page holding something the reader sees: column content, a float, a
|
|
3742
3785
|
* part opener. A parity blank is not one. */
|
|
3743
|
-
const pageTakesNumbering = (page) => pageHasContent(page) || (page.floats?.length ?? 0) > 0 || page.partInfo !== undefined || page.comic !== undefined;
|
|
3786
|
+
const pageTakesNumbering = (page) => pageHasContent(page) || (page.floats?.length ?? 0) > 0 || page.partInfo !== undefined || page.comic !== undefined || page.composed !== undefined;
|
|
3744
3787
|
/** Commits a pending `:::numbering` change to the first page from the
|
|
3745
3788
|
* directive on that receives content: the page the directive opens (the
|
|
3746
3789
|
* head of a chapter, right after a page break) or, when that page was
|
|
@@ -3905,16 +3948,14 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3905
3948
|
doc.blocks.push(child);
|
|
3906
3949
|
}
|
|
3907
3950
|
};
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
};
|
|
3917
|
-
const CUT_START = { child: 0, line: 0 };
|
|
3951
|
+
// --- Callout fragments (`keepTogether: false`) ---------------------------
|
|
3952
|
+
// A splittable box breaks only BETWEEN its child blocks (a list item or a
|
|
3953
|
+
// paragraph is never cut in two): the fragment that fits closes the
|
|
3954
|
+
// current column / page, the rest continues in a box of its own — same
|
|
3955
|
+
// frame, stripe and marker, no title or icon — on the next one, and may
|
|
3956
|
+
// split again. Every
|
|
3957
|
+
// fragment's frame shares the fence's `contentIndex` / `containerId` and
|
|
3958
|
+
// records its `callout.part` / `callout.continued`.
|
|
3918
3959
|
/** A strip in a box (the box of a page-wide strip set `here`, #590):
|
|
3919
3960
|
* laid out at the box's inner width, as tall as a page allows, with its
|
|
3920
3961
|
* placeholder line; the page it lays out for is the cursor's. */
|
|
@@ -3925,85 +3966,21 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3925
3966
|
withStripPlaceholder(blk, stripGeometry(idx, raw.comic, width, contentArea.height - 2 * floatGapPx, pageIsVertical(doc.pages[cursor.pageIndex])));
|
|
3926
3967
|
return blk;
|
|
3927
3968
|
};
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
//
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
groups.push([k, e]);
|
|
3944
|
-
}
|
|
3945
|
-
});
|
|
3946
|
-
const layoutRange = (from, to, width, frameId, continuation, mirrored = false) => {
|
|
3947
|
-
let n = 0;
|
|
3948
|
-
// A fragment that opens inside a `:::columns` group starts at its
|
|
3949
|
-
// opening marker and one that ends inside it at its closing marker:
|
|
3950
|
-
// the group sets the part between the cut's positions (#634).
|
|
3951
|
-
const fromChild = from.group ? from.group.open : from.child;
|
|
3952
|
-
const closeOfGroup = (open) => groups.find(([gs]) => gs === open)?.[1] ?? children.length - 1;
|
|
3953
|
-
// A cut inside child `to.child` includes that child (its first
|
|
3954
|
-
// `to.line` lines); a cut at a child's head excludes it.
|
|
3955
|
-
const toChild = to.group ? closeOfGroup(to.group.open) + 1 : to.line > 0 ? to.child + 1 : to.child;
|
|
3956
|
-
const inSlice = (pos) => pos.map((p) => ({ ...p, child: p.child - fromChild }));
|
|
3957
|
-
// Nested boxes still open at `from` (their closing markers leading
|
|
3958
|
-
// the range close them): the fragment opens inside them.
|
|
3959
|
-
const open = [];
|
|
3960
|
-
for (let k = 0; k < fromChild; k++) {
|
|
3961
|
-
const c = children[k];
|
|
3962
|
-
if (c.containerName !== 'callout')
|
|
3963
|
-
continue;
|
|
3964
|
-
if (c.type === 'containerStart')
|
|
3965
|
-
open.push({ idx: startIdx + 1 + k, block: c });
|
|
3966
|
-
else if (c.type === 'containerEnd')
|
|
3967
|
-
open.pop();
|
|
3968
|
-
}
|
|
3969
|
-
for (let k = fromChild; k < children.length && open.length > 0; k++) {
|
|
3970
|
-
const c = children[k];
|
|
3971
|
-
if (c.type !== 'containerEnd' || c.containerId !== open[open.length - 1].block.containerId)
|
|
3972
|
-
break;
|
|
3973
|
-
open.pop();
|
|
3974
|
-
}
|
|
3975
|
-
return layoutCallout({
|
|
3976
|
-
style,
|
|
3977
|
-
attrs: plan.attrs,
|
|
3978
|
-
...(contentBlocks[startIdx]?.direction ? { direction: contentBlocks[startIdx].direction } : {}),
|
|
3979
|
-
continuation,
|
|
3980
|
-
// Any range short of the box's end is a fragment that goes on.
|
|
3981
|
-
...(to.child < children.length || to.line > 0 || to.group ? { continues: true } : {}),
|
|
3982
|
-
children: children.slice(fromChild, toChild),
|
|
3983
|
-
childStartIdx: startIdx + 1 + fromChild,
|
|
3984
|
-
width,
|
|
3985
|
-
// A main-flow group's box sets its blocks as the text around it is
|
|
3986
|
-
// set: a styled section's or a part's body (#634).
|
|
3987
|
-
ctx: isFlowColumnsStyle(style.id)
|
|
3988
|
-
? (partPlan.byBlock[startIdx] ? partMeasureCtx : sectionMeasureCtx(sectionPlan.byBlock[startIdx]))
|
|
3989
|
-
: measureCtx,
|
|
3990
|
-
resolved: calloutResolved,
|
|
3991
|
-
containerId: plan.containerId,
|
|
3992
|
-
frameId,
|
|
3993
|
-
nextChildId: () => `${frameId}-c${n++}`,
|
|
3994
|
-
paragraphContainers,
|
|
3995
|
-
...(from.line > 0 && !from.group ? { lineFrom: from.line } : {}),
|
|
3996
|
-
...(from.line > 0 && !from.group && from.widths ? { lineWidths: from.widths } : {}),
|
|
3997
|
-
...(to.line > 0 && !to.group ? { lineTo: to.line } : {}),
|
|
3998
|
-
...(from.group ? { groupFrom: inSlice(from.group.pos) } : {}),
|
|
3999
|
-
...(to.group ? { groupTo: inSlice(to.group.pos) } : {}),
|
|
4000
|
-
...(open.length > 0 ? { openNested: open } : {}),
|
|
4001
|
-
mirrored,
|
|
4002
|
-
stripBlock: calloutStripBlock,
|
|
4003
|
-
});
|
|
4004
|
-
};
|
|
4005
|
-
return { children, childBase: startIdx + 1, realAt, end: { child: children.length, line: 0 }, layoutRange, groups };
|
|
4006
|
-
};
|
|
3969
|
+
/** What the box typesetter (`frameLayout.ts`) reads of this pass. */
|
|
3970
|
+
const framePass = {
|
|
3971
|
+
contentBlocks,
|
|
3972
|
+
resolved,
|
|
3973
|
+
calloutResolved,
|
|
3974
|
+
paragraphContainers,
|
|
3975
|
+
// A main-flow group's box sets its blocks as the text around it is
|
|
3976
|
+
// set: a styled section's or a part's body (#634).
|
|
3977
|
+
measureCtxFor: (startIdx, style) => (isFlowColumnsStyle(style.id) || style.id === FRAME_STYLE_ID
|
|
3978
|
+
? (partPlan.byBlock[startIdx] ? partMeasureCtx : sectionMeasureCtx(sectionPlan.byBlock[startIdx]))
|
|
3979
|
+
: measureCtx),
|
|
3980
|
+
stripBlock: calloutStripBlock,
|
|
3981
|
+
columnHeight: () => contentArea.height,
|
|
3982
|
+
};
|
|
3983
|
+
const makeCalloutLayouter = (startIdx, plan, style) => makeCalloutLayouterIn(framePass, startIdx, plan, style);
|
|
4007
3984
|
/** Whether a page swaps its mirrored margins (a verso of a left-bound
|
|
4008
3985
|
* book, a recto of a right-bound one: an `'outer'` corner icon hangs on
|
|
4009
3986
|
* the left there). A vertical page has no outer side: a box's outer
|
|
@@ -4029,192 +4006,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4029
4006
|
const withSide = side && sideUsedBottom(side) > side.bbox.y + 0.5 ? [...cols, side] : cols;
|
|
4030
4007
|
return bandUsedBottom(withSide);
|
|
4031
4008
|
};
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
* lines of a text child. `splitMinLines` guards text: a cut between
|
|
4035
|
-
* children leaves on each side at least that many text lines or at least
|
|
4036
|
-
* one indivisible block (a figure, table, display formula or nested
|
|
4037
|
-
* box); a cut inside a text child counts every line on its side, a block
|
|
4038
|
-
* as one line, and leaves at least `layout.boxChildSplitMinLines` lines
|
|
4039
|
-
* of that child on each side (two by default, `splitMinLines` when that
|
|
4040
|
-
* is lower; EF-115). A nested box that may split
|
|
4041
|
-
* itself (`keepTogether: false`, or taller than a full column) offers the cuts
|
|
4042
|
-
* inside it too, by its own `splitMinLines` over its own children; the
|
|
4043
|
-
* fragments on both sides redraw its frame. The full layout's geometry
|
|
4044
|
-
* ranks the candidates (box bottom = content bottom at the cut + the
|
|
4045
|
-
* tails of the boxes closed below it); the deepest candidate that fits
|
|
4046
|
-
* is laid out for real and taken when it truly fits. `null` when none
|
|
4047
|
-
* does. */
|
|
4048
|
-
const splitCalloutFragment = (L, from, width, roomPx, frameId, continuation, minLines, mirrored = false) => {
|
|
4049
|
-
const full = L.layoutRange(from, L.end, width, frameId, continuation, mirrored);
|
|
4050
|
-
/** Figures, tables and display formulas: never cut, not text lines. */
|
|
4051
|
-
const indivisible = (c) => c.type === 'resource' || c.type === 'mathDisplay';
|
|
4052
|
-
const unitBottom = (u) => {
|
|
4053
|
-
const b = u.kind === 'block' ? u.block.bbox : u.box.result.frame.bbox;
|
|
4054
|
-
return b.y + b.height;
|
|
4055
|
-
};
|
|
4056
|
-
/** Room a box keeps under its last item (padding, border, icon growth). */
|
|
4057
|
-
const tailOf = (r) => {
|
|
4058
|
-
const last = r.units[r.units.length - 1];
|
|
4059
|
-
return last ? r.frame.bbox.y + r.totalHeight - unitBottom(last) : 0;
|
|
4060
|
-
};
|
|
4061
|
-
if (full.units.length === 0)
|
|
4062
|
-
return null;
|
|
4063
|
-
// A head that goes on also carries the style's continuation marker.
|
|
4064
|
-
const tail = tailOf(full) + full.continuesMarkerPx;
|
|
4065
|
-
/** Candidate cuts with the head's content bottom. A `soft` cut parts a
|
|
4066
|
-
* wrapped code line from its continuation (#624): taken only when no
|
|
4067
|
-
* other cut fits. */
|
|
4068
|
-
const candidates = [];
|
|
4069
|
-
/** Collect the cuts among `units` (one box's items; `below` = the tails
|
|
4070
|
-
* of the nested boxes around them), each side of a cut holding enough
|
|
4071
|
-
* by the box's `min` lines: a block counts as one line, a nested box
|
|
4072
|
-
* as one indivisible block. */
|
|
4073
|
-
const collect = (units, minLines, below) => {
|
|
4074
|
-
const min = Math.max(1, minLines);
|
|
4075
|
-
const lineCount = (u) => (u.kind === 'block' ? Math.max(1, u.block.lines.length) : 1);
|
|
4076
|
-
const isBlock = (u) => u.kind === 'box' || indivisible(u.block);
|
|
4077
|
-
const totalLines = units.reduce((n, u) => n + lineCount(u), 0);
|
|
4078
|
-
const totalBlocks = units.filter(isBlock).length;
|
|
4079
|
-
/** A side of a cut holds enough: `lines` (blocks included) of which
|
|
4080
|
-
* `blocks` are indivisible. Between children, one block suffices or
|
|
4081
|
-
* the text lines alone meet the minimum; inside a text child, the
|
|
4082
|
-
* lines do. */
|
|
4083
|
-
const holds = (lines, blocks, betweenChildren) => betweenChildren ? blocks > 0 || lines - blocks >= min : lines >= min;
|
|
4084
|
-
const bothHold = (lines, blocks, betweenChildren) => holds(lines, blocks, betweenChildren) && holds(totalLines - lines, totalBlocks - blocks, betweenChildren);
|
|
4085
|
-
let linesBefore = 0;
|
|
4086
|
-
let blocksBefore = 0;
|
|
4087
|
-
units.forEach((u, i) => {
|
|
4088
|
-
let next;
|
|
4089
|
-
if (u.kind === 'block') {
|
|
4090
|
-
const c = u.block;
|
|
4091
|
-
const k = (c.contentIndex ?? L.childBase) - L.childBase;
|
|
4092
|
-
next = k + 1;
|
|
4093
|
-
if (!indivisible(c) && c.lines.length > 1) {
|
|
4094
|
-
// The first laid-out child of a continuation opens after
|
|
4095
|
-
// `from.line` lines: cuts inside it are counted from the
|
|
4096
|
-
// child's own head. Each side of the box still counts all its
|
|
4097
|
-
// lines against `min`, and a cut inside a child leaves at least
|
|
4098
|
-
// `layout.boxChildSplitMinLines` lines of it on each side (2 by
|
|
4099
|
-
// default, so no lone line: EF-115), or `min` when that is
|
|
4100
|
-
// lower. The count is of this fragment's part of the child,
|
|
4101
|
-
// since a part left behind already passed the test.
|
|
4102
|
-
const childMin = Math.min(min, resolved.layout.boxChildSplitMinLines);
|
|
4103
|
-
const lineBase = k === from.child ? from.line : 0;
|
|
4104
|
-
for (let l = childMin; l <= c.lines.length - childMin; l++) {
|
|
4105
|
-
const line = c.lines[l - 1];
|
|
4106
|
-
if (bothHold(linesBefore + l, blocksBefore, false)) {
|
|
4107
|
-
candidates.push({
|
|
4108
|
-
cut: { child: k, line: lineBase + l, widths: k === from.child ? cutWidths(from, width) : [{ fromLine: 0, width }] },
|
|
4109
|
-
bottom: line.bbox.y + line.bbox.height + below,
|
|
4110
|
-
...(c.lines[l]?.codeLine?.continued ? { soft: true } : {}),
|
|
4111
|
-
});
|
|
4112
|
-
}
|
|
4113
|
-
}
|
|
4114
|
-
}
|
|
4115
|
-
}
|
|
4116
|
-
else {
|
|
4117
|
-
const { box } = u;
|
|
4118
|
-
if (box.endIdx !== undefined)
|
|
4119
|
-
next = box.endIdx + 1 - L.childBase;
|
|
4120
|
-
if (!box.style.keepTogether || tallerThanColumn(box.result)) {
|
|
4121
|
-
collect(box.result.units, box.style.splitMinLines, below + tailOf(box.result));
|
|
4122
|
-
}
|
|
4123
|
-
}
|
|
4124
|
-
linesBefore += lineCount(u);
|
|
4125
|
-
if (isBlock(u))
|
|
4126
|
-
blocksBefore++;
|
|
4127
|
-
if (i < units.length - 1 && next !== undefined && bothHold(linesBefore, blocksBefore, true)) {
|
|
4128
|
-
candidates.push({ cut: { child: next, line: 0 }, bottom: unitBottom(u) + below });
|
|
4129
|
-
}
|
|
4130
|
-
});
|
|
4131
|
-
};
|
|
4132
|
-
collect(full.units, minLines, 0);
|
|
4133
|
-
// Inside a `:::columns` group of the box (#634): the cut the group
|
|
4134
|
-
// offers for the room, where each of its sub-columns (each stream, in
|
|
4135
|
-
// a parallel group) ends when the galley fills them in turn; at least
|
|
4136
|
-
// one stream goes on and one moves on. A group of a nested box is
|
|
4137
|
-
// never cut, nor any group under 1.24's rules (`layout.flowColumns`).
|
|
4138
|
-
if (resolved.layout.flowColumns) {
|
|
4139
|
-
const base = from.group ? from.group.open : from.child;
|
|
4140
|
-
const childMin = Math.min(Math.max(1, minLines), resolved.layout.boxChildSplitMinLines);
|
|
4141
|
-
for (const g of full.groups ?? []) {
|
|
4142
|
-
const h = roomPx - tail - g.top;
|
|
4143
|
-
if (h <= 0.5)
|
|
4144
|
-
continue;
|
|
4145
|
-
const reopened = from.group?.open === g.open + base ? from.group : undefined;
|
|
4146
|
-
const pos = [];
|
|
4147
|
-
let moved = false;
|
|
4148
|
-
let left = false;
|
|
4149
|
-
let used = 0;
|
|
4150
|
-
g.streams.forEach((items, s) => {
|
|
4151
|
-
const end = { child: (g.ends[s] ?? g.close) + base, line: 0 };
|
|
4152
|
-
if (items.length === 0) {
|
|
4153
|
-
pos.push(end);
|
|
4154
|
-
return;
|
|
4155
|
-
}
|
|
4156
|
-
const breaks = galleyBreaks(items, childMin);
|
|
4157
|
-
const fill = fillGalley(items, breaks, g.flow === 'snake' ? g.columns : 1, h);
|
|
4158
|
-
if (fill.end) {
|
|
4159
|
-
moved = true;
|
|
4160
|
-
used = Math.max(used, fill.used);
|
|
4161
|
-
pos.push(end);
|
|
4162
|
-
return;
|
|
4163
|
-
}
|
|
4164
|
-
left = true;
|
|
4165
|
-
if (fill.cuts.length === 0) {
|
|
4166
|
-
// This stream takes nothing in the fragment: it stays where it is.
|
|
4167
|
-
pos.push(reopened?.pos[s] ?? { child: items[0].child + base, line: 0 });
|
|
4168
|
-
return;
|
|
4169
|
-
}
|
|
4170
|
-
moved = true;
|
|
4171
|
-
used = Math.max(used, fill.used);
|
|
4172
|
-
const b = breaks[fill.cuts[fill.cuts.length - 1]];
|
|
4173
|
-
const it = items[b.item];
|
|
4174
|
-
if (b.line === 0) {
|
|
4175
|
-
pos.push({ child: it.child + base, line: 0 });
|
|
4176
|
-
return;
|
|
4177
|
-
}
|
|
4178
|
-
// The sub-column widths the paragraph's lines are set at.
|
|
4179
|
-
const before = it.lineBase > 0 ? reopened?.pos[s]?.widths : undefined;
|
|
4180
|
-
const lastW = before?.[before.length - 1];
|
|
4181
|
-
const widths = !before || before.length === 0
|
|
4182
|
-
? [{ fromLine: 0, width: g.columnWidth }]
|
|
4183
|
-
: Math.abs(lastW.width - g.columnWidth) <= 0.5 ? before : [...before, { fromLine: it.lineBase, width: g.columnWidth }];
|
|
4184
|
-
pos.push({ child: it.child + base, line: it.lineBase + b.line, widths });
|
|
4185
|
-
});
|
|
4186
|
-
if (!moved || !left)
|
|
4187
|
-
continue;
|
|
4188
|
-
candidates.push({
|
|
4189
|
-
cut: { child: Math.min(...pos.map((p) => p.child)), line: 0, group: { open: g.open + base, pos } },
|
|
4190
|
-
bottom: g.top + used,
|
|
4191
|
-
});
|
|
4192
|
-
}
|
|
4193
|
-
}
|
|
4194
|
-
const insideGroup = (cut) => !cut.group && L.groups.some(([gs, ge]) => (cut.line === 0 ? gs < cut.child && cut.child <= ge : gs < cut.child && cut.child < ge));
|
|
4195
|
-
const viable = candidates
|
|
4196
|
-
.filter((c) => !insideGroup(c.cut))
|
|
4197
|
-
.sort((a, b) => b.bottom - a.bottom);
|
|
4198
|
-
// A wrapped code line stays with its continuations when a cut
|
|
4199
|
-
// elsewhere fits (#624).
|
|
4200
|
-
viable.sort((a, b) => (a.soft ? 1 : 0) - (b.soft ? 1 : 0));
|
|
4201
|
-
for (const c of viable) {
|
|
4202
|
-
if (c.bottom + tail > roomPx + 0.01)
|
|
4203
|
-
continue;
|
|
4204
|
-
const result = L.layoutRange(from, c.cut, width, frameId, continuation, mirrored);
|
|
4205
|
-
if (result.totalHeight <= roomPx + 0.01)
|
|
4206
|
-
return { to: c.cut, result };
|
|
4207
|
-
}
|
|
4208
|
-
return null;
|
|
4209
|
-
};
|
|
4210
|
-
/** Absolute content indices of the children a fragment from cut `from`
|
|
4211
|
-
* to cut `to` of `L` touches, for the fragment's source range. */
|
|
4212
|
-
const fragmentRange = (L, from, to) => ({ firstChildIdx: L.childBase + from.child, lastChildIdx: L.childBase + (to.line > 0 ? to.child : to.child - 1) });
|
|
4213
|
-
/** The (rest of the) box is taller than an empty, full-height column —
|
|
4214
|
-
* a whole page's content area for a page-span box: no column could
|
|
4215
|
-
* hold it, so even a keep-together box splits (with the rules of a
|
|
4216
|
-
* `keepTogether: false` one) rather than overflow. */
|
|
4217
|
-
const tallerThanColumn = (result) => result.totalHeight > contentArea.height + 0.01;
|
|
4009
|
+
const splitCalloutFragment = (L, from, width, roomPx, frameId, continuation, minLines, mirrored = false) => splitCalloutFragmentIn(framePass, L, from, width, roomPx, frameId, continuation, minLines, mirrored);
|
|
4010
|
+
const tallerThanColumn = (result) => tallerThanColumnIn(framePass, result);
|
|
4218
4011
|
const markFragment = (result, part, continued) => {
|
|
4219
4012
|
if (result.frame.callout) {
|
|
4220
4013
|
result.frame.callout.part = part;
|
|
@@ -6055,6 +5848,102 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6055
5848
|
}
|
|
6056
5849
|
return out;
|
|
6057
5850
|
};
|
|
5851
|
+
/** Content indices a composed page set in its frames: the main loop
|
|
5852
|
+
* passes over them. */
|
|
5853
|
+
const composedLaid = new Set();
|
|
5854
|
+
/** The composed pages' layout warnings (`frameOverflow`). */
|
|
5855
|
+
const composedNotes = [];
|
|
5856
|
+
/** Set the composed page `planned` on a fresh page (#855), or a spread
|
|
5857
|
+
* template on the two facing pages from the next verso (#861). */
|
|
5858
|
+
const placeComposedPage = (planned, fence) => {
|
|
5859
|
+
pendingSpacing = 0;
|
|
5860
|
+
closeFlowSegment(planned.startIdx);
|
|
5861
|
+
leaveCurrentPage();
|
|
5862
|
+
cursor.columnIndex = 0;
|
|
5863
|
+
const frameless = calloutStyles.find((st) => st.id === FRAME_STYLE_ID);
|
|
5864
|
+
const common = (page) => ({
|
|
5865
|
+
pass: framePass,
|
|
5866
|
+
fence,
|
|
5867
|
+
startIdx: planned.startIdx,
|
|
5868
|
+
endIdx: planned.endIdx,
|
|
5869
|
+
stories: planned.stories,
|
|
5870
|
+
styleOf: (frame) => frameStyleOf((frame.style ? resolved.calloutStyles.find((st) => st.id === frame.style) : undefined) ?? frameless, frame),
|
|
5871
|
+
dpi,
|
|
5872
|
+
emPx: bodyStyle.fontSizePx,
|
|
5873
|
+
bodyOffset,
|
|
5874
|
+
mirrored: mirroredOf(page),
|
|
5875
|
+
pushGapPx: wrapGapPx(resolved.layout.wrap?.gap, dpi, bodyStyle.fontSizePx, floatGapPx),
|
|
5876
|
+
});
|
|
5877
|
+
const placed = [];
|
|
5878
|
+
let laid;
|
|
5879
|
+
const sheet = resolvePageTemplate(templateSource, fence.template, { spread: true });
|
|
5880
|
+
if (sheet?.spread) {
|
|
5881
|
+
// A spread opens on a verso, a parity blank before it when needed,
|
|
5882
|
+
// as a comic spread does; the recto after it takes the other half.
|
|
5883
|
+
breakToEvenPage();
|
|
5884
|
+
const verso = doc.pages[cursor.pageIndex];
|
|
5885
|
+
verso.columns = [createVDTColumn(0, verso.contentArea)];
|
|
5886
|
+
const start = cursor.pageIndex;
|
|
5887
|
+
do {
|
|
5888
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx);
|
|
5889
|
+
} while (cursor.pageIndex === start);
|
|
5890
|
+
const recto = doc.pages[cursor.pageIndex];
|
|
5891
|
+
recto.columns = [createVDTColumn(0, recto.contentArea)];
|
|
5892
|
+
cursor.columnIndex = 0;
|
|
5893
|
+
// The sheet is laid in the pages' flow: the left page first, or the
|
|
5894
|
+
// right one where the flow is mirrored (right to left).
|
|
5895
|
+
const versoIsLeft = resolved.page.binding !== 'right';
|
|
5896
|
+
const flowMirrored = pageIsMirrored(verso);
|
|
5897
|
+
const left = versoIsLeft ? verso : recto;
|
|
5898
|
+
const right = versoIsLeft ? recto : verso;
|
|
5899
|
+
const out = layoutComposedSpread({
|
|
5900
|
+
...common(flowMirrored ? right : left),
|
|
5901
|
+
template: sheet,
|
|
5902
|
+
first: flowMirrored ? right : left,
|
|
5903
|
+
second: flowMirrored ? left : right,
|
|
5904
|
+
firstSide: flowMirrored ? 'right' : 'left',
|
|
5905
|
+
trim: pageMetrics.physical.trimBox,
|
|
5906
|
+
bleed: pageMetrics.physical.bleedBox,
|
|
5907
|
+
});
|
|
5908
|
+
placed.push(...out.sides);
|
|
5909
|
+
composedNotes.push(...out.warnings);
|
|
5910
|
+
laid = out.laid;
|
|
5911
|
+
}
|
|
5912
|
+
else {
|
|
5913
|
+
const page = doc.pages[cursor.pageIndex];
|
|
5914
|
+
page.columns = [createVDTColumn(0, page.contentArea)];
|
|
5915
|
+
// The physical side: a recto has an odd folio (in either binding).
|
|
5916
|
+
const parity = (page.index + pageIndexOffset) % 2 === 0 ? 'recto' : 'verso';
|
|
5917
|
+
const template = resolvePageTemplate(templateSource, fence.template, { parity });
|
|
5918
|
+
const frames = designFramesOn(page);
|
|
5919
|
+
const area = template.area === 'trim' ? frames.page : template.area === 'bleed' ? frames.bleed : page.contentArea;
|
|
5920
|
+
const out = layoutComposedPage({
|
|
5921
|
+
...common(page),
|
|
5922
|
+
page,
|
|
5923
|
+
template,
|
|
5924
|
+
areas: { area, page: frames.page, bleed: frames.bleed },
|
|
5925
|
+
});
|
|
5926
|
+
placed.push({ page, composed: out.composed, blocks: out.blocks });
|
|
5927
|
+
composedNotes.push(...out.warnings);
|
|
5928
|
+
laid = out.laid;
|
|
5929
|
+
}
|
|
5930
|
+
for (const { page, composed, blocks } of placed) {
|
|
5931
|
+
page.composed = composed;
|
|
5932
|
+
const floats = (page.floats ??= []);
|
|
5933
|
+
for (const b of blocks) {
|
|
5934
|
+
floats.push(b);
|
|
5935
|
+
doc.blocks.push(b);
|
|
5936
|
+
}
|
|
5937
|
+
}
|
|
5938
|
+
for (const [head, story] of planned.stories) {
|
|
5939
|
+
if (!laid.has(head))
|
|
5940
|
+
continue;
|
|
5941
|
+
for (let i = story.startIdx; i <= story.plan.endIdx; i++)
|
|
5942
|
+
composedLaid.add(i);
|
|
5943
|
+
}
|
|
5944
|
+
pendingComposedBreak = 'page';
|
|
5945
|
+
flushPendingNumberingAtBoundary();
|
|
5946
|
+
};
|
|
6058
5947
|
/** The first block of the document that sets something: a heading there
|
|
6059
5948
|
* opens the document's first page (`openerPages`, #749). */
|
|
6060
5949
|
const firstFlowBlockIdx = contentBlocks.findIndex((b) => !isMarkerBlock(b) && b.type !== 'directive');
|
|
@@ -6063,6 +5952,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6063
5952
|
throw new BuildCancelledError();
|
|
6064
5953
|
options?.onProgress?.({ pass: 1, blocks: blockIdx, totalBlocks: contentBlocks.length, pages: doc.pages.length });
|
|
6065
5954
|
const rawBlock = contentBlocks[blockIdx];
|
|
5955
|
+
// Blocks a composed page set in its frames (#855) are done.
|
|
5956
|
+
if (composedLaid.has(blockIdx))
|
|
5957
|
+
continue;
|
|
6066
5958
|
// The styled section this block sits in: its geometry applies to the
|
|
6067
5959
|
// pages opened from here (a heading with `breakBefore` opens one).
|
|
6068
5960
|
const blockSection = sectionPlan.byBlock[blockIdx];
|
|
@@ -6279,26 +6171,39 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6279
6171
|
pendingPaperBreak = false;
|
|
6280
6172
|
breakForPaper(blockIdx);
|
|
6281
6173
|
}
|
|
6282
|
-
// A composed page (`::::page{template=…}`, #
|
|
6283
|
-
//
|
|
6284
|
-
//
|
|
6285
|
-
//
|
|
6286
|
-
//
|
|
6287
|
-
//
|
|
6288
|
-
if (
|
|
6289
|
-
|
|
6290
|
-
|
|
6174
|
+
// A composed page (`::::page{template=…}`, #855): it owns a fresh page,
|
|
6175
|
+
// its template's frames filled with its stories (`layoutComposedPage`);
|
|
6176
|
+
// nothing flows on it, and what follows starts on the next page. A
|
|
6177
|
+
// story whose frame this side lacks, and content no frame takes, are
|
|
6178
|
+
// set in the flow there. A page whose template is unknown is set in
|
|
6179
|
+
// the flow on pages of its own (`templateUnknown`).
|
|
6180
|
+
if (rawBlock.type === 'containerStart' && rawBlock.containerName === 'composedPage') {
|
|
6181
|
+
const planned = composedPlans.get(blockIdx);
|
|
6182
|
+
pendingComposedBreak = false;
|
|
6183
|
+
if (planned && rawBlock.composedPage)
|
|
6184
|
+
placeComposedPage(planned, rawBlock.composedPage);
|
|
6185
|
+
else
|
|
6291
6186
|
breakForPaper(blockIdx);
|
|
6292
|
-
}
|
|
6293
|
-
else {
|
|
6294
|
-
pendingComposedBreak = true;
|
|
6295
|
-
}
|
|
6296
6187
|
continue;
|
|
6297
6188
|
}
|
|
6298
|
-
if (
|
|
6189
|
+
if (rawBlock.type === 'containerEnd' && rawBlock.containerName === 'composedPage') {
|
|
6190
|
+
// (Set to `'page'` by `placeComposedPage`, a closure the flow
|
|
6191
|
+
// analysis does not follow.)
|
|
6192
|
+
if (pendingComposedBreak !== 'page')
|
|
6193
|
+
pendingComposedBreak = 'flow';
|
|
6194
|
+
continue;
|
|
6195
|
+
}
|
|
6196
|
+
const composedBreak = pendingComposedBreak;
|
|
6197
|
+
if (composedBreak === 'flow') {
|
|
6299
6198
|
pendingComposedBreak = false;
|
|
6300
6199
|
breakForPaper(blockIdx);
|
|
6301
6200
|
}
|
|
6201
|
+
else if (composedBreak === 'page') {
|
|
6202
|
+
pendingComposedBreak = false;
|
|
6203
|
+
pendingSpacing = 0;
|
|
6204
|
+
leaveCurrentPage();
|
|
6205
|
+
flushPendingNumberingAtBoundary();
|
|
6206
|
+
}
|
|
6302
6207
|
// `:::page`: a comic page owns a fresh page — its panels, split lines
|
|
6303
6208
|
// and lettering laid out on the sheet (`layoutComicPage`); nothing
|
|
6304
6209
|
// flows on it, and what follows starts on the next page.
|
|
@@ -8322,6 +8227,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
8322
8227
|
floatShrinkWarningsByDoc.set(doc, shrunk);
|
|
8323
8228
|
if (textWrapNotes.length > 0 || columnsNotes.length > 0)
|
|
8324
8229
|
textWrapWarningsByDoc.set(doc, [...textWrapNotes, ...columnsNotes]);
|
|
8230
|
+
// Composed pages (#855): frames whose content does not fit.
|
|
8231
|
+
if (composedNotes.length > 0)
|
|
8232
|
+
composedWarningsByDoc.set(doc, composedNotes);
|
|
8325
8233
|
// The composition rules (#749): short lists cut, floats on opener pages.
|
|
8326
8234
|
const ruleNotes = [...shortListWarnings(), ...openerFloatNotes, ...tocGroupWarnings()];
|
|
8327
8235
|
if (ruleNotes.length > 0)
|
|
@@ -8396,7 +8304,7 @@ export function* buildDocumentGen(content, config, cache, options) {
|
|
|
8396
8304
|
// cap; words of a joining script that run past their line, and styles
|
|
8397
8305
|
// whose letter-spacing such words do not take.
|
|
8398
8306
|
// Line numbers set over a float of the side column (#621).
|
|
8399
|
-
const loose = [...cjkLooseLineWarnings(doc), ...raggedLineWarnings(doc), ...wordOverflowWarnings(doc), ...(joiningSpacingWarnings.get(doc) ?? []), ...(dropCapWarningsByDoc.get(doc) ?? []), ...lineNumberWarnings(doc), ...codeOverflowWarnings(doc), ...(floatShrinkWarningsByDoc.get(doc) ?? []), ...(textWrapWarningsByDoc.get(doc) ?? []), ...(compositionWarningsByDoc.get(doc) ?? [])];
|
|
8307
|
+
const loose = [...cjkLooseLineWarnings(doc), ...raggedLineWarnings(doc), ...wordOverflowWarnings(doc), ...(joiningSpacingWarnings.get(doc) ?? []), ...(dropCapWarningsByDoc.get(doc) ?? []), ...lineNumberWarnings(doc), ...codeOverflowWarnings(doc), ...(floatShrinkWarningsByDoc.get(doc) ?? []), ...(textWrapWarningsByDoc.get(doc) ?? []), ...(compositionWarningsByDoc.get(doc) ?? []), ...(composedWarningsByDoc.get(doc) ?? [])];
|
|
8400
8308
|
// Side boxes and side floats set on pages after the text, and what the
|
|
8401
8309
|
// layout could place nowhere (#639).
|
|
8402
8310
|
loose.push(...afterTextWarnings(doc), ...(unplacedByDoc.get(doc) ?? []));
|
|
@@ -8427,6 +8335,8 @@ export function* buildDocumentGen(content, config, cache, options) {
|
|
|
8427
8335
|
const harakat = annotateArabicMarks(doc);
|
|
8428
8336
|
// The rules over `*…*` runs under `bodyText.emphasis: 'overline'`.
|
|
8429
8337
|
overlineEmphasis(doc);
|
|
8338
|
+
// The bands of the highlight marks (`:mark[…]`, #888).
|
|
8339
|
+
highlightDocument(doc);
|
|
8430
8340
|
// Faces the text was set in that the font set could not give (#629).
|
|
8431
8341
|
const fallbacks = fontSet && resolveDebugConfig(config?.debug).warnings.missingFont
|
|
8432
8342
|
? fontFallbacks(documentFontFaces(doc), fontSet).map((f) => ({ kind: 'fontFallback', family: f.family, weight: f.weight, style: f.style, reason: f.reason }))
|
|
@@ -8455,6 +8365,8 @@ const floatShrinkWarningsByDoc = new WeakMap();
|
|
|
8455
8365
|
/** The `textWrap` warnings of a build (#627) and its `columnsTooNarrow`
|
|
8456
8366
|
* ones (#634), found by its last pass. */
|
|
8457
8367
|
const textWrapWarningsByDoc = new WeakMap();
|
|
8368
|
+
/** The composed pages' layout warnings of a pass (`frameOverflow`, #855). */
|
|
8369
|
+
const composedWarningsByDoc = new WeakMap();
|
|
8458
8370
|
/** The `shortListSplit` and `openerFloat` warnings of a build (#749),
|
|
8459
8371
|
* found by its last pass. */
|
|
8460
8372
|
const compositionWarningsByDoc = new WeakMap();
|