postext 1.33.11 → 1.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/__tests__/bundle/designOverflowPin.test.js +1 -1
- package/dist/__tests__/bundle/gridBreakRulesPin.test.js +2 -2
- package/dist/__tests__/bundle/shapingLanguagePin.test.js +3 -3
- package/dist/__tests__/bundle/taskBoxPin.test.js +1 -1
- package/dist/__tests__/bundle.test.js +34 -2
- package/dist/__tests__/bundle.test.js.map +1 -1
- package/dist/__tests__/codeBlocks.test.js +89 -1
- package/dist/__tests__/codeBlocks.test.js.map +1 -1
- package/dist/__tests__/composed/corpus.test.d.ts +2 -0
- package/dist/__tests__/composed/corpus.test.d.ts.map +1 -0
- package/dist/__tests__/composed/corpus.test.js +33 -0
- package/dist/__tests__/composed/corpus.test.js.map +1 -0
- 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 +159 -0
- package/dist/__tests__/composed/fixtures/page8.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/slotChecks.test.d.ts +2 -0
- package/dist/__tests__/composed/slotChecks.test.d.ts.map +1 -0
- package/dist/__tests__/composed/slotChecks.test.js +151 -0
- package/dist/__tests__/composed/slotChecks.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 +191 -0
- package/dist/__tests__/composedPaint.test.js.map +1 -0
- package/dist/__tests__/composedTemplates.test.d.ts +2 -0
- package/dist/__tests__/composedTemplates.test.d.ts.map +1 -0
- package/dist/__tests__/composedTemplates.test.js +349 -0
- package/dist/__tests__/composedTemplates.test.js.map +1 -0
- package/dist/__tests__/contentInConfig.test.d.ts +2 -0
- package/dist/__tests__/contentInConfig.test.d.ts.map +1 -0
- package/dist/__tests__/contentInConfig.test.js +201 -0
- package/dist/__tests__/contentInConfig.test.js.map +1 -0
- package/dist/__tests__/defaults/stripRoundTrip.test.js +6 -3
- package/dist/__tests__/defaults/stripRoundTrip.test.js.map +1 -1
- package/dist/__tests__/exports.test.js +34 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/__tests__/hardBreaks.test.js +1 -1
- package/dist/__tests__/headingInlineMarks.test.js +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__/mathSizeMigration.test.js +2 -2
- package/dist/__tests__/parse/composedPages.test.d.ts +2 -0
- package/dist/__tests__/parse/composedPages.test.d.ts.map +1 -0
- package/dist/__tests__/parse/composedPages.test.js +323 -0
- package/dist/__tests__/parse/composedPages.test.js.map +1 -0
- package/dist/__tests__/parse/containers.test.js +2 -2
- package/dist/__tests__/parse/containers.test.js.map +1 -1
- package/dist/__tests__/pipeline/calloutInlineResourceGap.test.js +1 -1
- package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js +1 -1
- package/dist/__tests__/pipeline/colonListRoom.test.js +1 -1
- package/dist/__tests__/pipeline/compoundBreaks.test.js +1 -1
- package/dist/__tests__/pipeline/dashBreaks.test.js +1 -1
- package/dist/__tests__/pipeline/headingSplitOrphans.test.js +1 -1
- package/dist/__tests__/pipeline/inlineFigureSpace.test.js +1 -1
- package/dist/__tests__/pipeline/paragraphContainerTail.test.js +1 -1
- package/dist/__tests__/pipeline/raggedOptimal.test.js +1 -1
- package/dist/__tests__/tocGroups.test.d.ts +2 -0
- package/dist/__tests__/tocGroups.test.d.ts.map +1 -0
- package/dist/__tests__/tocGroups.test.js +213 -0
- package/dist/__tests__/tocGroups.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/__tests__/verseLines.test.js +1 -1
- 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/configVersion.d.ts +16 -5
- package/dist/bundle/configVersion.d.ts.map +1 -1
- package/dist/bundle/configVersion.js +17 -4
- package/dist/bundle/configVersion.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 +11 -3
- 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 +15 -0
- package/dist/canvas-backend/composed.d.ts.map +1 -0
- package/dist/canvas-backend/composed.js +41 -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/document.d.ts +43 -0
- package/dist/composed/document.d.ts.map +1 -0
- package/dist/composed/document.js +88 -0
- package/dist/composed/document.js.map +1 -0
- 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/paint.d.ts +41 -0
- package/dist/composed/paint.d.ts.map +1 -0
- package/dist/composed/paint.js +83 -0
- package/dist/composed/paint.js.map +1 -0
- package/dist/composed/slotChecks.d.ts +29 -0
- package/dist/composed/slotChecks.d.ts.map +1 -0
- package/dist/composed/slotChecks.js +109 -0
- package/dist/composed/slotChecks.js.map +1 -0
- package/dist/composed/templates.d.ts +133 -0
- package/dist/composed/templates.d.ts.map +1 -0
- package/dist/composed/templates.js +702 -0
- package/dist/composed/templates.js.map +1 -0
- package/dist/composed/types.d.ts +361 -0
- package/dist/composed/types.d.ts.map +1 -0
- package/dist/composed/types.js +2 -0
- package/dist/composed/types.js.map +1 -0
- package/dist/composed/validate.d.ts +26 -0
- package/dist/composed/validate.d.ts.map +1 -0
- package/dist/composed/validate.js +276 -0
- package/dist/composed/validate.js.map +1 -0
- 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.d.ts +19 -3
- package/dist/configWarnings.d.ts.map +1 -1
- package/dist/configWarnings.js +171 -41
- package/dist/configWarnings.js.map +1 -1
- package/dist/defaults/checks.d.ts +7 -0
- package/dist/defaults/checks.d.ts.map +1 -0
- package/dist/defaults/checks.js +49 -0
- package/dist/defaults/checks.js.map +1 -0
- 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/index.d.ts +2 -0
- package/dist/defaults/index.d.ts.map +1 -1
- package/dist/defaults/index.js +35 -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/defaults/toc.d.ts +17 -2
- package/dist/defaults/toc.d.ts.map +1 -1
- package/dist/defaults/toc.js +53 -1
- package/dist/defaults/toc.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 +10 -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/design/slots.d.ts +29 -0
- package/dist/design/slots.d.ts.map +1 -0
- package/dist/design/slots.js +48 -0
- package/dist/design/slots.js.map +1 -0
- 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 +65 -8
- 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 +21 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- 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/blockParser.d.ts.map +1 -1
- package/dist/parse/blockParser.js +295 -36
- package/dist/parse/blockParser.js.map +1 -1
- package/dist/parse/index.d.ts +1 -1
- package/dist/parse/index.d.ts.map +1 -1
- package/dist/parse/index.js.map +1 -1
- package/dist/parse/indexMarks.d.ts.map +1 -1
- package/dist/parse/indexMarks.js +24 -0
- package/dist/parse/indexMarks.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 +119 -2
- package/dist/parse/types.d.ts.map +1 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +318 -287
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/calloutLayout.d.ts +33 -0
- package/dist/pipeline/calloutLayout.d.ts.map +1 -1
- package/dist/pipeline/calloutLayout.js +91 -2
- 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 +88 -0
- package/dist/pipeline/composedLayout.d.ts.map +1 -0
- package/dist/pipeline/composedLayout.js +320 -0
- package/dist/pipeline/composedLayout.js.map +1 -0
- package/dist/pipeline/config.d.ts.map +1 -1
- package/dist/pipeline/config.js +18 -2
- package/dist/pipeline/config.js.map +1 -1
- package/dist/pipeline/contentWarnings.d.ts.map +1 -1
- package/dist/pipeline/contentWarnings.js +105 -1
- 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 +48 -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/placeholders.d.ts +7 -0
- package/dist/pipeline/placeholders.d.ts.map +1 -1
- package/dist/pipeline/placeholders.js +41 -0
- package/dist/pipeline/placeholders.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/pipeline/textWrap.js +1 -1
- package/dist/pipeline/textWrap.js.map +1 -1
- package/dist/pipeline/toc.d.ts +11 -1
- package/dist/pipeline/toc.d.ts.map +1 -1
- package/dist/pipeline/toc.js +147 -8
- package/dist/pipeline/toc.js.map +1 -1
- package/dist/types.d.ts +168 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/util/closestKey.d.ts +4 -0
- package/dist/util/closestKey.d.ts.map +1 -0
- package/dist/util/closestKey.js +40 -0
- package/dist/util/closestKey.js.map +1 -0
- package/dist/vdt.d.ts +293 -7
- 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
|
@@ -34,6 +34,9 @@ import { anchorTargetsOf, hasAnchorRefs, printsAnchorPages } from './crossRefs';
|
|
|
34
34
|
import { applyStatementNumbering, numberStatements, outlineLookup } from './statementNumbering';
|
|
35
35
|
import { SPAN_EMBED_STYLE_ID, isPageSpanStrip, spanEmbedStyle, wrapPageSpanEmbeds } from './spanEmbeds';
|
|
36
36
|
import { flowColumnsStyles, isFlowColumnsStyle, wrapFlowColumns } from './flowColumns';
|
|
37
|
+
import { FRAME_STYLE_ID, frameBoxStyle, wrapComposedPages } from '../composed/wrap';
|
|
38
|
+
import { resolvePageTemplate } from '../composed/templates';
|
|
39
|
+
import { composedPageAt, frameStyleOf, layoutComposedPage, planComposedPages } from './composedLayout';
|
|
37
40
|
import { anchorOutline, computeOutline, hasIndexDirective, hasTocDirective, headingNumberingOptions, headingTemplatesOf, outlineFromDoc, sameOutline } from './outline';
|
|
38
41
|
import { expandTocDirectives } from './toc';
|
|
39
42
|
import { expandIndexDirectives, locateIndexMarks } from './indexDirective';
|
|
@@ -49,8 +52,8 @@ import { measureContentBlock } from './measureContentBlock';
|
|
|
49
52
|
import { containerStyle, paragraphStyleIdOf, planParagraphContainers } from './paragraphContainers';
|
|
50
53
|
import { appendChapterEndNotes, footnoteIdsOfLines, footnoteParagraphStyle, noteContentBlock, noteNumberPositionOf, numberFootnotes, footnoteFormatOf, numberFootnotesByPlacement, sameFootnoteNumbers, splitFootnoteDefinitions, withFootnoteStyle, } from './footnotes';
|
|
51
54
|
import { planParts, derivePartMeasureContext } from './parts';
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
55
|
+
import { offsetBlock, offsetCalloutToAbsolute, pickCalloutStyle, planCallouts, resolveCalloutAttrs, } from './calloutLayout';
|
|
56
|
+
import { CUT_START, fragmentRange, makeCalloutLayouter as makeCalloutLayouterIn, splitCalloutFragment as splitCalloutFragmentIn, tallerThanColumn as tallerThanColumnIn, } from './frameLayout';
|
|
54
57
|
import { chooseTableSlice, layoutCaptionText, layoutResourceBlock, MIN_TAIL_ROWS } from './resourceLayout';
|
|
55
58
|
import { computeFloatPlan, floatedResourceIds, floatColumnCount, resolveResourcePlacement, } from './floatPlacement';
|
|
56
59
|
import { enumerateCurrentPageSlots, measureFloatBand, floatGapAbove, floatGapBelow, measureSideStack, clearSideObstacles, columnHasFloatBand, fitsStrict, trueBottom, } from './floatSlots';
|
|
@@ -77,6 +80,7 @@ import { annotateArabicMarks } from '../arabicMarks';
|
|
|
77
80
|
import { literalBreaksFor } from './hardBreaks';
|
|
78
81
|
import { tashkilFor } from './tashkil';
|
|
79
82
|
import { overlineEmphasis } from '../emphasisOverline';
|
|
83
|
+
import { highlightDocument } from '../highlightMarks';
|
|
80
84
|
import { withBookTitleBrackets } from './annotations';
|
|
81
85
|
import { paperByBlock, stampPagePaper } from './paper';
|
|
82
86
|
import { headingLineSpanBand } from './lineSpan';
|
|
@@ -479,7 +483,13 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
479
483
|
// set by the span-block path like any other.
|
|
480
484
|
// A `:::columns` group in the running text (#634): each in a frameless
|
|
481
485
|
// box the callout machinery places, cuts and splits.
|
|
482
|
-
|
|
486
|
+
// Composed pages (#855): each page's content regrouped into the stories
|
|
487
|
+
// its template's frames receive, one frameless box each (set at the
|
|
488
|
+
// page's template, below). Before the main-flow groups: a `:::columns`
|
|
489
|
+
// in a frame is a group of its box.
|
|
490
|
+
const templateSource = { pageTemplates: resolved.pageTemplates, calloutStyles: resolved.calloutStyles };
|
|
491
|
+
const composedWrap = wrapComposedPages(numberedBlocks, templateSource);
|
|
492
|
+
const flowGroups = resolved.layout.flowColumns ? wrapFlowColumns(composedWrap.blocks) : { blocks: composedWrap.blocks, wrapped: false };
|
|
483
493
|
const spanEmbeds = wrapPageSpanEmbeds(flowGroups.blocks, content.resources ?? [], effectiveResourceTypes(config, content.resources ?? []));
|
|
484
494
|
// Code listings (#624): each in a box of the code style, which the
|
|
485
495
|
// callout machinery places and splits.
|
|
@@ -525,6 +535,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
525
535
|
const syntheticBoxes = [
|
|
526
536
|
...(spanEmbeds.wrapped ? [spanEmbedStyle(bodyStyle.lineHeightPx, resolved.layout.inlineResourceGap !== 'above')] : []),
|
|
527
537
|
...(codeBoxes.wrapped ? [codeBoxStyle(resolved)] : []),
|
|
538
|
+
// The frameless box of a composed page's story (#855).
|
|
539
|
+
...(composedWrap.wrapped ? [frameBoxStyle(Math.max(resolved.bodyText.avoidOrphans ? resolved.bodyText.orphanMinLines : 1, resolved.bodyText.avoidWidows ? resolved.bodyText.widowMinLines : 1))] : []),
|
|
528
540
|
// The boxes of main-flow groups: sub-columns a body line apart in the
|
|
529
541
|
// text column, a gutter apart across the page.
|
|
530
542
|
...(flowGroups.wrapped
|
|
@@ -536,7 +548,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
536
548
|
: resolved.calloutStyles;
|
|
537
549
|
// A box nested in another looks its style up in the configuration it is
|
|
538
550
|
// laid out with: the listings' box among them.
|
|
539
|
-
const calloutResolved = codeBoxes.wrapped || flowGroups.wrapped ? { ...resolved, calloutStyles } : resolved;
|
|
551
|
+
const calloutResolved = codeBoxes.wrapped || flowGroups.wrapped || composedWrap.wrapped ? { ...resolved, calloutStyles } : resolved;
|
|
540
552
|
const blockquoteStyle = resolveBlockquoteStyle(resolved);
|
|
541
553
|
const listLevelIndentsPx = computeLevelIndentsPx(resolved, bodyStyle.fontSizePx);
|
|
542
554
|
const orderedMetrics = computeOrderedListRunMetrics(contentBlocks, resolved, bodyStyle.fontSizePx);
|
|
@@ -568,6 +580,23 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
568
580
|
// mode of the styled section the reference sits in (a horizontal
|
|
569
581
|
// appendix of a vertical book turns its figures as asked).
|
|
570
582
|
const floatPlan = computeFloatPlan(contentBlocks, resources, resourceTypes, incorporated, (blockIdx) => sectionWritingMode(sectionPlan, resolved, blockIdx) === 'vertical-rl', resolved.layout.floatShrink, resolved.layout.wrap, resolved.layout.floatsAtCitingPage);
|
|
583
|
+
// A composed page's pictures are set in its frames: a `::resource` a
|
|
584
|
+
// story holds does not float. A reference in a frame to a picture set
|
|
585
|
+
// elsewhere floats from the page's end, to the pages after it.
|
|
586
|
+
const composedPlans = planComposedPages(contentBlocks, calloutPlan, templateSource);
|
|
587
|
+
if (composedPlans.size > 0) {
|
|
588
|
+
for (let k = floatPlan.length - 1; k >= 0; k--) {
|
|
589
|
+
const f = floatPlan[k];
|
|
590
|
+
const page = composedPageAt(composedPlans, f.firstBlockIdx);
|
|
591
|
+
if (!page)
|
|
592
|
+
continue;
|
|
593
|
+
const raw = contentBlocks[f.firstBlockIdx];
|
|
594
|
+
if (raw?.type === 'resourceBlock' && raw.resourceId === f.resourceId && page.storyAt(f.firstBlockIdx))
|
|
595
|
+
floatPlan.splice(k, 1);
|
|
596
|
+
else
|
|
597
|
+
f.firstBlockIdx = page.endIdx;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
571
600
|
const floatedIds = floatedResourceIds(floatPlan, incorporated, resources, resourceTypes);
|
|
572
601
|
const floatsByFirstBlock = new Map();
|
|
573
602
|
for (const f of floatPlan) {
|
|
@@ -2986,7 +3015,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
2986
3015
|
// A page still empty takes the geometry right away — the document (or
|
|
2987
3016
|
// a chapter laid out on its own) opening with a styled heading.
|
|
2988
3017
|
const page = doc.pages[cursor.pageIndex];
|
|
2989
|
-
if (page && !page.partInfo && !page.comic && cursor.columnIndex === 0
|
|
3018
|
+
if (page && !page.partInfo && !page.comic && !page.composed && cursor.columnIndex === 0
|
|
2990
3019
|
&& !pageHasContent(page) && !(page.floats && page.floats.length > 0)) {
|
|
2991
3020
|
const fresh = createPageWithColumns(page.index, geomResolved, contentArea, pageWidthPx, pageHeightPx, pageIndexOffset);
|
|
2992
3021
|
if (page.blankForParity)
|
|
@@ -3033,11 +3062,13 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3033
3062
|
// one in an Arabic book. Its lines carry their span (`VDTLine.measure`).
|
|
3034
3063
|
if (blk.type !== 'resource' && raw.direction !== undefined && raw.direction !== resolvedDirection(resolved))
|
|
3035
3064
|
blk.direction = raw.direction;
|
|
3065
|
+
const tocContinued = raw.toc?.group?.role === 'continuation' ? { continued: true } : {};
|
|
3036
3066
|
if (raw.toc?.kind === 'entry') {
|
|
3037
|
-
blk.tocEntry = raw.toc.pageIndex !== undefined ? { pageIndex: raw.toc.pageIndex } : {};
|
|
3067
|
+
blk.tocEntry = { ...(raw.toc.pageIndex !== undefined ? { pageIndex: raw.toc.pageIndex } : {}), ...tocContinued };
|
|
3038
3068
|
}
|
|
3039
3069
|
if (raw.toc?.kind === 'part') {
|
|
3040
3070
|
blk.tocPart = {
|
|
3071
|
+
...tocContinued,
|
|
3041
3072
|
number: raw.toc.number,
|
|
3042
3073
|
title: raw.toc.title ?? '',
|
|
3043
3074
|
pageLabel: raw.toc.pageLabel ?? '',
|
|
@@ -3366,7 +3397,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3366
3397
|
*/
|
|
3367
3398
|
const openSpanHeadingHere = (blockIdx, rawBlock, level) => {
|
|
3368
3399
|
const page = doc.pages[cursor.pageIndex];
|
|
3369
|
-
if (page.partInfo || page.comic || currentColumn(doc, cursor).kind === 'span')
|
|
3400
|
+
if (page.partInfo || page.comic || page.composed || currentColumn(doc, cursor).kind === 'span')
|
|
3370
3401
|
return false;
|
|
3371
3402
|
const band = currentBand(page, cursor);
|
|
3372
3403
|
const cols = bandColumns(page, band);
|
|
@@ -3500,7 +3531,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3500
3531
|
if (!balancingCfg.enabled || !balancingCfg.trailing)
|
|
3501
3532
|
return;
|
|
3502
3533
|
const page = doc.pages[cursor.pageIndex];
|
|
3503
|
-
if (page.columns[cursor.columnIndex]?.kind === 'span' || page.partInfo || page.comic)
|
|
3534
|
+
if (page.columns[cursor.columnIndex]?.kind === 'span' || page.partInfo || page.comic || page.composed)
|
|
3504
3535
|
return;
|
|
3505
3536
|
const band = currentBand(page, cursor);
|
|
3506
3537
|
const cols = bandColumns(page, band).filter((c) => c.bbox.height > 0.5);
|
|
@@ -3706,6 +3737,12 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3706
3737
|
/** A closed `:::paper` still owes a page break before the next placed
|
|
3707
3738
|
* block. */
|
|
3708
3739
|
let pendingPaperBreak = false;
|
|
3740
|
+
/** A composed page (`::::page`, #854) owes a page break before the next
|
|
3741
|
+
* placed block: `'page'` once its template was laid on the current page
|
|
3742
|
+
* (nothing flowed on it), `'flow'` after content set in the flow (a page
|
|
3743
|
+
* of unknown template, or what no frame took), which closes as a
|
|
3744
|
+
* `:::paper` run does. */
|
|
3745
|
+
let pendingComposedBreak = false;
|
|
3709
3746
|
/** A comic page (`:::page`) was laid out on the current page: the next
|
|
3710
3747
|
* placed block opens a new one (a page that ends the document leaves no
|
|
3711
3748
|
* empty page behind). */
|
|
@@ -3735,7 +3772,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3735
3772
|
let pendingNumberingPage = 0;
|
|
3736
3773
|
/** A page holding something the reader sees: column content, a float, a
|
|
3737
3774
|
* part opener. A parity blank is not one. */
|
|
3738
|
-
const pageTakesNumbering = (page) => pageHasContent(page) || (page.floats?.length ?? 0) > 0 || page.partInfo !== undefined || page.comic !== undefined;
|
|
3775
|
+
const pageTakesNumbering = (page) => pageHasContent(page) || (page.floats?.length ?? 0) > 0 || page.partInfo !== undefined || page.comic !== undefined || page.composed !== undefined;
|
|
3739
3776
|
/** Commits a pending `:::numbering` change to the first page from the
|
|
3740
3777
|
* directive on that receives content: the page the directive opens (the
|
|
3741
3778
|
* head of a chapter, right after a page break) or, when that page was
|
|
@@ -3900,16 +3937,14 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3900
3937
|
doc.blocks.push(child);
|
|
3901
3938
|
}
|
|
3902
3939
|
};
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
};
|
|
3912
|
-
const CUT_START = { child: 0, line: 0 };
|
|
3940
|
+
// --- Callout fragments (`keepTogether: false`) ---------------------------
|
|
3941
|
+
// A splittable box breaks only BETWEEN its child blocks (a list item or a
|
|
3942
|
+
// paragraph is never cut in two): the fragment that fits closes the
|
|
3943
|
+
// current column / page, the rest continues in a box of its own — same
|
|
3944
|
+
// frame, stripe and marker, no title or icon — on the next one, and may
|
|
3945
|
+
// split again. Every
|
|
3946
|
+
// fragment's frame shares the fence's `contentIndex` / `containerId` and
|
|
3947
|
+
// records its `callout.part` / `callout.continued`.
|
|
3913
3948
|
/** A strip in a box (the box of a page-wide strip set `here`, #590):
|
|
3914
3949
|
* laid out at the box's inner width, as tall as a page allows, with its
|
|
3915
3950
|
* placeholder line; the page it lays out for is the cursor's. */
|
|
@@ -3920,85 +3955,21 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3920
3955
|
withStripPlaceholder(blk, stripGeometry(idx, raw.comic, width, contentArea.height - 2 * floatGapPx, pageIsVertical(doc.pages[cursor.pageIndex])));
|
|
3921
3956
|
return blk;
|
|
3922
3957
|
};
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
//
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
groups.push([k, e]);
|
|
3939
|
-
}
|
|
3940
|
-
});
|
|
3941
|
-
const layoutRange = (from, to, width, frameId, continuation, mirrored = false) => {
|
|
3942
|
-
let n = 0;
|
|
3943
|
-
// A fragment that opens inside a `:::columns` group starts at its
|
|
3944
|
-
// opening marker and one that ends inside it at its closing marker:
|
|
3945
|
-
// the group sets the part between the cut's positions (#634).
|
|
3946
|
-
const fromChild = from.group ? from.group.open : from.child;
|
|
3947
|
-
const closeOfGroup = (open) => groups.find(([gs]) => gs === open)?.[1] ?? children.length - 1;
|
|
3948
|
-
// A cut inside child `to.child` includes that child (its first
|
|
3949
|
-
// `to.line` lines); a cut at a child's head excludes it.
|
|
3950
|
-
const toChild = to.group ? closeOfGroup(to.group.open) + 1 : to.line > 0 ? to.child + 1 : to.child;
|
|
3951
|
-
const inSlice = (pos) => pos.map((p) => ({ ...p, child: p.child - fromChild }));
|
|
3952
|
-
// Nested boxes still open at `from` (their closing markers leading
|
|
3953
|
-
// the range close them): the fragment opens inside them.
|
|
3954
|
-
const open = [];
|
|
3955
|
-
for (let k = 0; k < fromChild; k++) {
|
|
3956
|
-
const c = children[k];
|
|
3957
|
-
if (c.containerName !== 'callout')
|
|
3958
|
-
continue;
|
|
3959
|
-
if (c.type === 'containerStart')
|
|
3960
|
-
open.push({ idx: startIdx + 1 + k, block: c });
|
|
3961
|
-
else if (c.type === 'containerEnd')
|
|
3962
|
-
open.pop();
|
|
3963
|
-
}
|
|
3964
|
-
for (let k = fromChild; k < children.length && open.length > 0; k++) {
|
|
3965
|
-
const c = children[k];
|
|
3966
|
-
if (c.type !== 'containerEnd' || c.containerId !== open[open.length - 1].block.containerId)
|
|
3967
|
-
break;
|
|
3968
|
-
open.pop();
|
|
3969
|
-
}
|
|
3970
|
-
return layoutCallout({
|
|
3971
|
-
style,
|
|
3972
|
-
attrs: plan.attrs,
|
|
3973
|
-
...(contentBlocks[startIdx]?.direction ? { direction: contentBlocks[startIdx].direction } : {}),
|
|
3974
|
-
continuation,
|
|
3975
|
-
// Any range short of the box's end is a fragment that goes on.
|
|
3976
|
-
...(to.child < children.length || to.line > 0 || to.group ? { continues: true } : {}),
|
|
3977
|
-
children: children.slice(fromChild, toChild),
|
|
3978
|
-
childStartIdx: startIdx + 1 + fromChild,
|
|
3979
|
-
width,
|
|
3980
|
-
// A main-flow group's box sets its blocks as the text around it is
|
|
3981
|
-
// set: a styled section's or a part's body (#634).
|
|
3982
|
-
ctx: isFlowColumnsStyle(style.id)
|
|
3983
|
-
? (partPlan.byBlock[startIdx] ? partMeasureCtx : sectionMeasureCtx(sectionPlan.byBlock[startIdx]))
|
|
3984
|
-
: measureCtx,
|
|
3985
|
-
resolved: calloutResolved,
|
|
3986
|
-
containerId: plan.containerId,
|
|
3987
|
-
frameId,
|
|
3988
|
-
nextChildId: () => `${frameId}-c${n++}`,
|
|
3989
|
-
paragraphContainers,
|
|
3990
|
-
...(from.line > 0 && !from.group ? { lineFrom: from.line } : {}),
|
|
3991
|
-
...(from.line > 0 && !from.group && from.widths ? { lineWidths: from.widths } : {}),
|
|
3992
|
-
...(to.line > 0 && !to.group ? { lineTo: to.line } : {}),
|
|
3993
|
-
...(from.group ? { groupFrom: inSlice(from.group.pos) } : {}),
|
|
3994
|
-
...(to.group ? { groupTo: inSlice(to.group.pos) } : {}),
|
|
3995
|
-
...(open.length > 0 ? { openNested: open } : {}),
|
|
3996
|
-
mirrored,
|
|
3997
|
-
stripBlock: calloutStripBlock,
|
|
3998
|
-
});
|
|
3999
|
-
};
|
|
4000
|
-
return { children, childBase: startIdx + 1, realAt, end: { child: children.length, line: 0 }, layoutRange, groups };
|
|
4001
|
-
};
|
|
3958
|
+
/** What the box typesetter (`frameLayout.ts`) reads of this pass. */
|
|
3959
|
+
const framePass = {
|
|
3960
|
+
contentBlocks,
|
|
3961
|
+
resolved,
|
|
3962
|
+
calloutResolved,
|
|
3963
|
+
paragraphContainers,
|
|
3964
|
+
// A main-flow group's box sets its blocks as the text around it is
|
|
3965
|
+
// set: a styled section's or a part's body (#634).
|
|
3966
|
+
measureCtxFor: (startIdx, style) => (isFlowColumnsStyle(style.id) || style.id === FRAME_STYLE_ID
|
|
3967
|
+
? (partPlan.byBlock[startIdx] ? partMeasureCtx : sectionMeasureCtx(sectionPlan.byBlock[startIdx]))
|
|
3968
|
+
: measureCtx),
|
|
3969
|
+
stripBlock: calloutStripBlock,
|
|
3970
|
+
columnHeight: () => contentArea.height,
|
|
3971
|
+
};
|
|
3972
|
+
const makeCalloutLayouter = (startIdx, plan, style) => makeCalloutLayouterIn(framePass, startIdx, plan, style);
|
|
4002
3973
|
/** Whether a page swaps its mirrored margins (a verso of a left-bound
|
|
4003
3974
|
* book, a recto of a right-bound one: an `'outer'` corner icon hangs on
|
|
4004
3975
|
* the left there). A vertical page has no outer side: a box's outer
|
|
@@ -4024,192 +3995,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4024
3995
|
const withSide = side && sideUsedBottom(side) > side.bbox.y + 0.5 ? [...cols, side] : cols;
|
|
4025
3996
|
return bandUsedBottom(withSide);
|
|
4026
3997
|
};
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
* lines of a text child. `splitMinLines` guards text: a cut between
|
|
4030
|
-
* children leaves on each side at least that many text lines or at least
|
|
4031
|
-
* one indivisible block (a figure, table, display formula or nested
|
|
4032
|
-
* box); a cut inside a text child counts every line on its side, a block
|
|
4033
|
-
* as one line, and leaves at least `layout.boxChildSplitMinLines` lines
|
|
4034
|
-
* of that child on each side (two by default, `splitMinLines` when that
|
|
4035
|
-
* is lower; EF-115). A nested box that may split
|
|
4036
|
-
* itself (`keepTogether: false`, or taller than a full column) offers the cuts
|
|
4037
|
-
* inside it too, by its own `splitMinLines` over its own children; the
|
|
4038
|
-
* fragments on both sides redraw its frame. The full layout's geometry
|
|
4039
|
-
* ranks the candidates (box bottom = content bottom at the cut + the
|
|
4040
|
-
* tails of the boxes closed below it); the deepest candidate that fits
|
|
4041
|
-
* is laid out for real and taken when it truly fits. `null` when none
|
|
4042
|
-
* does. */
|
|
4043
|
-
const splitCalloutFragment = (L, from, width, roomPx, frameId, continuation, minLines, mirrored = false) => {
|
|
4044
|
-
const full = L.layoutRange(from, L.end, width, frameId, continuation, mirrored);
|
|
4045
|
-
/** Figures, tables and display formulas: never cut, not text lines. */
|
|
4046
|
-
const indivisible = (c) => c.type === 'resource' || c.type === 'mathDisplay';
|
|
4047
|
-
const unitBottom = (u) => {
|
|
4048
|
-
const b = u.kind === 'block' ? u.block.bbox : u.box.result.frame.bbox;
|
|
4049
|
-
return b.y + b.height;
|
|
4050
|
-
};
|
|
4051
|
-
/** Room a box keeps under its last item (padding, border, icon growth). */
|
|
4052
|
-
const tailOf = (r) => {
|
|
4053
|
-
const last = r.units[r.units.length - 1];
|
|
4054
|
-
return last ? r.frame.bbox.y + r.totalHeight - unitBottom(last) : 0;
|
|
4055
|
-
};
|
|
4056
|
-
if (full.units.length === 0)
|
|
4057
|
-
return null;
|
|
4058
|
-
// A head that goes on also carries the style's continuation marker.
|
|
4059
|
-
const tail = tailOf(full) + full.continuesMarkerPx;
|
|
4060
|
-
/** Candidate cuts with the head's content bottom. A `soft` cut parts a
|
|
4061
|
-
* wrapped code line from its continuation (#624): taken only when no
|
|
4062
|
-
* other cut fits. */
|
|
4063
|
-
const candidates = [];
|
|
4064
|
-
/** Collect the cuts among `units` (one box's items; `below` = the tails
|
|
4065
|
-
* of the nested boxes around them), each side of a cut holding enough
|
|
4066
|
-
* by the box's `min` lines: a block counts as one line, a nested box
|
|
4067
|
-
* as one indivisible block. */
|
|
4068
|
-
const collect = (units, minLines, below) => {
|
|
4069
|
-
const min = Math.max(1, minLines);
|
|
4070
|
-
const lineCount = (u) => (u.kind === 'block' ? Math.max(1, u.block.lines.length) : 1);
|
|
4071
|
-
const isBlock = (u) => u.kind === 'box' || indivisible(u.block);
|
|
4072
|
-
const totalLines = units.reduce((n, u) => n + lineCount(u), 0);
|
|
4073
|
-
const totalBlocks = units.filter(isBlock).length;
|
|
4074
|
-
/** A side of a cut holds enough: `lines` (blocks included) of which
|
|
4075
|
-
* `blocks` are indivisible. Between children, one block suffices or
|
|
4076
|
-
* the text lines alone meet the minimum; inside a text child, the
|
|
4077
|
-
* lines do. */
|
|
4078
|
-
const holds = (lines, blocks, betweenChildren) => betweenChildren ? blocks > 0 || lines - blocks >= min : lines >= min;
|
|
4079
|
-
const bothHold = (lines, blocks, betweenChildren) => holds(lines, blocks, betweenChildren) && holds(totalLines - lines, totalBlocks - blocks, betweenChildren);
|
|
4080
|
-
let linesBefore = 0;
|
|
4081
|
-
let blocksBefore = 0;
|
|
4082
|
-
units.forEach((u, i) => {
|
|
4083
|
-
let next;
|
|
4084
|
-
if (u.kind === 'block') {
|
|
4085
|
-
const c = u.block;
|
|
4086
|
-
const k = (c.contentIndex ?? L.childBase) - L.childBase;
|
|
4087
|
-
next = k + 1;
|
|
4088
|
-
if (!indivisible(c) && c.lines.length > 1) {
|
|
4089
|
-
// The first laid-out child of a continuation opens after
|
|
4090
|
-
// `from.line` lines: cuts inside it are counted from the
|
|
4091
|
-
// child's own head. Each side of the box still counts all its
|
|
4092
|
-
// lines against `min`, and a cut inside a child leaves at least
|
|
4093
|
-
// `layout.boxChildSplitMinLines` lines of it on each side (2 by
|
|
4094
|
-
// default, so no lone line: EF-115), or `min` when that is
|
|
4095
|
-
// lower. The count is of this fragment's part of the child,
|
|
4096
|
-
// since a part left behind already passed the test.
|
|
4097
|
-
const childMin = Math.min(min, resolved.layout.boxChildSplitMinLines);
|
|
4098
|
-
const lineBase = k === from.child ? from.line : 0;
|
|
4099
|
-
for (let l = childMin; l <= c.lines.length - childMin; l++) {
|
|
4100
|
-
const line = c.lines[l - 1];
|
|
4101
|
-
if (bothHold(linesBefore + l, blocksBefore, false)) {
|
|
4102
|
-
candidates.push({
|
|
4103
|
-
cut: { child: k, line: lineBase + l, widths: k === from.child ? cutWidths(from, width) : [{ fromLine: 0, width }] },
|
|
4104
|
-
bottom: line.bbox.y + line.bbox.height + below,
|
|
4105
|
-
...(c.lines[l]?.codeLine?.continued ? { soft: true } : {}),
|
|
4106
|
-
});
|
|
4107
|
-
}
|
|
4108
|
-
}
|
|
4109
|
-
}
|
|
4110
|
-
}
|
|
4111
|
-
else {
|
|
4112
|
-
const { box } = u;
|
|
4113
|
-
if (box.endIdx !== undefined)
|
|
4114
|
-
next = box.endIdx + 1 - L.childBase;
|
|
4115
|
-
if (!box.style.keepTogether || tallerThanColumn(box.result)) {
|
|
4116
|
-
collect(box.result.units, box.style.splitMinLines, below + tailOf(box.result));
|
|
4117
|
-
}
|
|
4118
|
-
}
|
|
4119
|
-
linesBefore += lineCount(u);
|
|
4120
|
-
if (isBlock(u))
|
|
4121
|
-
blocksBefore++;
|
|
4122
|
-
if (i < units.length - 1 && next !== undefined && bothHold(linesBefore, blocksBefore, true)) {
|
|
4123
|
-
candidates.push({ cut: { child: next, line: 0 }, bottom: unitBottom(u) + below });
|
|
4124
|
-
}
|
|
4125
|
-
});
|
|
4126
|
-
};
|
|
4127
|
-
collect(full.units, minLines, 0);
|
|
4128
|
-
// Inside a `:::columns` group of the box (#634): the cut the group
|
|
4129
|
-
// offers for the room, where each of its sub-columns (each stream, in
|
|
4130
|
-
// a parallel group) ends when the galley fills them in turn; at least
|
|
4131
|
-
// one stream goes on and one moves on. A group of a nested box is
|
|
4132
|
-
// never cut, nor any group under 1.24's rules (`layout.flowColumns`).
|
|
4133
|
-
if (resolved.layout.flowColumns) {
|
|
4134
|
-
const base = from.group ? from.group.open : from.child;
|
|
4135
|
-
const childMin = Math.min(Math.max(1, minLines), resolved.layout.boxChildSplitMinLines);
|
|
4136
|
-
for (const g of full.groups ?? []) {
|
|
4137
|
-
const h = roomPx - tail - g.top;
|
|
4138
|
-
if (h <= 0.5)
|
|
4139
|
-
continue;
|
|
4140
|
-
const reopened = from.group?.open === g.open + base ? from.group : undefined;
|
|
4141
|
-
const pos = [];
|
|
4142
|
-
let moved = false;
|
|
4143
|
-
let left = false;
|
|
4144
|
-
let used = 0;
|
|
4145
|
-
g.streams.forEach((items, s) => {
|
|
4146
|
-
const end = { child: (g.ends[s] ?? g.close) + base, line: 0 };
|
|
4147
|
-
if (items.length === 0) {
|
|
4148
|
-
pos.push(end);
|
|
4149
|
-
return;
|
|
4150
|
-
}
|
|
4151
|
-
const breaks = galleyBreaks(items, childMin);
|
|
4152
|
-
const fill = fillGalley(items, breaks, g.flow === 'snake' ? g.columns : 1, h);
|
|
4153
|
-
if (fill.end) {
|
|
4154
|
-
moved = true;
|
|
4155
|
-
used = Math.max(used, fill.used);
|
|
4156
|
-
pos.push(end);
|
|
4157
|
-
return;
|
|
4158
|
-
}
|
|
4159
|
-
left = true;
|
|
4160
|
-
if (fill.cuts.length === 0) {
|
|
4161
|
-
// This stream takes nothing in the fragment: it stays where it is.
|
|
4162
|
-
pos.push(reopened?.pos[s] ?? { child: items[0].child + base, line: 0 });
|
|
4163
|
-
return;
|
|
4164
|
-
}
|
|
4165
|
-
moved = true;
|
|
4166
|
-
used = Math.max(used, fill.used);
|
|
4167
|
-
const b = breaks[fill.cuts[fill.cuts.length - 1]];
|
|
4168
|
-
const it = items[b.item];
|
|
4169
|
-
if (b.line === 0) {
|
|
4170
|
-
pos.push({ child: it.child + base, line: 0 });
|
|
4171
|
-
return;
|
|
4172
|
-
}
|
|
4173
|
-
// The sub-column widths the paragraph's lines are set at.
|
|
4174
|
-
const before = it.lineBase > 0 ? reopened?.pos[s]?.widths : undefined;
|
|
4175
|
-
const lastW = before?.[before.length - 1];
|
|
4176
|
-
const widths = !before || before.length === 0
|
|
4177
|
-
? [{ fromLine: 0, width: g.columnWidth }]
|
|
4178
|
-
: Math.abs(lastW.width - g.columnWidth) <= 0.5 ? before : [...before, { fromLine: it.lineBase, width: g.columnWidth }];
|
|
4179
|
-
pos.push({ child: it.child + base, line: it.lineBase + b.line, widths });
|
|
4180
|
-
});
|
|
4181
|
-
if (!moved || !left)
|
|
4182
|
-
continue;
|
|
4183
|
-
candidates.push({
|
|
4184
|
-
cut: { child: Math.min(...pos.map((p) => p.child)), line: 0, group: { open: g.open + base, pos } },
|
|
4185
|
-
bottom: g.top + used,
|
|
4186
|
-
});
|
|
4187
|
-
}
|
|
4188
|
-
}
|
|
4189
|
-
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));
|
|
4190
|
-
const viable = candidates
|
|
4191
|
-
.filter((c) => !insideGroup(c.cut))
|
|
4192
|
-
.sort((a, b) => b.bottom - a.bottom);
|
|
4193
|
-
// A wrapped code line stays with its continuations when a cut
|
|
4194
|
-
// elsewhere fits (#624).
|
|
4195
|
-
viable.sort((a, b) => (a.soft ? 1 : 0) - (b.soft ? 1 : 0));
|
|
4196
|
-
for (const c of viable) {
|
|
4197
|
-
if (c.bottom + tail > roomPx + 0.01)
|
|
4198
|
-
continue;
|
|
4199
|
-
const result = L.layoutRange(from, c.cut, width, frameId, continuation, mirrored);
|
|
4200
|
-
if (result.totalHeight <= roomPx + 0.01)
|
|
4201
|
-
return { to: c.cut, result };
|
|
4202
|
-
}
|
|
4203
|
-
return null;
|
|
4204
|
-
};
|
|
4205
|
-
/** Absolute content indices of the children a fragment from cut `from`
|
|
4206
|
-
* to cut `to` of `L` touches, for the fragment's source range. */
|
|
4207
|
-
const fragmentRange = (L, from, to) => ({ firstChildIdx: L.childBase + from.child, lastChildIdx: L.childBase + (to.line > 0 ? to.child : to.child - 1) });
|
|
4208
|
-
/** The (rest of the) box is taller than an empty, full-height column —
|
|
4209
|
-
* a whole page's content area for a page-span box: no column could
|
|
4210
|
-
* hold it, so even a keep-together box splits (with the rules of a
|
|
4211
|
-
* `keepTogether: false` one) rather than overflow. */
|
|
4212
|
-
const tallerThanColumn = (result) => result.totalHeight > contentArea.height + 0.01;
|
|
3998
|
+
const splitCalloutFragment = (L, from, width, roomPx, frameId, continuation, minLines, mirrored = false) => splitCalloutFragmentIn(framePass, L, from, width, roomPx, frameId, continuation, minLines, mirrored);
|
|
3999
|
+
const tallerThanColumn = (result) => tallerThanColumnIn(framePass, result);
|
|
4213
4000
|
const markFragment = (result, part, continued) => {
|
|
4214
4001
|
if (result.frame.callout) {
|
|
4215
4002
|
result.frame.callout.part = part;
|
|
@@ -5933,6 +5720,174 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5933
5720
|
inlineGapOwed = pendingSpacing > 0 ? { afterIdx: blockIdx, pending: pendingSpacing, exact: owed } : null;
|
|
5934
5721
|
return undefined;
|
|
5935
5722
|
};
|
|
5723
|
+
// --- Blocks of the contents kept together (`toc.groups`, #850) -----------
|
|
5724
|
+
/** The measure context of content block `idx` (a part's, a styled
|
|
5725
|
+
* section's). */
|
|
5726
|
+
const measureCtxOf = (idx) => (partPlan.byBlock[idx] ? partMeasureCtx : sectionMeasureCtx(sectionPlan.byBlock[idx]));
|
|
5727
|
+
/** The rows of the contents block whose lead row is `idx`, in order (its
|
|
5728
|
+
* head's repeats aside). */
|
|
5729
|
+
const tocGroupRows = (idx) => {
|
|
5730
|
+
const id = contentBlocks[idx]?.toc?.group?.id;
|
|
5731
|
+
const rows = [];
|
|
5732
|
+
if (id === undefined)
|
|
5733
|
+
return rows;
|
|
5734
|
+
for (let i = idx; i < contentBlocks.length; i++) {
|
|
5735
|
+
const b = contentBlocks[i];
|
|
5736
|
+
if (isMarkerBlock(b))
|
|
5737
|
+
continue;
|
|
5738
|
+
if (b.toc?.group?.id !== id)
|
|
5739
|
+
break;
|
|
5740
|
+
if (b.toc.group.role !== 'continuation')
|
|
5741
|
+
rows.push(i);
|
|
5742
|
+
}
|
|
5743
|
+
return rows;
|
|
5744
|
+
};
|
|
5745
|
+
/**
|
|
5746
|
+
* The room the contents block led by row `idx` takes in a column `width`
|
|
5747
|
+
* wide, from the top of its first row (the space above it aside): `whole`
|
|
5748
|
+
* for every row, `lead` down to the `minEntries`-th entry under its head
|
|
5749
|
+
* (the least a cut block keeps with its head). The rows are spaced as
|
|
5750
|
+
* the layout spaces them, by the larger of the margins that meet.
|
|
5751
|
+
*/
|
|
5752
|
+
const tocGroupNeed = (idx, width) => {
|
|
5753
|
+
const rows = tocGroupRows(idx);
|
|
5754
|
+
if (rows.length < 2)
|
|
5755
|
+
return undefined;
|
|
5756
|
+
const min = contentBlocks[idx].toc.group.minEntries;
|
|
5757
|
+
let height = 0;
|
|
5758
|
+
let lead = 0;
|
|
5759
|
+
let prevBottom;
|
|
5760
|
+
let afterHead = -1;
|
|
5761
|
+
for (const i of rows) {
|
|
5762
|
+
const raw = contentBlocks[i];
|
|
5763
|
+
const m = measureContentBlock(raw, i, width, measureCtxOf(i));
|
|
5764
|
+
if (!m)
|
|
5765
|
+
return undefined;
|
|
5766
|
+
const style = m.kind.style;
|
|
5767
|
+
if (prevBottom !== undefined)
|
|
5768
|
+
height += Math.max(prevBottom, style.marginTopPx);
|
|
5769
|
+
height += m.measured.lines.length * style.lineHeightPx;
|
|
5770
|
+
prevBottom = style.marginBottomPx;
|
|
5771
|
+
if (raw.toc.group.role === 'head')
|
|
5772
|
+
afterHead = 0;
|
|
5773
|
+
else if (afterHead >= 0 && raw.toc.kind === 'entry')
|
|
5774
|
+
afterHead++;
|
|
5775
|
+
if (afterHead >= 0 && afterHead <= min)
|
|
5776
|
+
lead = height;
|
|
5777
|
+
}
|
|
5778
|
+
return { whole: height, lead };
|
|
5779
|
+
};
|
|
5780
|
+
/**
|
|
5781
|
+
* Whether the repeat of a contents block's head row at `idx` is set: the
|
|
5782
|
+
* entry after it goes on in a fresh column, which the repeat opens. When
|
|
5783
|
+
* the entry does not fit in the room the cursor's column has left (an
|
|
5784
|
+
* entry is not cut between columns once its block is), the cursor moves
|
|
5785
|
+
* on to the next column first.
|
|
5786
|
+
*/
|
|
5787
|
+
const tocContinuationOpens = (idx) => {
|
|
5788
|
+
let next = idx + 1;
|
|
5789
|
+
while (next < contentBlocks.length && isMarkerBlock(contentBlocks[next]))
|
|
5790
|
+
next++;
|
|
5791
|
+
const entry = contentBlocks[next];
|
|
5792
|
+
if (entry?.toc?.group?.id !== contentBlocks[idx].toc.group.id)
|
|
5793
|
+
return false;
|
|
5794
|
+
const col = currentColumn(doc, cursor);
|
|
5795
|
+
if (col.blocks.length === 0)
|
|
5796
|
+
return true;
|
|
5797
|
+
const m = measureContentBlock(entry, next, col.bbox.width, measureCtxOf(next));
|
|
5798
|
+
if (!m)
|
|
5799
|
+
return false;
|
|
5800
|
+
const style = m.kind.style;
|
|
5801
|
+
const need = m.measured.lines.length * style.lineHeightPx + Math.max(pendingSpacing, style.marginTopPx);
|
|
5802
|
+
if (need <= col.availableHeight + FIT_EPS)
|
|
5803
|
+
return false;
|
|
5804
|
+
pendingSpacing = 0;
|
|
5805
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onNewPage);
|
|
5806
|
+
return true;
|
|
5807
|
+
};
|
|
5808
|
+
/** A `tocGroupSplit` warning for each contents block set in more than
|
|
5809
|
+
* one column, with its head's title and the page it is cut on. */
|
|
5810
|
+
const tocGroupWarnings = () => {
|
|
5811
|
+
const placed = new Map();
|
|
5812
|
+
for (const page of doc.pages) {
|
|
5813
|
+
for (const c of page.columns) {
|
|
5814
|
+
for (const b of c.blocks) {
|
|
5815
|
+
const raw = b.contentIndex !== undefined ? contentBlocks[b.contentIndex] : undefined;
|
|
5816
|
+
const group = raw?.toc?.group;
|
|
5817
|
+
if (!raw || !group || group.role === 'continuation')
|
|
5818
|
+
continue;
|
|
5819
|
+
const at = placed.get(group.id) ?? { title: group.title, columns: new Set(), pageIndex: page.index, source: raw };
|
|
5820
|
+
at.columns.add(`${page.index}:${c.index}`);
|
|
5821
|
+
placed.set(group.id, at);
|
|
5822
|
+
}
|
|
5823
|
+
}
|
|
5824
|
+
}
|
|
5825
|
+
const out = [];
|
|
5826
|
+
for (const at of placed.values()) {
|
|
5827
|
+
if (at.columns.size < 2)
|
|
5828
|
+
continue;
|
|
5829
|
+
out.push({
|
|
5830
|
+
kind: 'tocGroupSplit',
|
|
5831
|
+
title: at.title,
|
|
5832
|
+
columns: at.columns.size,
|
|
5833
|
+
sourceStart: at.source.sourceStart + bodyOffset,
|
|
5834
|
+
sourceEnd: at.source.sourceEnd + bodyOffset,
|
|
5835
|
+
pageIndex: at.pageIndex,
|
|
5836
|
+
});
|
|
5837
|
+
}
|
|
5838
|
+
return out;
|
|
5839
|
+
};
|
|
5840
|
+
/** Content indices a composed page set in its frames: the main loop
|
|
5841
|
+
* passes over them. */
|
|
5842
|
+
const composedLaid = new Set();
|
|
5843
|
+
/** The composed pages' layout warnings (`frameOverflow`). */
|
|
5844
|
+
const composedNotes = [];
|
|
5845
|
+
/** Set the composed page `planned` on a fresh page (#855). */
|
|
5846
|
+
const placeComposedPage = (planned, fence) => {
|
|
5847
|
+
pendingSpacing = 0;
|
|
5848
|
+
closeFlowSegment(planned.startIdx);
|
|
5849
|
+
leaveCurrentPage();
|
|
5850
|
+
cursor.columnIndex = 0;
|
|
5851
|
+
const page = doc.pages[cursor.pageIndex];
|
|
5852
|
+
page.columns = [createVDTColumn(0, page.contentArea)];
|
|
5853
|
+
// The physical side: a recto has an odd folio (in either binding).
|
|
5854
|
+
const parity = (page.index + pageIndexOffset) % 2 === 0 ? 'recto' : 'verso';
|
|
5855
|
+
const template = resolvePageTemplate(templateSource, fence.template, { parity });
|
|
5856
|
+
const frameless = calloutStyles.find((st) => st.id === FRAME_STYLE_ID);
|
|
5857
|
+
const frames = designFramesOn(page);
|
|
5858
|
+
const area = template.area === 'trim' ? frames.page : template.area === 'bleed' ? frames.bleed : page.contentArea;
|
|
5859
|
+
const out = layoutComposedPage({
|
|
5860
|
+
pass: framePass,
|
|
5861
|
+
page,
|
|
5862
|
+
template,
|
|
5863
|
+
fence,
|
|
5864
|
+
startIdx: planned.startIdx,
|
|
5865
|
+
endIdx: planned.endIdx,
|
|
5866
|
+
stories: planned.stories,
|
|
5867
|
+
styleOf: (frame) => frameStyleOf((frame.style ? resolved.calloutStyles.find((st) => st.id === frame.style) : undefined) ?? frameless, frame),
|
|
5868
|
+
areas: { area, page: frames.page, bleed: frames.bleed },
|
|
5869
|
+
dpi,
|
|
5870
|
+
emPx: bodyStyle.fontSizePx,
|
|
5871
|
+
bodyOffset,
|
|
5872
|
+
mirrored: mirroredOf(page),
|
|
5873
|
+
pushGapPx: wrapGapPx(resolved.layout.wrap?.gap, dpi, bodyStyle.fontSizePx, floatGapPx),
|
|
5874
|
+
});
|
|
5875
|
+
page.composed = out.composed;
|
|
5876
|
+
const floats = (page.floats ??= []);
|
|
5877
|
+
for (const b of out.blocks) {
|
|
5878
|
+
floats.push(b);
|
|
5879
|
+
doc.blocks.push(b);
|
|
5880
|
+
}
|
|
5881
|
+
composedNotes.push(...out.warnings);
|
|
5882
|
+
for (const [head, story] of planned.stories) {
|
|
5883
|
+
if (!out.laid.has(head))
|
|
5884
|
+
continue;
|
|
5885
|
+
for (let i = story.startIdx; i <= story.plan.endIdx; i++)
|
|
5886
|
+
composedLaid.add(i);
|
|
5887
|
+
}
|
|
5888
|
+
pendingComposedBreak = 'page';
|
|
5889
|
+
flushPendingNumberingAtBoundary();
|
|
5890
|
+
};
|
|
5936
5891
|
/** The first block of the document that sets something: a heading there
|
|
5937
5892
|
* opens the document's first page (`openerPages`, #749). */
|
|
5938
5893
|
const firstFlowBlockIdx = contentBlocks.findIndex((b) => !isMarkerBlock(b) && b.type !== 'directive');
|
|
@@ -5941,11 +5896,18 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5941
5896
|
throw new BuildCancelledError();
|
|
5942
5897
|
options?.onProgress?.({ pass: 1, blocks: blockIdx, totalBlocks: contentBlocks.length, pages: doc.pages.length });
|
|
5943
5898
|
const rawBlock = contentBlocks[blockIdx];
|
|
5899
|
+
// Blocks a composed page set in its frames (#855) are done.
|
|
5900
|
+
if (composedLaid.has(blockIdx))
|
|
5901
|
+
continue;
|
|
5944
5902
|
// The styled section this block sits in: its geometry applies to the
|
|
5945
5903
|
// pages opened from here (a heading with `breakBefore` opens one).
|
|
5946
5904
|
const blockSection = sectionPlan.byBlock[blockIdx];
|
|
5947
5905
|
if (blockSection !== currentSection)
|
|
5948
5906
|
enterSection(blockSection);
|
|
5907
|
+
// The repeat of a contents block's head row (#850): set where a cut
|
|
5908
|
+
// block goes on in a fresh column, skipped everywhere else.
|
|
5909
|
+
if (rawBlock.toc?.group?.role === 'continuation' && !tocContinuationOpens(blockIdx))
|
|
5910
|
+
continue;
|
|
5949
5911
|
// Floats whose reference landed in an earlier iteration take the first
|
|
5950
5912
|
// free slot of the current page now — after their reference in reading
|
|
5951
5913
|
// order. Then enqueue the floats first-referenced in this block, so the
|
|
@@ -6153,6 +6115,39 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6153
6115
|
pendingPaperBreak = false;
|
|
6154
6116
|
breakForPaper(blockIdx);
|
|
6155
6117
|
}
|
|
6118
|
+
// A composed page (`::::page{template=…}`, #855): it owns a fresh page,
|
|
6119
|
+
// its template's frames filled with its stories (`layoutComposedPage`);
|
|
6120
|
+
// nothing flows on it, and what follows starts on the next page. A
|
|
6121
|
+
// story whose frame this side lacks, and content no frame takes, are
|
|
6122
|
+
// set in the flow there. A page whose template is unknown is set in
|
|
6123
|
+
// the flow on pages of its own (`templateUnknown`).
|
|
6124
|
+
if (rawBlock.type === 'containerStart' && rawBlock.containerName === 'composedPage') {
|
|
6125
|
+
const planned = composedPlans.get(blockIdx);
|
|
6126
|
+
pendingComposedBreak = false;
|
|
6127
|
+
if (planned && rawBlock.composedPage)
|
|
6128
|
+
placeComposedPage(planned, rawBlock.composedPage);
|
|
6129
|
+
else
|
|
6130
|
+
breakForPaper(blockIdx);
|
|
6131
|
+
continue;
|
|
6132
|
+
}
|
|
6133
|
+
if (rawBlock.type === 'containerEnd' && rawBlock.containerName === 'composedPage') {
|
|
6134
|
+
// (Set to `'page'` by `placeComposedPage`, a closure the flow
|
|
6135
|
+
// analysis does not follow.)
|
|
6136
|
+
if (pendingComposedBreak !== 'page')
|
|
6137
|
+
pendingComposedBreak = 'flow';
|
|
6138
|
+
continue;
|
|
6139
|
+
}
|
|
6140
|
+
const composedBreak = pendingComposedBreak;
|
|
6141
|
+
if (composedBreak === 'flow') {
|
|
6142
|
+
pendingComposedBreak = false;
|
|
6143
|
+
breakForPaper(blockIdx);
|
|
6144
|
+
}
|
|
6145
|
+
else if (composedBreak === 'page') {
|
|
6146
|
+
pendingComposedBreak = false;
|
|
6147
|
+
pendingSpacing = 0;
|
|
6148
|
+
leaveCurrentPage();
|
|
6149
|
+
flushPendingNumberingAtBoundary();
|
|
6150
|
+
}
|
|
6156
6151
|
// `:::page`: a comic page owns a fresh page — its panels, split lines
|
|
6157
6152
|
// and lettering laid out on the sheet (`layoutComicPage`); nothing
|
|
6158
6153
|
// flows on it, and what follows starts on the next page.
|
|
@@ -7389,6 +7384,35 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
7389
7384
|
}
|
|
7390
7385
|
}
|
|
7391
7386
|
}
|
|
7387
|
+
// A block of the contents is set whole (`toc.groups.keepTogether`,
|
|
7388
|
+
// `:::toc{keep}`, #850): when its rows do not all fit in the room the
|
|
7389
|
+
// column has left and a full column would hold them, it opens the
|
|
7390
|
+
// next column, with the headings right above it. One taller than a
|
|
7391
|
+
// column is cut, but keeps its head with `minEntriesAfterHead`
|
|
7392
|
+
// entries. Not a block that opens its column, or stands under
|
|
7393
|
+
// nothing but headings: it cannot do better anywhere.
|
|
7394
|
+
if (rawBlock.toc?.group?.lead && partIndex === 0 && curCol.blocks.length > 0) {
|
|
7395
|
+
const headingRun = trailingHeadingRun(curCol);
|
|
7396
|
+
const need = headingRun < curCol.blocks.length ? tocGroupNeed(blockIdx, curCol.bbox.width) : undefined;
|
|
7397
|
+
if (need) {
|
|
7398
|
+
const room = curCol.availableHeight - spacingBefore;
|
|
7399
|
+
const asked = need.whole <= contentArea.height + FIT_EPS ? need.whole : need.lead;
|
|
7400
|
+
if (asked > room + FIT_EPS) {
|
|
7401
|
+
if (resolved.headings.keepWithNext && headingRun > 0) {
|
|
7402
|
+
const rolledBack = rollbackHeadings(curCol);
|
|
7403
|
+
if (rolledBack.length > 0) {
|
|
7404
|
+
blockIdx = (rolledBack[0].contentIndex ?? blockIdx - rolledBack.length) - 1;
|
|
7405
|
+
pendingSpacing = 0;
|
|
7406
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onNewPage);
|
|
7407
|
+
break;
|
|
7408
|
+
}
|
|
7409
|
+
}
|
|
7410
|
+
pendingSpacing = 0;
|
|
7411
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onNewPage);
|
|
7412
|
+
continue;
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
}
|
|
7392
7416
|
// A short list is set whole (`bodyText.shortListSplit: 'avoid'`,
|
|
7393
7417
|
// #749): when its items do not all fit under what the column holds
|
|
7394
7418
|
// and an empty column would hold them, the list opens the next
|
|
@@ -8147,8 +8171,11 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
8147
8171
|
floatShrinkWarningsByDoc.set(doc, shrunk);
|
|
8148
8172
|
if (textWrapNotes.length > 0 || columnsNotes.length > 0)
|
|
8149
8173
|
textWrapWarningsByDoc.set(doc, [...textWrapNotes, ...columnsNotes]);
|
|
8174
|
+
// Composed pages (#855): frames whose content does not fit.
|
|
8175
|
+
if (composedNotes.length > 0)
|
|
8176
|
+
composedWarningsByDoc.set(doc, composedNotes);
|
|
8150
8177
|
// The composition rules (#749): short lists cut, floats on opener pages.
|
|
8151
|
-
const ruleNotes = [...shortListWarnings(), ...openerFloatNotes];
|
|
8178
|
+
const ruleNotes = [...shortListWarnings(), ...openerFloatNotes, ...tocGroupWarnings()];
|
|
8152
8179
|
if (ruleNotes.length > 0)
|
|
8153
8180
|
compositionWarningsByDoc.set(doc, ruleNotes);
|
|
8154
8181
|
const { proposals: citingPageProposals, refused: citingPageRefused } = settleCitingPageFloats();
|
|
@@ -8221,7 +8248,7 @@ export function* buildDocumentGen(content, config, cache, options) {
|
|
|
8221
8248
|
// cap; words of a joining script that run past their line, and styles
|
|
8222
8249
|
// whose letter-spacing such words do not take.
|
|
8223
8250
|
// Line numbers set over a float of the side column (#621).
|
|
8224
|
-
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) ?? [])];
|
|
8251
|
+
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) ?? [])];
|
|
8225
8252
|
// Side boxes and side floats set on pages after the text, and what the
|
|
8226
8253
|
// layout could place nowhere (#639).
|
|
8227
8254
|
loose.push(...afterTextWarnings(doc), ...(unplacedByDoc.get(doc) ?? []));
|
|
@@ -8252,6 +8279,8 @@ export function* buildDocumentGen(content, config, cache, options) {
|
|
|
8252
8279
|
const harakat = annotateArabicMarks(doc);
|
|
8253
8280
|
// The rules over `*…*` runs under `bodyText.emphasis: 'overline'`.
|
|
8254
8281
|
overlineEmphasis(doc);
|
|
8282
|
+
// The bands of the highlight marks (`:mark[…]`, #888).
|
|
8283
|
+
highlightDocument(doc);
|
|
8255
8284
|
// Faces the text was set in that the font set could not give (#629).
|
|
8256
8285
|
const fallbacks = fontSet && resolveDebugConfig(config?.debug).warnings.missingFont
|
|
8257
8286
|
? fontFallbacks(documentFontFaces(doc), fontSet).map((f) => ({ kind: 'fontFallback', family: f.family, weight: f.weight, style: f.style, reason: f.reason }))
|
|
@@ -8262,7 +8291,7 @@ export function* buildDocumentGen(content, config, cache, options) {
|
|
|
8262
8291
|
// Config values the build replaced (an unknown number format, a font
|
|
8263
8292
|
// stack, a side column no column width can take): walked once per build,
|
|
8264
8293
|
// not per pass — they belong to no page.
|
|
8265
|
-
const configWarnings = collectConfigWarnings(config);
|
|
8294
|
+
const configWarnings = collectConfigWarnings(config, { resources: content.resources, metadata: doc.metadata });
|
|
8266
8295
|
if (configWarnings.length > 0)
|
|
8267
8296
|
doc.configWarnings = configWarnings;
|
|
8268
8297
|
return doc;
|
|
@@ -8280,6 +8309,8 @@ const floatShrinkWarningsByDoc = new WeakMap();
|
|
|
8280
8309
|
/** The `textWrap` warnings of a build (#627) and its `columnsTooNarrow`
|
|
8281
8310
|
* ones (#634), found by its last pass. */
|
|
8282
8311
|
const textWrapWarningsByDoc = new WeakMap();
|
|
8312
|
+
/** The composed pages' layout warnings of a pass (`frameOverflow`, #855). */
|
|
8313
|
+
const composedWarningsByDoc = new WeakMap();
|
|
8283
8314
|
/** The `shortListSplit` and `openerFloat` warnings of a build (#749),
|
|
8284
8315
|
* found by its last pass. */
|
|
8285
8316
|
const compositionWarningsByDoc = new WeakMap();
|