postext 1.27.1 → 1.28.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/balloonPlacementPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/balloonPlacementPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/balloonPlacementPin.test.js +71 -0
- package/dist/__tests__/bundle/balloonPlacementPin.test.js.map +1 -0
- package/dist/__tests__/bundle/cjkRulesPin.test.js +131 -7
- package/dist/__tests__/bundle/cjkRulesPin.test.js.map +1 -1
- package/dist/__tests__/bundle/designOverflowPin.test.js +3 -3
- package/dist/__tests__/bundle/designOverflowPin.test.js.map +1 -1
- package/dist/__tests__/bundle/flowColumnsPin.test.js +3 -1
- package/dist/__tests__/bundle/flowColumnsPin.test.js.map +1 -1
- package/dist/__tests__/bundle/gridBalancingPin.test.js +14 -5
- package/dist/__tests__/bundle/gridBalancingPin.test.js.map +1 -1
- package/dist/__tests__/bundle/gridBreakRulesPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/gridBreakRulesPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/gridBreakRulesPin.test.js +144 -0
- package/dist/__tests__/bundle/gridBreakRulesPin.test.js.map +1 -0
- package/dist/__tests__/bundle/indexGroupSplitPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/indexGroupSplitPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/indexGroupSplitPin.test.js +55 -0
- package/dist/__tests__/bundle/indexGroupSplitPin.test.js.map +1 -0
- package/dist/__tests__/bundle/inlineCaptionSidePin.test.d.ts +2 -0
- package/dist/__tests__/bundle/inlineCaptionSidePin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/inlineCaptionSidePin.test.js +60 -0
- package/dist/__tests__/bundle/inlineCaptionSidePin.test.js.map +1 -0
- package/dist/__tests__/bundle/inlineTableSplitPin.test.js +3 -1
- package/dist/__tests__/bundle/inlineTableSplitPin.test.js.map +1 -1
- package/dist/__tests__/bundle/looseOrderPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/looseOrderPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/looseOrderPin.test.js +76 -0
- package/dist/__tests__/bundle/looseOrderPin.test.js.map +1 -0
- package/dist/__tests__/bundle/openerHeadFloatsPin.test.js +2 -1
- package/dist/__tests__/bundle/openerHeadFloatsPin.test.js.map +1 -1
- package/dist/__tests__/bundle/refLabelBreaksPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/refLabelBreaksPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/refLabelBreaksPin.test.js +72 -0
- package/dist/__tests__/bundle/refLabelBreaksPin.test.js.map +1 -0
- package/dist/__tests__/bundle/scriptContextPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/scriptContextPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/scriptContextPin.test.js +66 -0
- package/dist/__tests__/bundle/scriptContextPin.test.js.map +1 -0
- package/dist/__tests__/bundle/trailingStepPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/trailingStepPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/trailingStepPin.test.js +59 -0
- package/dist/__tests__/bundle/trailingStepPin.test.js.map +1 -0
- package/dist/__tests__/bundle/wideFloatStretchPin.test.d.ts +2 -0
- package/dist/__tests__/bundle/wideFloatStretchPin.test.d.ts.map +1 -0
- package/dist/__tests__/bundle/wideFloatStretchPin.test.js +59 -0
- package/dist/__tests__/bundle/wideFloatStretchPin.test.js.map +1 -0
- package/dist/__tests__/bundle.test.js +8 -6
- package/dist/__tests__/bundle.test.js.map +1 -1
- package/dist/__tests__/cjk/annotations.test.js +223 -0
- package/dist/__tests__/cjk/annotations.test.js.map +1 -1
- package/dist/__tests__/cjk/annotationsRender.test.js +3 -3
- package/dist/__tests__/cjk/annotationsRender.test.js.map +1 -1
- package/dist/__tests__/cjk/chipLatinSpacing.test.js +13 -2
- package/dist/__tests__/cjk/chipLatinSpacing.test.js.map +1 -1
- package/dist/__tests__/cjk/designNumberSeams.test.d.ts +2 -0
- package/dist/__tests__/cjk/designNumberSeams.test.d.ts.map +1 -0
- package/dist/__tests__/cjk/designNumberSeams.test.js +221 -0
- package/dist/__tests__/cjk/designNumberSeams.test.js.map +1 -0
- package/dist/__tests__/cjk/grid.test.js +1 -1
- package/dist/__tests__/cjk/grid.test.js.map +1 -1
- package/dist/__tests__/cjk/gridBalancing.test.js +3 -1
- package/dist/__tests__/cjk/gridBalancing.test.js.map +1 -1
- package/dist/__tests__/cjk/japaneseSpacing.test.js +3 -1
- package/dist/__tests__/cjk/japaneseSpacing.test.js.map +1 -1
- package/dist/__tests__/cjk/keepAll.test.js +3 -1
- package/dist/__tests__/cjk/keepAll.test.js.map +1 -1
- package/dist/__tests__/cjk/keepAllLatinQuotation.test.d.ts +2 -0
- package/dist/__tests__/cjk/keepAllLatinQuotation.test.d.ts.map +1 -0
- package/dist/__tests__/cjk/keepAllLatinQuotation.test.js +166 -0
- package/dist/__tests__/cjk/keepAllLatinQuotation.test.js.map +1 -0
- package/dist/__tests__/cjk/latinSpacingEdge.test.d.ts +2 -0
- package/dist/__tests__/cjk/latinSpacingEdge.test.d.ts.map +1 -0
- package/dist/__tests__/cjk/latinSpacingEdge.test.js +179 -0
- package/dist/__tests__/cjk/latinSpacingEdge.test.js.map +1 -0
- package/dist/__tests__/cjk/runt.test.js +92 -1
- package/dist/__tests__/cjk/runt.test.js.map +1 -1
- package/dist/__tests__/codeBlocks.test.js +1 -1
- package/dist/__tests__/columnBalancing.test.js +216 -0
- package/dist/__tests__/columnBalancing.test.js.map +1 -1
- package/dist/__tests__/columnRuleBands.test.js +78 -0
- package/dist/__tests__/columnRuleBands.test.js.map +1 -1
- package/dist/__tests__/comics/readingDirection.test.js +52 -0
- package/dist/__tests__/comics/readingDirection.test.js.map +1 -1
- package/dist/__tests__/comics/script.test.js +5 -0
- package/dist/__tests__/comics/script.test.js.map +1 -1
- package/dist/__tests__/contrast.test.d.ts +2 -0
- package/dist/__tests__/contrast.test.d.ts.map +1 -0
- package/dist/__tests__/contrast.test.js +258 -0
- package/dist/__tests__/contrast.test.js.map +1 -0
- package/dist/__tests__/defaults/cjk.test.js +4 -4
- package/dist/__tests__/defaults/cjk.test.js.map +1 -1
- package/dist/__tests__/defaults/gridBreakRules.test.d.ts +2 -0
- package/dist/__tests__/defaults/gridBreakRules.test.d.ts.map +1 -0
- package/dist/__tests__/defaults/gridBreakRules.test.js +152 -0
- package/dist/__tests__/defaults/gridBreakRules.test.js.map +1 -0
- package/dist/__tests__/defaults/headingsBalancing.test.js +25 -0
- package/dist/__tests__/defaults/headingsBalancing.test.js.map +1 -1
- package/dist/__tests__/defaults/stripContextDefaults.test.js +41 -0
- package/dist/__tests__/defaults/stripContextDefaults.test.js.map +1 -1
- package/dist/__tests__/defaults/stripRoundTrip.test.js +8 -5
- package/dist/__tests__/defaults/stripRoundTrip.test.js.map +1 -1
- package/dist/__tests__/exports.test.js +30 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/__tests__/fontUsage.test.d.ts +2 -0
- package/dist/__tests__/fontUsage.test.d.ts.map +1 -0
- package/dist/__tests__/fontUsage.test.js +113 -0
- package/dist/__tests__/fontUsage.test.js.map +1 -0
- package/dist/__tests__/hardBreaks.test.js +1 -1
- package/dist/__tests__/headingInlineMarks.test.js +7 -5
- package/dist/__tests__/headingInlineMarks.test.js.map +1 -1
- package/dist/__tests__/hyphenationRules.test.d.ts +2 -0
- package/dist/__tests__/hyphenationRules.test.d.ts.map +1 -0
- package/dist/__tests__/hyphenationRules.test.js +295 -0
- package/dist/__tests__/hyphenationRules.test.js.map +1 -0
- package/dist/__tests__/indexGroupSplit.test.d.ts +2 -0
- package/dist/__tests__/indexGroupSplit.test.d.ts.map +1 -0
- package/dist/__tests__/indexGroupSplit.test.js +175 -0
- package/dist/__tests__/indexGroupSplit.test.js.map +1 -0
- package/dist/__tests__/mathSizeMigration.test.js +7 -5
- package/dist/__tests__/mathSizeMigration.test.js.map +1 -1
- package/dist/__tests__/multipleColumns.test.js +19 -0
- package/dist/__tests__/multipleColumns.test.js.map +1 -1
- package/dist/__tests__/pipeline/calloutInlineResourceGap.test.js +1 -1
- package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js +3 -3
- package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js.map +1 -1
- package/dist/__tests__/pipeline/closingBandUnderOpener.test.d.ts +2 -0
- package/dist/__tests__/pipeline/closingBandUnderOpener.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/closingBandUnderOpener.test.js +90 -0
- package/dist/__tests__/pipeline/closingBandUnderOpener.test.js.map +1 -0
- package/dist/__tests__/pipeline/colonListRoom.test.js +5 -4
- package/dist/__tests__/pipeline/colonListRoom.test.js.map +1 -1
- package/dist/__tests__/pipeline/columnHeadSpace.test.d.ts +2 -0
- package/dist/__tests__/pipeline/columnHeadSpace.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/columnHeadSpace.test.js +175 -0
- package/dist/__tests__/pipeline/columnHeadSpace.test.js.map +1 -0
- package/dist/__tests__/pipeline/compoundBreaks.test.js +6 -6
- package/dist/__tests__/pipeline/compoundBreaks.test.js.map +1 -1
- package/dist/__tests__/pipeline/dashBreaks.test.js +5 -5
- package/dist/__tests__/pipeline/dashBreaks.test.js.map +1 -1
- package/dist/__tests__/pipeline/flowColumns.test.js +100 -0
- package/dist/__tests__/pipeline/flowColumns.test.js.map +1 -1
- package/dist/__tests__/pipeline/headingShortBand.test.js +2 -1
- package/dist/__tests__/pipeline/headingShortBand.test.js.map +1 -1
- package/dist/__tests__/pipeline/headingSplitOrphans.test.js +6 -5
- package/dist/__tests__/pipeline/headingSplitOrphans.test.js.map +1 -1
- package/dist/__tests__/pipeline/hyphenAcrossColumns.test.js +188 -1
- package/dist/__tests__/pipeline/hyphenAcrossColumns.test.js.map +1 -1
- package/dist/__tests__/pipeline/inlineCaptionSide.test.d.ts +2 -0
- package/dist/__tests__/pipeline/inlineCaptionSide.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/inlineCaptionSide.test.js +270 -0
- package/dist/__tests__/pipeline/inlineCaptionSide.test.js.map +1 -0
- package/dist/__tests__/pipeline/inlineFigureSpace.test.js +5 -5
- package/dist/__tests__/pipeline/inlineFigureSpace.test.js.map +1 -1
- package/dist/__tests__/pipeline/inlineRefRender.test.js +8 -6
- package/dist/__tests__/pipeline/inlineRefRender.test.js.map +1 -1
- package/dist/__tests__/pipeline/looseBeforeHeadingLines.test.d.ts +2 -0
- package/dist/__tests__/pipeline/looseBeforeHeadingLines.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/looseBeforeHeadingLines.test.js +73 -0
- package/dist/__tests__/pipeline/looseBeforeHeadingLines.test.js.map +1 -0
- package/dist/__tests__/pipeline/openerFloats.test.d.ts +2 -0
- package/dist/__tests__/pipeline/openerFloats.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/openerFloats.test.js +137 -0
- package/dist/__tests__/pipeline/openerFloats.test.js.map +1 -0
- package/dist/__tests__/pipeline/orderedNumberWidthItem.test.d.ts +2 -0
- package/dist/__tests__/pipeline/orderedNumberWidthItem.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/orderedNumberWidthItem.test.js +162 -0
- package/dist/__tests__/pipeline/orderedNumberWidthItem.test.js.map +1 -0
- package/dist/__tests__/pipeline/paragraphContainerTail.test.js +68 -8
- package/dist/__tests__/pipeline/paragraphContainerTail.test.js.map +1 -1
- package/dist/__tests__/pipeline/paragraphStyleFaces.test.js +1 -1
- package/dist/__tests__/pipeline/paragraphStyleFaces.test.js.map +1 -1
- package/dist/__tests__/pipeline/raggedLineAndRuntFix.test.d.ts +2 -0
- package/dist/__tests__/pipeline/raggedLineAndRuntFix.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/raggedLineAndRuntFix.test.js +151 -0
- package/dist/__tests__/pipeline/raggedLineAndRuntFix.test.js.map +1 -0
- package/dist/__tests__/pipeline/raggedOptimal.test.js +6 -6
- package/dist/__tests__/pipeline/raggedOptimal.test.js.map +1 -1
- package/dist/__tests__/pipeline/refLabelBreaks.test.d.ts +2 -0
- package/dist/__tests__/pipeline/refLabelBreaks.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/refLabelBreaks.test.js +324 -0
- package/dist/__tests__/pipeline/refLabelBreaks.test.js.map +1 -0
- package/dist/__tests__/pipeline/resourceTemplateStyles.test.d.ts +2 -0
- package/dist/__tests__/pipeline/resourceTemplateStyles.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/resourceTemplateStyles.test.js +145 -0
- package/dist/__tests__/pipeline/resourceTemplateStyles.test.js.map +1 -0
- package/dist/__tests__/pipeline/shortListSplit.test.d.ts +2 -0
- package/dist/__tests__/pipeline/shortListSplit.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/shortListSplit.test.js +181 -0
- package/dist/__tests__/pipeline/shortListSplit.test.js.map +1 -0
- package/dist/__tests__/pipeline/snapTailAtColumnFoot.test.d.ts +2 -0
- package/dist/__tests__/pipeline/snapTailAtColumnFoot.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/snapTailAtColumnFoot.test.js +133 -0
- package/dist/__tests__/pipeline/snapTailAtColumnFoot.test.js.map +1 -0
- package/dist/__tests__/pipeline/stretchAfterDisplays.test.d.ts +2 -0
- package/dist/__tests__/pipeline/stretchAfterDisplays.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/stretchAfterDisplays.test.js +51 -0
- package/dist/__tests__/pipeline/stretchAfterDisplays.test.js.map +1 -0
- package/dist/__tests__/pipeline/trailingCapFloatHead.test.js +26 -0
- package/dist/__tests__/pipeline/trailingCapFloatHead.test.js.map +1 -1
- package/dist/__tests__/pipeline/trailingStep.test.d.ts +2 -0
- package/dist/__tests__/pipeline/trailingStep.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/trailingStep.test.js +187 -0
- package/dist/__tests__/pipeline/trailingStep.test.js.map +1 -0
- package/dist/__tests__/pipeline/wideFloatStretch.test.d.ts +2 -0
- package/dist/__tests__/pipeline/wideFloatStretch.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/wideFloatStretch.test.js +84 -0
- package/dist/__tests__/pipeline/wideFloatStretch.test.js.map +1 -0
- package/dist/__tests__/scriptContext.test.d.ts +2 -0
- package/dist/__tests__/scriptContext.test.d.ts.map +1 -0
- package/dist/__tests__/scriptContext.test.js +919 -0
- package/dist/__tests__/scriptContext.test.js.map +1 -0
- package/dist/__tests__/softHyphenEdges.test.d.ts +2 -0
- package/dist/__tests__/softHyphenEdges.test.d.ts.map +1 -0
- package/dist/__tests__/softHyphenEdges.test.js +217 -0
- package/dist/__tests__/softHyphenEdges.test.js.map +1 -0
- package/dist/__tests__/spaceLimitRatio.test.d.ts +2 -0
- package/dist/__tests__/spaceLimitRatio.test.d.ts.map +1 -0
- package/dist/__tests__/spaceLimitRatio.test.js +226 -0
- package/dist/__tests__/spaceLimitRatio.test.js.map +1 -0
- package/dist/__tests__/trackedLigatures.test.js +365 -24
- package/dist/__tests__/trackedLigatures.test.js.map +1 -1
- package/dist/__tests__/verseLines.test.js +9 -7
- package/dist/__tests__/verseLines.test.js.map +1 -1
- package/dist/bundle/configVersion.d.ts +201 -6
- package/dist/bundle/configVersion.d.ts.map +1 -1
- package/dist/bundle/configVersion.js +440 -6
- package/dist/bundle/configVersion.js.map +1 -1
- package/dist/bundle/index.d.ts +8 -0
- package/dist/bundle/index.d.ts.map +1 -1
- package/dist/bundle/index.js +8 -0
- package/dist/bundle/index.js.map +1 -1
- package/dist/canvas-backend/blockRender.d.ts.map +1 -1
- package/dist/canvas-backend/blockRender.js +3 -2
- package/dist/canvas-backend/blockRender.js.map +1 -1
- package/dist/canvas-backend/chip.js +1 -1
- package/dist/canvas-backend/chip.js.map +1 -1
- package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
- package/dist/canvas-backend/headerFooter.js +17 -2
- package/dist/canvas-backend/headerFooter.js.map +1 -1
- package/dist/canvas-backend/runDirection.d.ts +10 -6
- package/dist/canvas-backend/runDirection.d.ts.map +1 -1
- package/dist/canvas-backend/runDirection.js +12 -7
- package/dist/canvas-backend/runDirection.js.map +1 -1
- package/dist/canvas-backend/scriptText.d.ts +11 -0
- package/dist/canvas-backend/scriptText.d.ts.map +1 -0
- package/dist/canvas-backend/scriptText.js +75 -0
- package/dist/canvas-backend/scriptText.js.map +1 -0
- package/dist/canvas-backend/segmentText.d.ts.map +1 -1
- package/dist/canvas-backend/segmentText.js +9 -1
- package/dist/canvas-backend/segmentText.js.map +1 -1
- package/dist/canvas-backend/trackedText.d.ts +35 -20
- package/dist/canvas-backend/trackedText.d.ts.map +1 -1
- package/dist/canvas-backend/trackedText.js +58 -22
- package/dist/canvas-backend/trackedText.js.map +1 -1
- package/dist/canvas-backend/verticalText.d.ts.map +1 -1
- package/dist/canvas-backend/verticalText.js +10 -2
- package/dist/canvas-backend/verticalText.js.map +1 -1
- package/dist/canvas-backend/wordRuns.d.ts +14 -5
- package/dist/canvas-backend/wordRuns.d.ts.map +1 -1
- package/dist/canvas-backend/wordRuns.js +20 -7
- package/dist/canvas-backend/wordRuns.js.map +1 -1
- package/dist/citations/names.d.ts +8 -0
- package/dist/citations/names.d.ts.map +1 -0
- package/dist/citations/names.js +25 -0
- package/dist/citations/names.js.map +1 -0
- package/dist/columnClip.d.ts +8 -1
- package/dist/columnClip.d.ts.map +1 -1
- package/dist/columnClip.js +32 -3
- package/dist/columnClip.js.map +1 -1
- package/dist/columnRule.d.ts +6 -3
- package/dist/columnRule.d.ts.map +1 -1
- package/dist/columnRule.js +6 -3
- package/dist/columnRule.js.map +1 -1
- package/dist/comics/layoutPage.d.ts.map +1 -1
- package/dist/comics/layoutPage.js +51 -22
- package/dist/comics/layoutPage.js.map +1 -1
- package/dist/comics/lettering/__tests__/bystanderFaces.test.d.ts +2 -0
- package/dist/comics/lettering/__tests__/bystanderFaces.test.d.ts.map +1 -0
- package/dist/comics/lettering/__tests__/bystanderFaces.test.js +204 -0
- package/dist/comics/lettering/__tests__/bystanderFaces.test.js.map +1 -0
- package/dist/comics/lettering/__tests__/shapeTextDash.test.d.ts +2 -0
- package/dist/comics/lettering/__tests__/shapeTextDash.test.d.ts.map +1 -0
- package/dist/comics/lettering/__tests__/shapeTextDash.test.js +173 -0
- package/dist/comics/lettering/__tests__/shapeTextDash.test.js.map +1 -0
- package/dist/comics/lettering/__tests__/strictPlacement.test.d.ts +2 -0
- package/dist/comics/lettering/__tests__/strictPlacement.test.d.ts.map +1 -0
- package/dist/comics/lettering/__tests__/strictPlacement.test.js +130 -0
- package/dist/comics/lettering/__tests__/strictPlacement.test.js.map +1 -0
- package/dist/comics/lettering/letter.js +21 -8
- package/dist/comics/lettering/letter.js.map +1 -1
- package/dist/comics/lettering/placement.d.ts.map +1 -1
- package/dist/comics/lettering/placement.js +12 -3
- package/dist/comics/lettering/placement.js.map +1 -1
- package/dist/comics/lettering/shape-text.d.ts +3 -0
- package/dist/comics/lettering/shape-text.d.ts.map +1 -1
- package/dist/comics/lettering/shape-text.js +71 -12
- package/dist/comics/lettering/shape-text.js.map +1 -1
- package/dist/comics/lettering/text.d.ts +5 -0
- package/dist/comics/lettering/text.d.ts.map +1 -1
- package/dist/comics/lettering/text.js +6 -1
- package/dist/comics/lettering/text.js.map +1 -1
- package/dist/comics/lettering/types.d.ts +12 -2
- package/dist/comics/lettering/types.d.ts.map +1 -1
- package/dist/comics/script.js +1 -1
- package/dist/comics/script.js.map +1 -1
- package/dist/comics/types.d.ts +7 -3
- package/dist/comics/types.d.ts.map +1 -1
- package/dist/configWarnings.d.ts.map +1 -1
- package/dist/configWarnings.js +33 -6
- package/dist/configWarnings.js.map +1 -1
- package/dist/contrast.d.ts +188 -0
- package/dist/contrast.d.ts.map +1 -0
- package/dist/contrast.js +583 -0
- package/dist/contrast.js.map +1 -0
- package/dist/defaults/bodyText.d.ts +31 -3
- package/dist/defaults/bodyText.d.ts.map +1 -1
- package/dist/defaults/bodyText.js +76 -8
- package/dist/defaults/bodyText.js.map +1 -1
- package/dist/defaults/citations.d.ts.map +1 -1
- package/dist/defaults/citations.js +4 -0
- package/dist/defaults/citations.js.map +1 -1
- package/dist/defaults/cjk.d.ts +11 -1
- package/dist/defaults/cjk.d.ts.map +1 -1
- package/dist/defaults/cjk.js +41 -3
- package/dist/defaults/cjk.js.map +1 -1
- package/dist/defaults/comics.d.ts.map +1 -1
- package/dist/defaults/comics.js +2 -0
- package/dist/defaults/comics.js.map +1 -1
- package/dist/defaults/contrast.d.ts +11 -0
- package/dist/defaults/contrast.d.ts.map +1 -0
- package/dist/defaults/contrast.js +65 -0
- package/dist/defaults/contrast.js.map +1 -0
- package/dist/defaults/crossRefs.d.ts +1 -1
- package/dist/defaults/crossRefs.d.ts.map +1 -1
- package/dist/defaults/crossRefs.js +6 -1
- package/dist/defaults/crossRefs.js.map +1 -1
- package/dist/defaults/footnotes.d.ts.map +1 -1
- package/dist/defaults/footnotes.js +5 -0
- package/dist/defaults/footnotes.js.map +1 -1
- package/dist/defaults/headings.d.ts +5 -1
- package/dist/defaults/headings.d.ts.map +1 -1
- package/dist/defaults/headings.js +41 -1
- package/dist/defaults/headings.js.map +1 -1
- package/dist/defaults/index.d.ts +3 -2
- package/dist/defaults/index.d.ts.map +1 -1
- package/dist/defaults/index.js +15 -4
- package/dist/defaults/index.js.map +1 -1
- package/dist/defaults/indexConfig.d.ts +1 -0
- package/dist/defaults/indexConfig.d.ts.map +1 -1
- package/dist/defaults/indexConfig.js +7 -1
- package/dist/defaults/indexConfig.js.map +1 -1
- package/dist/defaults/layout.d.ts.map +1 -1
- package/dist/defaults/layout.js +13 -1
- package/dist/defaults/layout.js.map +1 -1
- package/dist/defaults/orderedLists.js +1 -1
- package/dist/defaults/orderedLists.js.map +1 -1
- package/dist/defaults/paragraphStyles.d.ts.map +1 -1
- package/dist/defaults/paragraphStyles.js +5 -0
- package/dist/defaults/paragraphStyles.js.map +1 -1
- package/dist/defaults/shared.d.ts +4 -1
- package/dist/defaults/shared.d.ts.map +1 -1
- package/dist/defaults/shared.js +5 -0
- package/dist/defaults/shared.js.map +1 -1
- package/dist/design/cjkText.d.ts +7 -2
- package/dist/design/cjkText.d.ts.map +1 -1
- package/dist/design/cjkText.js +8 -2
- package/dist/design/cjkText.js.map +1 -1
- package/dist/design/layout.d.ts.map +1 -1
- package/dist/design/layout.js +85 -12
- package/dist/design/layout.js.map +1 -1
- package/dist/design/richText.d.ts.map +1 -1
- package/dist/design/richText.js +7 -3
- package/dist/design/richText.js.map +1 -1
- package/dist/fonts/usage.d.ts.map +1 -1
- package/dist/fonts/usage.js +89 -0
- package/dist/fonts/usage.js.map +1 -1
- package/dist/html-backend.d.ts.map +1 -1
- package/dist/html-backend.js +97 -27
- package/dist/html-backend.js.map +1 -1
- package/dist/hyphenate.d.ts +58 -1
- package/dist/hyphenate.d.ts.map +1 -1
- package/dist/hyphenate.js +228 -19
- package/dist/hyphenate.js.map +1 -1
- package/dist/hyphenationExceptions.d.ts +10 -0
- package/dist/hyphenationExceptions.d.ts.map +1 -0
- package/dist/hyphenationExceptions.js +29 -0
- package/dist/hyphenationExceptions.js.map +1 -0
- package/dist/index.d.ts +12 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/knuthPlass/pretextAdapter.d.ts.map +1 -1
- package/dist/knuthPlass/pretextAdapter.js +4 -17
- package/dist/knuthPlass/pretextAdapter.js.map +1 -1
- package/dist/knuthPlass/richAdapter.d.ts +9 -0
- package/dist/knuthPlass/richAdapter.d.ts.map +1 -1
- package/dist/knuthPlass/richAdapter.js +15 -18
- package/dist/knuthPlass/richAdapter.js.map +1 -1
- package/dist/looseLines.d.ts +15 -4
- package/dist/looseLines.d.ts.map +1 -1
- package/dist/looseLines.js +17 -4
- package/dist/looseLines.js.map +1 -1
- package/dist/measure/cache.d.ts.map +1 -1
- package/dist/measure/cache.js +14 -4
- package/dist/measure/cache.js.map +1 -1
- package/dist/measure/canvas.d.ts +18 -0
- package/dist/measure/canvas.d.ts.map +1 -1
- package/dist/measure/canvas.js +104 -0
- package/dist/measure/canvas.js.map +1 -1
- package/dist/measure/cjkAnnotate.d.ts +11 -6
- package/dist/measure/cjkAnnotate.d.ts.map +1 -1
- package/dist/measure/cjkAnnotate.js +27 -11
- package/dist/measure/cjkAnnotate.js.map +1 -1
- package/dist/measure/cjkCompose.d.ts +6 -2
- package/dist/measure/cjkCompose.d.ts.map +1 -1
- package/dist/measure/cjkCompose.js +146 -30
- package/dist/measure/cjkCompose.js.map +1 -1
- package/dist/measure/cjkPunctuation.d.ts +17 -0
- package/dist/measure/cjkPunctuation.d.ts.map +1 -1
- package/dist/measure/cjkPunctuation.js +15 -1
- package/dist/measure/cjkPunctuation.js.map +1 -1
- package/dist/measure/font.d.ts +2 -1
- package/dist/measure/font.d.ts.map +1 -1
- package/dist/measure/font.js +4 -2
- package/dist/measure/font.js.map +1 -1
- package/dist/measure/hardBreaks.d.ts.map +1 -1
- package/dist/measure/hardBreaks.js +6 -2
- package/dist/measure/hardBreaks.js.map +1 -1
- package/dist/measure/kashida.d.ts.map +1 -1
- package/dist/measure/kashida.js +8 -11
- package/dist/measure/kashida.js.map +1 -1
- package/dist/measure/plain.d.ts +3 -0
- package/dist/measure/plain.d.ts.map +1 -1
- package/dist/measure/plain.js +70 -5
- package/dist/measure/plain.js.map +1 -1
- package/dist/measure/rich.d.ts +32 -0
- package/dist/measure/rich.d.ts.map +1 -1
- package/dist/measure/rich.js +227 -35
- package/dist/measure/rich.js.map +1 -1
- package/dist/measure/script.d.ts +180 -0
- package/dist/measure/script.d.ts.map +1 -0
- package/dist/measure/script.js +329 -0
- package/dist/measure/script.js.map +1 -0
- package/dist/measure/spaceRatios.d.ts +28 -0
- package/dist/measure/spaceRatios.d.ts.map +1 -0
- package/dist/measure/spaceRatios.js +48 -0
- package/dist/measure/spaceRatios.js.map +1 -0
- package/dist/measure/spaces.d.ts +10 -0
- package/dist/measure/spaces.d.ts.map +1 -1
- package/dist/measure/spaces.js +36 -0
- package/dist/measure/spaces.js.map +1 -1
- package/dist/measure/types.d.ts +9 -0
- package/dist/measure/types.d.ts.map +1 -1
- package/dist/measure/types.js.map +1 -1
- package/dist/numbering.d.ts +5 -0
- package/dist/numbering.d.ts.map +1 -1
- package/dist/numbering.js +5 -1
- package/dist/numbering.js.map +1 -1
- package/dist/parse/types.d.ts +13 -0
- package/dist/parse/types.d.ts.map +1 -1
- package/dist/pipeline/bandCaps.d.ts +35 -1
- package/dist/pipeline/bandCaps.d.ts.map +1 -1
- package/dist/pipeline/bandCaps.js +95 -3
- package/dist/pipeline/bandCaps.js.map +1 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +754 -49
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/buildHelpers.d.ts.map +1 -1
- package/dist/pipeline/buildHelpers.js +5 -1
- package/dist/pipeline/buildHelpers.js.map +1 -1
- package/dist/pipeline/buildMeasurement.d.ts +9 -0
- package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
- package/dist/pipeline/buildMeasurement.js +3 -2
- package/dist/pipeline/buildMeasurement.js.map +1 -1
- package/dist/pipeline/calloutLayout.d.ts +10 -1
- package/dist/pipeline/calloutLayout.d.ts.map +1 -1
- package/dist/pipeline/calloutLayout.js +45 -9
- package/dist/pipeline/calloutLayout.js.map +1 -1
- package/dist/pipeline/columnBalancing.d.ts +44 -7
- package/dist/pipeline/columnBalancing.d.ts.map +1 -1
- package/dist/pipeline/columnBalancing.js +167 -40
- package/dist/pipeline/columnBalancing.js.map +1 -1
- package/dist/pipeline/config.d.ts +2 -2
- package/dist/pipeline/config.d.ts.map +1 -1
- package/dist/pipeline/config.js +18 -3
- package/dist/pipeline/config.js.map +1 -1
- package/dist/pipeline/contentWarnings.d.ts +6 -0
- package/dist/pipeline/contentWarnings.d.ts.map +1 -1
- package/dist/pipeline/contentWarnings.js +32 -0
- package/dist/pipeline/contentWarnings.js.map +1 -1
- package/dist/pipeline/crossRefs.d.ts +12 -1
- package/dist/pipeline/crossRefs.d.ts.map +1 -1
- package/dist/pipeline/crossRefs.js +22 -14
- package/dist/pipeline/crossRefs.js.map +1 -1
- package/dist/pipeline/flowColumns.d.ts +2 -1
- package/dist/pipeline/flowColumns.d.ts.map +1 -1
- package/dist/pipeline/flowColumns.js +12 -2
- package/dist/pipeline/flowColumns.js.map +1 -1
- package/dist/pipeline/footnotes.d.ts.map +1 -1
- package/dist/pipeline/footnotes.js +3 -0
- package/dist/pipeline/footnotes.js.map +1 -1
- package/dist/pipeline/indexDirective.d.ts.map +1 -1
- package/dist/pipeline/indexDirective.js +15 -0
- package/dist/pipeline/indexDirective.js.map +1 -1
- package/dist/pipeline/lists.d.ts +1 -1
- package/dist/pipeline/lists.d.ts.map +1 -1
- package/dist/pipeline/lists.js +9 -1
- package/dist/pipeline/lists.js.map +1 -1
- package/dist/pipeline/measureContentBlock.d.ts +18 -0
- package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
- package/dist/pipeline/measureContentBlock.js +13 -3
- package/dist/pipeline/measureContentBlock.js.map +1 -1
- package/dist/pipeline/paragraphContainers.d.ts +4 -1
- package/dist/pipeline/paragraphContainers.d.ts.map +1 -1
- package/dist/pipeline/paragraphContainers.js +2 -0
- package/dist/pipeline/paragraphContainers.js.map +1 -1
- package/dist/pipeline/placement.d.ts +15 -0
- package/dist/pipeline/placement.d.ts.map +1 -1
- package/dist/pipeline/placement.js +36 -4
- package/dist/pipeline/placement.js.map +1 -1
- package/dist/pipeline/raggedLines.d.ts +8 -6
- package/dist/pipeline/raggedLines.d.ts.map +1 -1
- package/dist/pipeline/raggedLines.js +13 -10
- package/dist/pipeline/raggedLines.js.map +1 -1
- package/dist/pipeline/resourceLayout.d.ts +4 -0
- package/dist/pipeline/resourceLayout.d.ts.map +1 -1
- package/dist/pipeline/resourceLayout.js +22 -7
- package/dist/pipeline/resourceLayout.js.map +1 -1
- package/dist/pipeline/resourceNumbering.d.ts +6 -3
- package/dist/pipeline/resourceNumbering.d.ts.map +1 -1
- package/dist/pipeline/resourceNumbering.js +36 -19
- package/dist/pipeline/resourceNumbering.js.map +1 -1
- package/dist/pipeline/toc.d.ts +0 -3
- package/dist/pipeline/toc.d.ts.map +1 -1
- package/dist/pipeline/toc.js +19 -2
- package/dist/pipeline/toc.js.map +1 -1
- package/dist/types.d.ts +411 -15
- package/dist/types.d.ts.map +1 -1
- package/dist/vdt.d.ts +90 -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
|
@@ -8,6 +8,8 @@ import { buildPageLabels, computeHeadingNumbering, parseNumberFormat, } from '..
|
|
|
8
8
|
import { extractFrontmatter, normalizeMetadata } from '../frontmatter';
|
|
9
9
|
import { collectConfigWarnings } from '../configWarnings';
|
|
10
10
|
import { initHyphenator } from '../measure';
|
|
11
|
+
import { setHyphenationRules } from '../hyphenate';
|
|
12
|
+
import { citedNames } from '../citations/names';
|
|
11
13
|
import { getCjkLineBreak, setCjkLineBreak } from '../measure/cjkClasses';
|
|
12
14
|
import { cjkCompositionOf, getCjkComposition, setCjkComposition } from '../measure/cjkPunctuation';
|
|
13
15
|
import { getMeasureRegion, getMeasureUprightDigits, getMeasureWritingMode, measuringVertically, setMeasureUprightDigits, setMeasureWritingMode } from '../measure/vertical';
|
|
@@ -21,6 +23,7 @@ import { defaultFontSet, documentFontFaces, fontFallbacks } from '../fonts/faces
|
|
|
21
23
|
import { syncFontSet } from '../fonts/fontSet';
|
|
22
24
|
import { asciiDigits } from '../arabicNumerals';
|
|
23
25
|
import { getMeasureArabicNumbers, getMeasureDirection, setMeasureArabicNumbers, setMeasureDirection, shiftLineX } from '../measure/bidiLines';
|
|
26
|
+
import { getMeasureScriptContext, hanMarksOfLocale, scriptContextOfLocale, setMeasureScriptContext } from '../measure/script';
|
|
24
27
|
import { createHeadingLevelResolver, deriveSectionGeometryConfig, sectionWritingMode, deriveSectionMeasureContext, headingIsHidden, headingIsNumbered, headingMarksFor, headingStyleOf, numberTitlesFor, planHeadingSections, } from './headingStyles';
|
|
25
28
|
import { locateAnchors } from './anchors';
|
|
26
29
|
import { applyCitations, citationLocale, processCitations, withBibliographyStyle } from './citations';
|
|
@@ -34,7 +37,7 @@ import { expandTocDirectives } from './toc';
|
|
|
34
37
|
import { expandIndexDirectives, locateIndexMarks } from './indexDirective';
|
|
35
38
|
import { resolveBodyStyle, resolveBlockquoteStyle, resolveParagraphStyle } from './styles';
|
|
36
39
|
import { computeLevelIndentsPx, computeOrderedLevelIndentsPx, computeOrderedListRunMetrics, directListMarker, listBulletPosition, listItemGapPx, listItemSpacingPx, mirrorListMarker, } from './lists';
|
|
37
|
-
import { resetLinePositions, createPageWithColumns, currentColumn, advanceToNextColumn, advanceToNextPageBoundary, enforcePageParity, placeBlockInColumn, placeAtomicBlock, createPartPage, pageHasContent, sideColumnOf, sideColumns, sideUsedBottom, pageIsOccupied, bandColumns, currentBand, isBandLevel, bandUsedBottom, closeBandAndInsertSpan, closeBandAt, pageLayoutOf, FIT_EPS, } from './placement';
|
|
40
|
+
import { resetLinePositions, createPageWithColumns, currentColumn, advanceToNextColumn, columnClosesPage, flowColumnsAfter, advanceToNextPageBoundary, enforcePageParity, placeBlockInColumn, placeAtomicBlock, createPartPage, pageHasContent, sideColumnOf, sideColumns, sideUsedBottom, pageIsOccupied, bandColumns, currentBand, isBandLevel, bandUsedBottom, closeBandAndInsertSpan, closeBandAt, pageLayoutOf, FIT_EPS, } from './placement';
|
|
38
41
|
import { chooseParagraphSplit } from './orphanWidow';
|
|
39
42
|
import { layoutComicPage, comicPageLayoutWarnings } from '../comics/layoutPage';
|
|
40
43
|
import { comicStripExtent, comicStripOffset, comicStripPlacement, comicStripWidth, layoutComicStrip } from '../comics/strip';
|
|
@@ -47,7 +50,7 @@ import { planParts, derivePartMeasureContext } from './parts';
|
|
|
47
50
|
import { layoutCallout, offsetBlock, offsetCalloutToAbsolute, pickCalloutStyle, planCallouts, resolveCalloutAttrs, } from './calloutLayout';
|
|
48
51
|
import { fillGalley, galleyBreaks } from './columnsGroup';
|
|
49
52
|
import { chooseTableSlice, layoutCaptionText, layoutResourceBlock, MIN_TAIL_ROWS } from './resourceLayout';
|
|
50
|
-
import { computeFloatPlan, floatedResourceIds, floatColumnCount, } from './floatPlacement';
|
|
53
|
+
import { computeFloatPlan, floatedResourceIds, floatColumnCount, resolveResourcePlacement, } from './floatPlacement';
|
|
51
54
|
import { enumerateCurrentPageSlots, measureFloatBand, floatGapAbove, floatGapBelow, measureSideStack, clearSideObstacles, columnHasFloatBand, fitsStrict, trueBottom, } from './floatSlots';
|
|
52
55
|
import { computeHeadingContext, computeResourceNumberingState, } from './resourceNumbering';
|
|
53
56
|
import { documentLocale, effectiveResourceTypes } from '../defaults/resourceTypes';
|
|
@@ -61,9 +64,9 @@ import { buildHeadersAndFooters, defaultOpenerTitle, headingDesignBoxes, measure
|
|
|
61
64
|
import { flowColorValues } from './partPalette';
|
|
62
65
|
import { chapterNumberCounter, leadingBoldText } from './placeholders';
|
|
63
66
|
import { proposeBalanceLines, GRID_LINE_LEVERS, collectColumnGaps, firstDivergentColumn, gapLinesIn, boxRoomIn, boxLeverKeys, pageSegments, MAX_BALANCING_PASSES, MAX_BALANCING_PASSES_PER_DOCUMENT, balanceKey, candidateKey, flexFigureKey, flexFloatKey } from './columnBalancing';
|
|
64
|
-
import { applyBandCap, uncapBand, columnBottom, bandCapLines, bandTop, bareBandTop, resolveBandCapsGen, drainPasses, resolveTrailingCapsGen, bandCapLinesAroundZone, } from './bandCaps';
|
|
67
|
+
import { applyBandCap, uncapBand, columnBottom, bandCapLines, bandTop, bareBandTop, resolveBandCapsGen, drainPasses, resolveTrailingCapsGen, bandCapLinesAroundZone, bandLinePitch, capRetryLimit, } from './bandCaps';
|
|
65
68
|
import { raggedLooseLines } from './raggedLines';
|
|
66
|
-
import { cjkLooseLineWarnings, collectContentWarnings, designTruncationWarnings, dropCapWarnings, floatShrinkWarnings, joiningLetterSpacingWarnings, locateContentWarnings, wordOverflowWarnings } from './contentWarnings';
|
|
69
|
+
import { cjkLooseLineWarnings, raggedLineWarnings, collectContentWarnings, designTruncationWarnings, dropCapWarnings, floatShrinkWarnings, joiningLetterSpacingWarnings, locateContentWarnings, wordOverflowWarnings } from './contentWarnings';
|
|
67
70
|
import { dropCapSinkAfter } from './dropCap';
|
|
68
71
|
import { mostlyJoiningScript } from '../measure/joining';
|
|
69
72
|
import { composesAsCjk } from '../measure/cjkCompose';
|
|
@@ -236,10 +239,12 @@ export function buildDocumentPass(content, config, cache, options, hints = {}) {
|
|
|
236
239
|
const uprightDigits = getMeasureUprightDigits();
|
|
237
240
|
const direction = getMeasureDirection();
|
|
238
241
|
const arabicNumbers = getMeasureArabicNumbers();
|
|
242
|
+
const scriptContext = getMeasureScriptContext();
|
|
239
243
|
try {
|
|
240
244
|
return placeDocumentPass(content, config, cache, options, hints);
|
|
241
245
|
}
|
|
242
246
|
finally {
|
|
247
|
+
setMeasureScriptContext(scriptContext);
|
|
243
248
|
setMeasureArabicNumbers(arabicNumbers);
|
|
244
249
|
setCjkLineBreak(lineBreak);
|
|
245
250
|
setCjkComposition(composition);
|
|
@@ -287,7 +292,10 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
287
292
|
// design text — and so do the words wider than their measure, divided at a
|
|
288
293
|
// syllable even in ragged text. Left unset, a build would hyphenate with
|
|
289
294
|
// whichever dictionary the previous one (or the default, en-us) chose.
|
|
290
|
-
|
|
295
|
+
// With the words the document keeps whole (#699); the names of the
|
|
296
|
+
// authors it cites join them below, once its references are read.
|
|
297
|
+
const hyphenationRules = { exceptions: resolved.bodyText.hyphenation.exceptions, capitalized: resolved.bodyText.hyphenation.capitalized };
|
|
298
|
+
initHyphenator(resolved.bodyText.hyphenation.locale, hyphenationRules);
|
|
291
299
|
// CJK text breaks at the document's level wherever it is measured (body,
|
|
292
300
|
// captions, cells, notes, boxes), as it hyphenates in its language.
|
|
293
301
|
setCjkLineBreak(resolved.cjk.lineBreak);
|
|
@@ -306,6 +314,15 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
306
314
|
// And, in an Arabic-script book, read a number that opens a paragraph as
|
|
307
315
|
// the numbers after its letters (#665).
|
|
308
316
|
setMeasureArabicNumbers(arabicNumbersOf(resolved));
|
|
317
|
+
// A word with no letter is shaped in the script of the text around it,
|
|
318
|
+
// and with no letter near in the script of the document's language (#725).
|
|
319
|
+
// A Chinese or Japanese document sets its doubled ellipsis and dash as
|
|
320
|
+
// Han text wherever they are cited.
|
|
321
|
+
setMeasureScriptContext({
|
|
322
|
+
enabled: resolved.bodyText.scriptContext !== false,
|
|
323
|
+
script: scriptContextOfLocale(resolvedLocale(resolved)),
|
|
324
|
+
...(hanMarksOfLocale(resolvedLocale(resolved)) ? { hanMarks: true } : {}),
|
|
325
|
+
});
|
|
309
326
|
// Compute baseline grid
|
|
310
327
|
const baselineGrid = computeBaselineGrid(resolved);
|
|
311
328
|
// Create document
|
|
@@ -337,6 +354,19 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
337
354
|
// styled section with its own margins / layout — the section's.
|
|
338
355
|
let contentArea = pageMetrics.contentArea;
|
|
339
356
|
let geomResolved = resolved;
|
|
357
|
+
/** How many columns of a fresh page take body text, in the geometry
|
|
358
|
+
* pages are opened with now (`hyphenateAcrossColumns: 'withinPage'`,
|
|
359
|
+
* #701: every that many column ends, a page ends). */
|
|
360
|
+
let freshFlowColumnsOf;
|
|
361
|
+
let freshFlowColumns = 1;
|
|
362
|
+
const freshPageFlowColumns = () => {
|
|
363
|
+
if (freshFlowColumnsOf !== geomResolved) {
|
|
364
|
+
freshFlowColumnsOf = geomResolved;
|
|
365
|
+
const fresh = createPageWithColumns(doc.pages.length, geomResolved, contentArea, pageWidthPx, pageHeightPx, pageIndexOffset);
|
|
366
|
+
freshFlowColumns = Math.max(1, fresh.columns.filter((c) => c.kind !== 'side').length);
|
|
367
|
+
}
|
|
368
|
+
return freshFlowColumns;
|
|
369
|
+
};
|
|
340
370
|
// Page/bleed frames for design elements anchored to `'page'` / `'bleed'`,
|
|
341
371
|
// in the frame of the page's flow: the sheet's, or on a vertical page
|
|
342
372
|
// (`page.flow`) the flow frame, where "the top of the page" is the
|
|
@@ -382,6 +412,11 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
382
412
|
const parsedBody = numberTitlesFor(headingMarksFor(tashkilFor(literalBreaksFor(parseMarkdownMemo(markdownBody, codeParseOptions(resolved)), resolved), resolved.bodyText.tashkil), resolved), resolved);
|
|
383
413
|
const citationContext = content.citations
|
|
384
414
|
?? (needsCitationContext(parsedBody, frontmatterMeta) ? bookCitationContexts([{ metadata: frontmatterMeta, blocks: parsedBody }], content.resources)[0] : undefined);
|
|
415
|
+
// `citations.hyphenateNames: false`: the cited authors' names are never
|
|
416
|
+
// divided, in a citation, in the text or in the bibliography (#699).
|
|
417
|
+
if (citationContext && !resolved.citations.hyphenateNames) {
|
|
418
|
+
setHyphenationRules({ ...hyphenationRules, names: citedNames(citationContext.items) });
|
|
419
|
+
}
|
|
385
420
|
const citationsApplied = citationContext
|
|
386
421
|
? applyCitations(parsedBody, citationContext, processCitations(citationContext, resolved, citationLocale(resolved, resolvedLocale(resolved))), resolved, resolvedLocale(resolved))
|
|
387
422
|
: undefined;
|
|
@@ -543,6 +578,30 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
543
578
|
/** The flow segment has ended and its floats and side boxes are taking
|
|
544
579
|
* pages after the text (see `drainPendingFloats`, #639). */
|
|
545
580
|
let drainingAfterText = false;
|
|
581
|
+
/** Opener pages (`layout.openerFloats`, #749): the page a part opens,
|
|
582
|
+
* the page a heading opens with its own break, and the first page of a
|
|
583
|
+
* document that starts with a heading. Under `'avoid'` they offer a
|
|
584
|
+
* float no slot (see `placeFloatInColumns`), so it takes the first one
|
|
585
|
+
* after them; under `'warn'` each float set on one is reported. */
|
|
586
|
+
const openerPages = new Set();
|
|
587
|
+
const openerFloatRule = resolved.layout.openerFloats;
|
|
588
|
+
/** The `openerFloat` warnings of this pass, and the floats they name. */
|
|
589
|
+
const openerFloatNotes = [];
|
|
590
|
+
const openerFloatsNoted = new Set();
|
|
591
|
+
const noteOpenerFloat = (page, f) => {
|
|
592
|
+
if (openerFloatRule !== 'warn' || !openerPages.has(page) || openerFloatsNoted.has(f.resourceId))
|
|
593
|
+
return;
|
|
594
|
+
openerFloatsNoted.add(f.resourceId);
|
|
595
|
+
const box = f.callout ? calloutFloats.get(f.callout.startIdx) : undefined;
|
|
596
|
+
const first = contentBlocks[box ? f.callout.startIdx : f.firstBlockIdx];
|
|
597
|
+
const last = contentBlocks[box ? box.plan.endIdx : f.firstBlockIdx];
|
|
598
|
+
openerFloatNotes.push({
|
|
599
|
+
kind: 'openerFloat',
|
|
600
|
+
...(box ? {} : { resourceId: f.resourceId }),
|
|
601
|
+
...(first && last ? { sourceStart: first.sourceStart + bodyOffset, sourceEnd: last.sourceEnd + bodyOffset } : {}),
|
|
602
|
+
pageIndex: page.index,
|
|
603
|
+
});
|
|
604
|
+
};
|
|
546
605
|
/** `span: 'side'` boxes of a style with `sideAtColumnEnd: 'after'`
|
|
547
606
|
* (EF-161), and the side boxes fenced behind them, waiting for the text
|
|
548
607
|
* after their fence to land (see `settleAwaitingSideBoxes`). Each keeps
|
|
@@ -1496,6 +1555,10 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
1496
1555
|
return { measure, ...band, cap, fits: excessOf(measure, band) <= 0.01 };
|
|
1497
1556
|
};
|
|
1498
1557
|
const placeFloatInColumns = (page, f, targetCols, position, pageSpan, mode, anchorToCap = false, side = false, refY) => {
|
|
1558
|
+
// An opener page takes no float (`layout.openerFloats: 'avoid'`, #749):
|
|
1559
|
+
// it waits for the page the flow opens next.
|
|
1560
|
+
if (openerFloatRule === 'avoid' && openerPages.has(page))
|
|
1561
|
+
return 'defer';
|
|
1499
1562
|
const first = targetCols[0];
|
|
1500
1563
|
const probe = probeFloatBand(page, f, targetCols, position, pageSpan, anchorToCap, side, refY);
|
|
1501
1564
|
if (!probe)
|
|
@@ -1568,6 +1631,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
1568
1631
|
return 'skip';
|
|
1569
1632
|
first.availableHeight = Math.max(0, first.availableHeight - need);
|
|
1570
1633
|
commitFloatBlock(page, first, built, xLeft, y, width, f.firstBlockIdx);
|
|
1634
|
+
noteOpenerFloat(page, f);
|
|
1571
1635
|
if (drainingAfterText && !calloutFloatOf(f.resourceId)) {
|
|
1572
1636
|
const citing = contentBlocks[f.firstBlockIdx];
|
|
1573
1637
|
setAfterText.set(built.block, {
|
|
@@ -1843,6 +1907,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
1843
1907
|
}
|
|
1844
1908
|
}
|
|
1845
1909
|
commitFloatBlock(page, first, built, xLeft, y, width, f.firstBlockIdx);
|
|
1910
|
+
noteOpenerFloat(page, f);
|
|
1846
1911
|
floatsPlaced++;
|
|
1847
1912
|
return rest ? { rest } : 'placed';
|
|
1848
1913
|
};
|
|
@@ -2067,8 +2132,10 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
2067
2132
|
const cursorCol = page.columns[cursor.columnIndex];
|
|
2068
2133
|
if (!cursorCol)
|
|
2069
2134
|
return false;
|
|
2135
|
+
// (A short list set whole stays under what introduces it: only the
|
|
2136
|
+
// cursor's column counts for it, #749.)
|
|
2070
2137
|
const candidates = bandColumns(page, currentBand(page, cursor))
|
|
2071
|
-
.filter((c) => c.kind !== 'span' && c.index >= cursorCol.index && (c === cursorCol || c.blocks.length === 0));
|
|
2138
|
+
.filter((c) => c.kind !== 'span' && c.index >= cursorCol.index && (c === cursorCol || (!box.stays && c.blocks.length === 0)));
|
|
2072
2139
|
const fitsIn = (c, available) => available >= box.heightAt(c.bbox.width) - 0.01;
|
|
2073
2140
|
if (!candidates.some((c) => fitsIn(c, c.availableHeight)))
|
|
2074
2141
|
return false;
|
|
@@ -2083,12 +2150,13 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
2083
2150
|
* empty columns; the band bottom for page-span floats). Runs before each
|
|
2084
2151
|
* block is placed, so a float lands in the first gap after its reference.
|
|
2085
2152
|
* `nextBlockIdx` is that block: a keep-together box it opens holds the
|
|
2086
|
-
* slots that would starve it (see `slotStarvesBox`)
|
|
2153
|
+
* slots that would starve it (see `slotStarvesBox`), and so does a
|
|
2154
|
+
* short list set whole (`shortListBoxAt`). */
|
|
2087
2155
|
const tryPlacePendingFloatsOnCurrentPage = (preferTop = false, nextBlockIdx, anyPosition = false) => {
|
|
2088
2156
|
if (pendingFloats.length === 0)
|
|
2089
2157
|
return;
|
|
2090
2158
|
const page = doc.pages[cursor.pageIndex];
|
|
2091
|
-
const box = nextBlockIdx !== undefined ? keepTogetherBoxAt(nextBlockIdx) : null;
|
|
2159
|
+
const box = nextBlockIdx !== undefined ? (keepTogetherBoxAt(nextBlockIdx) ?? shortListBoxAt(nextBlockIdx)) : null;
|
|
2092
2160
|
for (let i = 0; i < pendingFloats.length;) {
|
|
2093
2161
|
if (heldBack(i)) {
|
|
2094
2162
|
i++;
|
|
@@ -2848,6 +2916,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
2848
2916
|
// setting it one line shorter, #662): painted with it too.
|
|
2849
2917
|
if (m.letterSpacingPx !== undefined)
|
|
2850
2918
|
blk.letterSpacing = m.letterSpacingPx;
|
|
2919
|
+
if (m.runtTracking !== undefined)
|
|
2920
|
+
blk.runtFix = { tracking: m.runtTracking };
|
|
2851
2921
|
blk.lines = resetLinePositions(raggedLooseLines(m.measured.lines, noteStyle.textAlign), noteStyle.lineHeightPx).map((line) => ({
|
|
2852
2922
|
...line,
|
|
2853
2923
|
bbox: createBoundingBox(line.bbox.x + x, line.bbox.y + y, line.bbox.width, line.bbox.height),
|
|
@@ -2979,6 +3049,70 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
2979
3049
|
let inlineGapOwed = null;
|
|
2980
3050
|
/** The pending spacing a heading, a display formula or a box at `idx`
|
|
2981
3051
|
* collapses its top margin with (see `inlineGapOwed`). */
|
|
3052
|
+
/**
|
|
3053
|
+
* What a heading that opens a column keeps of its space above (#706),
|
|
3054
|
+
* 0 when it keeps none. `s0` is the space it takes above it after a
|
|
3055
|
+
* paragraph of body text, `S` its height plus its bottom margin as the
|
|
3056
|
+
* snap reads them, `u` the column's used height:
|
|
3057
|
+
*
|
|
3058
|
+
* kept = s0 − (snap(u + s0 + S) − snap(u + S))
|
|
3059
|
+
*
|
|
3060
|
+
* the whole grid lines the column head saves are dropped and the rest
|
|
3061
|
+
* stays. `kept` is less than a grid line and `u + kept + S` never passes
|
|
3062
|
+
* `snap(u + S)`, so the box's foot stays on its grid line. A run of
|
|
3063
|
+
* headings (the first does not snap because a heading follows it) reads
|
|
3064
|
+
* as one block: `S` runs from the first heading's top to the last one's
|
|
3065
|
+
* foot plus its bottom margin, the margins between them collapsed as the
|
|
3066
|
+
* placement loop collapses them, and `kept` goes above the first. A run
|
|
3067
|
+
* with a designed, page-span, hidden or `lineSpan` heading in it, or one
|
|
3068
|
+
* whose last heading does not snap, keeps today's placement; so does a
|
|
3069
|
+
* heading whose snapped box does not fit the column.
|
|
3070
|
+
*/
|
|
3071
|
+
const columnHeadKept = (blockIdx, rawBlock, usedHeight, height, style, snaps, col, ctx) => {
|
|
3072
|
+
let S;
|
|
3073
|
+
if (snaps) {
|
|
3074
|
+
S = height + style.marginBottomPx;
|
|
3075
|
+
}
|
|
3076
|
+
else {
|
|
3077
|
+
const own = headingLevels.forBlock(rawBlock);
|
|
3078
|
+
const ownSnaps = own?.snapToGrid ?? resolved.headings.snapToGrid;
|
|
3079
|
+
if (!own || !ownSnaps || own.advancedDesign.enabled || nextNonMarkerBlock(contentBlocks, blockIdx)?.type !== 'heading')
|
|
3080
|
+
return 0;
|
|
3081
|
+
let run = height;
|
|
3082
|
+
let pending = style.marginBottomPx;
|
|
3083
|
+
let closed;
|
|
3084
|
+
for (let j = blockIdx + 1; j < contentBlocks.length; j++) {
|
|
3085
|
+
const b = contentBlocks[j];
|
|
3086
|
+
if (isMarkerBlock(b))
|
|
3087
|
+
continue;
|
|
3088
|
+
const lvl = b.type === 'heading' ? headingLevels.forBlock(b) : undefined;
|
|
3089
|
+
if (!lvl || lvl.span === 'page' || lvl.advancedDesign.enabled || headingIsHidden(b, lvl))
|
|
3090
|
+
return 0;
|
|
3091
|
+
const m = measureContentBlock(b, j, col.bbox.width, ctx);
|
|
3092
|
+
if (!m || m.kind.vdtType !== 'heading' || m.kind.style.lineSpan !== undefined)
|
|
3093
|
+
return 0;
|
|
3094
|
+
const st = m.kind.style;
|
|
3095
|
+
run += Math.max(pending, st.marginTopPx) + m.measured.lines.length * st.lineHeightPx;
|
|
3096
|
+
if (nextNonMarkerBlock(contentBlocks, j)?.type === 'heading') {
|
|
3097
|
+
pending = st.marginBottomPx;
|
|
3098
|
+
continue;
|
|
3099
|
+
}
|
|
3100
|
+
if (lvl.snapToGrid ?? resolved.headings.snapToGrid)
|
|
3101
|
+
closed = run + st.marginBottomPx;
|
|
3102
|
+
break;
|
|
3103
|
+
}
|
|
3104
|
+
if (closed === undefined)
|
|
3105
|
+
return 0;
|
|
3106
|
+
S = closed;
|
|
3107
|
+
}
|
|
3108
|
+
const snap = (x) => Math.ceil((x - 0.01) / baselineGrid) * baselineGrid;
|
|
3109
|
+
const s0 = Math.max(ctx.bodyStyle.marginBottomPx, style.marginTopPx);
|
|
3110
|
+
const foot = snap(usedHeight + S);
|
|
3111
|
+
if (foot > col.bbox.height + FIT_EPS)
|
|
3112
|
+
return 0;
|
|
3113
|
+
const kept = s0 - (snap(usedHeight + s0 + S) - foot);
|
|
3114
|
+
return kept > 0.01 ? kept : 0;
|
|
3115
|
+
};
|
|
2982
3116
|
const pendingBeforeSelfSnapping = (idx) => inlineGapOwed && inlineGapOwed.afterIdx === idx - 1 && pendingSpacing === inlineGapOwed.pending
|
|
2983
3117
|
? inlineGapOwed.exact
|
|
2984
3118
|
: pendingSpacing;
|
|
@@ -3324,7 +3458,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3324
3458
|
// The cut is measured from under the float bands the proposing pass
|
|
3325
3459
|
// had at the band's head, which may not have landed yet.
|
|
3326
3460
|
const top = Math.max(bandTop(cols), bareBandTop(cols, floatHeadOf) + (cap.headPx ?? 0));
|
|
3327
|
-
|
|
3461
|
+
// (A trailing cap counts the lines of its band's own leading, #711.)
|
|
3462
|
+
applyBandCap(cols, cap.lines * (cap.pitchPx ?? baselineGrid), uncappedBottoms, cap.zone, cap.kind === 'trailing', top);
|
|
3328
3463
|
cappedBandColumns.set(spanIndex, cols);
|
|
3329
3464
|
activeCap = { spanIndex, pageIndex: page.index, band };
|
|
3330
3465
|
bandCapsApplied.add(spanIndex);
|
|
@@ -3349,7 +3484,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3349
3484
|
* the displaced text (see {@link bandCapLinesAroundZone}) — the box then
|
|
3350
3485
|
* fits on the page, under its columns, rather than opening a page alone.
|
|
3351
3486
|
*/
|
|
3352
|
-
const proposeTrailingCap = (boundaryIndex, zone) => {
|
|
3487
|
+
const proposeTrailingCap = (boundaryIndex, zone, closeLevel = false) => {
|
|
3353
3488
|
const balancingCfg = resolved.headings.balancing;
|
|
3354
3489
|
if (!balancingCfg.enabled || !balancingCfg.trailing)
|
|
3355
3490
|
return;
|
|
@@ -3385,9 +3520,25 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3385
3520
|
if (!bandStart || !registeredBand || registeredBand.pageIndex !== page.index || registeredBand.band !== band)
|
|
3386
3521
|
return;
|
|
3387
3522
|
const bottoms = cols.map((c) => c.bbox.y + (c.bbox.height - c.availableHeight));
|
|
3388
|
-
|
|
3389
|
-
|
|
3523
|
+
// The cut counts lines of the band's own text (#711,
|
|
3524
|
+
// `trailingStep: 'lines'`): an index or a list of references set on a
|
|
3525
|
+
// leading of its own is cut, and retried, by whole lines of that
|
|
3526
|
+
// leading, where a cut on the body grid lets a line more into one
|
|
3527
|
+
// column and each retry lowers it by more than a line of the band. A
|
|
3528
|
+
// band of body text has the grid for its pitch.
|
|
3529
|
+
const pitch = balancingCfg.trailingStep === 'grid' ? baselineGrid : bandLinePitch(cols, baselineGrid);
|
|
3530
|
+
const aroundZone = zone ? bandCapLinesAroundZone(cols, pitch, zone, (c) => columnBottom(c, uncappedBottoms)) : null;
|
|
3531
|
+
if (aroundZone === null && Math.max(...bottoms) - Math.min(...bottoms) <= baselineGrid + 0.5) {
|
|
3532
|
+
// A band that is level already needs no cap and no second pass, but
|
|
3533
|
+
// it ends here all the same: where the boundary closes the flow of
|
|
3534
|
+
// its page, its columns are cut on the grid line under its text, as
|
|
3535
|
+
// a delivered cap would leave them, so the column rule stops with
|
|
3536
|
+
// the text and not at the page foot (#713). Nothing is to be filled
|
|
3537
|
+
// up to the cut, so the columns are not flagged `trailingCap`.
|
|
3538
|
+
if (closeLevel)
|
|
3539
|
+
closeLevelBand(cols, bottoms);
|
|
3390
3540
|
return;
|
|
3541
|
+
}
|
|
3391
3542
|
// Float bands reserved at the columns' feet are the band's content too:
|
|
3392
3543
|
// the level cut must leave them room under the text (a figure placed
|
|
3393
3544
|
// before a span box then anchors to the cut, see `anchorToCap`). A band
|
|
@@ -3405,24 +3556,43 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3405
3556
|
const top = bandTop(cols);
|
|
3406
3557
|
const floatHeads = cols
|
|
3407
3558
|
.filter((c) => c.blocks.length === 0 && reservedOf(c).top > 0)
|
|
3408
|
-
.map((c) => Math.ceil((c.bbox.y - top - 0.01) /
|
|
3559
|
+
.map((c) => Math.ceil((c.bbox.y - top - 0.01) / pitch));
|
|
3409
3560
|
// So does one set under a page-span opener at the head of the opener's
|
|
3410
3561
|
// own column (#639).
|
|
3411
3562
|
for (const c of cols) {
|
|
3412
3563
|
if (c.headFloatFoot !== undefined)
|
|
3413
|
-
floatHeads.push(Math.ceil((c.headFloatFoot - top - 0.01) /
|
|
3564
|
+
floatHeads.push(Math.ceil((c.headFloatFoot - top - 0.01) / pitch));
|
|
3414
3565
|
}
|
|
3415
3566
|
bandCapProposals.set(boundaryIndex, {
|
|
3416
3567
|
kind: 'trailing',
|
|
3417
3568
|
startContentIndex: bandStart.contentIndex,
|
|
3418
3569
|
startPart: bandStart.part,
|
|
3419
3570
|
...(bandStart.visit > 0 ? { startVisit: bandStart.visit } : {}),
|
|
3420
|
-
lines: aroundZone ?? Math.max(bandCapLines(cols,
|
|
3571
|
+
lines: aroundZone ?? Math.max(bandCapLines(cols, pitch, footBands), ...floatHeads),
|
|
3572
|
+
...(pitch !== baselineGrid ? { pitchPx: pitch, retryLimit: capRetryLimit(pitch, baselineGrid) } : {}),
|
|
3421
3573
|
retries: 0,
|
|
3422
3574
|
...(aroundZone !== null ? { zone } : {}),
|
|
3423
3575
|
...capHeadPx(cols),
|
|
3424
3576
|
});
|
|
3425
3577
|
};
|
|
3578
|
+
/** Cut the columns of a closing band that ends level on the grid line
|
|
3579
|
+
* under its lowest text (#713). What a column paints below its used
|
|
3580
|
+
* height counts too (a tail whose negative margin snapped the flow back
|
|
3581
|
+
* above its last line): the renderers clip a column to its box. The true
|
|
3582
|
+
* bottoms go to `uncappedBottoms`, as under a delivered cap, so notes and
|
|
3583
|
+
* floats keep reading the page's foot. */
|
|
3584
|
+
const closeLevelBand = (cols, bottoms) => {
|
|
3585
|
+
const top = bandTop(cols);
|
|
3586
|
+
let lowest = Math.max(...bottoms);
|
|
3587
|
+
for (const c of cols) {
|
|
3588
|
+
for (const b of c.blocks) {
|
|
3589
|
+
if (!b.hidden)
|
|
3590
|
+
lowest = Math.max(lowest, paintedBottom(b), b.bbox.y + b.bbox.height);
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
const lines = Math.ceil((lowest - top - 0.01) / baselineGrid);
|
|
3594
|
+
applyBandCap(cols, lines * baselineGrid, uncappedBottoms, undefined, false, top);
|
|
3595
|
+
};
|
|
3426
3596
|
/** Close the flow at a chapter-level boundary (block `boundaryIndex`):
|
|
3427
3597
|
* floats take the page's free slots, the closing band is levelled, the
|
|
3428
3598
|
* page is marked as an explicit break, and every float still pending is
|
|
@@ -3458,7 +3628,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3458
3628
|
pendingFloats.splice(i, 1);
|
|
3459
3629
|
}
|
|
3460
3630
|
tryPlacePendingFloatsOnCurrentPage();
|
|
3461
|
-
proposeTrailingCap(boundaryIndex);
|
|
3631
|
+
proposeTrailingCap(boundaryIndex, undefined, true);
|
|
3462
3632
|
markForcedBreak();
|
|
3463
3633
|
hugClosingText();
|
|
3464
3634
|
drainPendingFloats();
|
|
@@ -3613,6 +3783,60 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
3613
3783
|
n++;
|
|
3614
3784
|
return n;
|
|
3615
3785
|
};
|
|
3786
|
+
/**
|
|
3787
|
+
* An index group divided between two columns keeps at least
|
|
3788
|
+
* `index.groups.splitMinEntries` entries on each side (#712). `entry` is
|
|
3789
|
+
* the entry block about to leave `col` (it does not fit, or would be
|
|
3790
|
+
* divided between its lines); `k` entries of its group already close the
|
|
3791
|
+
* column and `r` are still to place, this one included. Too few behind
|
|
3792
|
+
* (`k < min`): the `k` go on with it. Too few ahead (`r < min`): enough of
|
|
3793
|
+
* them go on for the next column to open with `min`, and all of them when
|
|
3794
|
+
* that would leave too few behind. The blocks taken off the column are
|
|
3795
|
+
* returned in column order (the caller rewinds to the first), with the
|
|
3796
|
+
* run of headings they would strand; empty when the rule asks for
|
|
3797
|
+
* nothing or cannot be met: the group's entries are all the column holds
|
|
3798
|
+
* under its headings (they would open the next column as they open this
|
|
3799
|
+
* one), or the entry that would lead the move is the rest of one begun
|
|
3800
|
+
* in the column before.
|
|
3801
|
+
*/
|
|
3802
|
+
const rollbackIndexGroup = (col, entry, min) => {
|
|
3803
|
+
const info = entry.index;
|
|
3804
|
+
if (!info || min <= 1 || info.groupIndex === undefined || info.groupPlace === undefined || info.groupSize === undefined)
|
|
3805
|
+
return [];
|
|
3806
|
+
const sameGroup = (b) => {
|
|
3807
|
+
const raw = b.contentIndex !== undefined ? contentBlocks[b.contentIndex] : undefined;
|
|
3808
|
+
return raw?.index !== undefined && raw.index.groupIndex === info.groupIndex && raw.sourceStart === entry.sourceStart;
|
|
3809
|
+
};
|
|
3810
|
+
let k = 0;
|
|
3811
|
+
for (let j = col.blocks.length - 1; j >= 0 && sameGroup(col.blocks[j]); j--)
|
|
3812
|
+
k++;
|
|
3813
|
+
if (k === 0)
|
|
3814
|
+
return [];
|
|
3815
|
+
const r = info.groupSize - info.groupPlace;
|
|
3816
|
+
let take = 0;
|
|
3817
|
+
if (k < min)
|
|
3818
|
+
take = k;
|
|
3819
|
+
else if (r < min)
|
|
3820
|
+
take = k - (min - r) < min ? k : min - r;
|
|
3821
|
+
if (take === 0)
|
|
3822
|
+
return [];
|
|
3823
|
+
// Nothing but the group under the column's headings: it stays.
|
|
3824
|
+
const above = col.blocks.slice(0, col.blocks.length - k);
|
|
3825
|
+
if (take === k && above.every((b) => isFreeHeading(b) || b.hidden))
|
|
3826
|
+
return [];
|
|
3827
|
+
// The rest of an entry begun in the column before cannot move back.
|
|
3828
|
+
if (col.blocks[col.blocks.length - take].id.includes('-cont-'))
|
|
3829
|
+
return [];
|
|
3830
|
+
let left = take;
|
|
3831
|
+
const popped = rollbackTrailingBlocks(col, doc.blocks, () => left-- > 0);
|
|
3832
|
+
// The headings the group stood under go with it.
|
|
3833
|
+
const heads = take === k ? rollbackHeadings(col) : [];
|
|
3834
|
+
// The space above the blocks taken off is the column's again.
|
|
3835
|
+
const last = col.blocks[col.blocks.length - 1];
|
|
3836
|
+
if (last)
|
|
3837
|
+
col.availableHeight = col.bbox.y + col.bbox.height - (last.bbox.y + last.bbox.height);
|
|
3838
|
+
return [...heads, ...popped];
|
|
3839
|
+
};
|
|
3616
3840
|
/** Stamp a callout frame's content index and source range: the whole
|
|
3617
3841
|
* fence (opening to closing marker) for an unsplit box; for a fragment
|
|
3618
3842
|
* of a split box, from the fence start (first fragment) or the first
|
|
@@ -4090,6 +4314,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4090
4314
|
* to the head or foot of a page, the bands it was floated to.
|
|
4091
4315
|
*/
|
|
4092
4316
|
const placeSpanFloatsAtCut = (page, capActiveHere) => {
|
|
4317
|
+
// Not on an opener page that takes no float (#749).
|
|
4318
|
+
if (openerFloatRule === 'avoid' && openerPages.has(page))
|
|
4319
|
+
return false;
|
|
4093
4320
|
let placedAny = false;
|
|
4094
4321
|
for (let i = 0; i < pendingFloats.length;) {
|
|
4095
4322
|
const f = pendingFloats[i];
|
|
@@ -4135,6 +4362,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4135
4362
|
offsetResourceBlockToAbsolute(built.block.resourceBlock, 0, built.block.bbox.y);
|
|
4136
4363
|
built.block.contentIndex = f.firstBlockIdx;
|
|
4137
4364
|
doc.blocks.push(built.block);
|
|
4365
|
+
noteOpenerFloat(page, f);
|
|
4138
4366
|
floatsPlaced++;
|
|
4139
4367
|
placedAny = true;
|
|
4140
4368
|
pendingFloats.splice(i, 1);
|
|
@@ -4393,8 +4621,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4393
4621
|
if (levelBefore && !capActive && !proposedSpan) {
|
|
4394
4622
|
// The box leaves an uncapped band: level it behind the box (a
|
|
4395
4623
|
// trailing cap, resolved after balancing) and keep balancing from
|
|
4396
|
-
// stretching its last column to the page bottom meanwhile.
|
|
4397
|
-
|
|
4624
|
+
// stretching its last column to the page bottom meanwhile. A band
|
|
4625
|
+
// that is level already is closed at its text (#713).
|
|
4626
|
+
proposeTrailingCap(startIdx, undefined, true);
|
|
4398
4627
|
markForcedBreak();
|
|
4399
4628
|
}
|
|
4400
4629
|
else if (capActive && cap?.kind === 'trailing') {
|
|
@@ -4921,6 +5150,65 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4921
5150
|
return true;
|
|
4922
5151
|
}
|
|
4923
5152
|
};
|
|
5153
|
+
/** Whether a resource set in the text asks for its caption in the side
|
|
5154
|
+
* column (#729): `placement.captionSide` on a `span: 'column'` embed,
|
|
5155
|
+
* `layout.inlineCaptionSide` on, a horizontal page, and no text wrapped
|
|
5156
|
+
* round it. The side column and its room are looked at where the block
|
|
5157
|
+
* is placed ({@link measureInlineAside}). */
|
|
5158
|
+
const inlineAsideWanted = (resource, type, page) => {
|
|
5159
|
+
if (!resource || !resolved.layout.inlineCaptionSide || pageIsVertical(page))
|
|
5160
|
+
return false;
|
|
5161
|
+
const placement = resolveResourcePlacement(resource, type);
|
|
5162
|
+
if (!placement.captionSide || placement.span !== 'column')
|
|
5163
|
+
return false;
|
|
5164
|
+
return resolveResourceWrap(resource, type, resolved.layout.wrap) === undefined;
|
|
5165
|
+
};
|
|
5166
|
+
/** Whether the side column `sc` is free over the band a caption
|
|
5167
|
+
* `asideHeight` tall takes beside an embed placed next in `c`: the side
|
|
5168
|
+
* stack ends above the embed's top, the band ends inside the side
|
|
5169
|
+
* column, and no obstacle (a heading design, another embed's caption)
|
|
5170
|
+
* stands in it or within the float gap of it. */
|
|
5171
|
+
const inlineAsideFree = (c, sc, spacing, asideHeight) => {
|
|
5172
|
+
const top = c.bbox.y + (c.bbox.height - c.availableHeight) + (c.blocks.length === 0 ? 0 : spacing);
|
|
5173
|
+
const bottom = top + asideHeight;
|
|
5174
|
+
if (sideUsedBottom(sc) > top + 0.5)
|
|
5175
|
+
return false;
|
|
5176
|
+
if (bottom > sc.bbox.y + sc.bbox.height + 0.5)
|
|
5177
|
+
return false;
|
|
5178
|
+
return !(sideObstacles.get(sc) ?? []).some((o) => o.bottom + floatGapPx > top + 0.5 && o.top - floatGapPx < bottom - 0.5);
|
|
5179
|
+
};
|
|
5180
|
+
/** The embed measured for column `c` with its caption and note in the
|
|
5181
|
+
* band's float-only side column, level with the body's top (#729), or
|
|
5182
|
+
* `null` when the band has no such column or it is not free there: the
|
|
5183
|
+
* caption then stays under the body. */
|
|
5184
|
+
const measureInlineAside = (raw, blockIdx, c, page, ctx, base, spacing) => {
|
|
5185
|
+
if (c.kind === 'span' || c.kind === 'side')
|
|
5186
|
+
return null;
|
|
5187
|
+
const sideCol = sideColumnOf(page, c.band ?? 0);
|
|
5188
|
+
if (!sideCol || sideCol.bbox.width <= 0.5)
|
|
5189
|
+
return null;
|
|
5190
|
+
const opts = { captionAside: { dx: sideCol.bbox.x - c.bbox.x, width: sideCol.bbox.width } };
|
|
5191
|
+
const block = measureContentBlock(raw, blockIdx, c.bbox.width, ctx, { ...base, ...opts });
|
|
5192
|
+
if (!block?.resourceBlock || block.asideHeight === undefined || block.resourceBlock.rotation)
|
|
5193
|
+
return null;
|
|
5194
|
+
if (!inlineAsideFree(c, sideCol, spacing, block.asideHeight))
|
|
5195
|
+
return null;
|
|
5196
|
+
return { block, opts, sideCol, col: c };
|
|
5197
|
+
};
|
|
5198
|
+
/** The band an embed's side caption takes in the side column, recorded
|
|
5199
|
+
* as an obstacle of its stack: side floats and side boxes set later go
|
|
5200
|
+
* above it when they fit there, else under it. */
|
|
5201
|
+
const markInlineAside = (blk, sideCol, asideHeight) => {
|
|
5202
|
+
if (!(asideHeight > 0))
|
|
5203
|
+
return;
|
|
5204
|
+
const mark = { owner: blk, top: blk.bbox.y, bottom: blk.bbox.y + asideHeight };
|
|
5205
|
+
const list = sideObstacles.get(sideCol);
|
|
5206
|
+
if (list)
|
|
5207
|
+
list.push(mark);
|
|
5208
|
+
else
|
|
5209
|
+
sideObstacles.set(sideCol, [mark]);
|
|
5210
|
+
sideObstacleColumn.set(blk, sideCol);
|
|
5211
|
+
};
|
|
4924
5212
|
/**
|
|
4925
5213
|
* An inline table (`::resource` placed `here`) that does not fit the room
|
|
4926
5214
|
* left in its column (#634), by its style's `overflow` when
|
|
@@ -4937,10 +5225,12 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4937
5225
|
* table is placed as one block by the caller (it fits, or the rule does
|
|
4938
5226
|
* not apply), `'dropped'`, or `'placed'`: every slice is placed and the
|
|
4939
5227
|
* cursor sits in the column of the last one, which the caller snaps
|
|
4940
|
-
* under. `blk` is the first slice's block, filled in here.
|
|
5228
|
+
* under. `blk` is the first slice's block, filled in here. With
|
|
5229
|
+
* `asideWanted` the first slice sets its caption in the side column when
|
|
5230
|
+
* that is free beside it (#729); the continuations are set as ever.
|
|
4941
5231
|
*/
|
|
4942
5232
|
const MIN_HEAD_ROWS = 2;
|
|
4943
|
-
const placeInlineTableSlices = (raw, blockIdx, blk, ctx, styleOverride, resource, wholeHeight, spacingBefore) => {
|
|
5233
|
+
const placeInlineTableSlices = (raw, blockIdx, blk, ctx, styleOverride, resource, wholeHeight, spacingBefore, asideWanted = false) => {
|
|
4944
5234
|
const style = pickTableStyle(resolved, resource.table?.styleId);
|
|
4945
5235
|
if (!style.splitInline || pageIsVertical(doc.pages[cursor.pageIndex]))
|
|
4946
5236
|
return 'whole';
|
|
@@ -4988,6 +5278,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4988
5278
|
let part = 0;
|
|
4989
5279
|
let moves = 0;
|
|
4990
5280
|
let block = blk;
|
|
5281
|
+
/** Columns where the first slice's caption found no room at the side. */
|
|
5282
|
+
const asideRefused = new Set();
|
|
4991
5283
|
for (;;) {
|
|
4992
5284
|
enterBand(blockIdx, part);
|
|
4993
5285
|
let col = currentColumn(doc, cursor);
|
|
@@ -4999,8 +5291,15 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
4999
5291
|
const metrics = metricsAt(width) ?? firstMetrics;
|
|
5000
5292
|
const spacing = part === 0 && col.blocks.length > 0 ? spacingBefore : 0;
|
|
5001
5293
|
const avail = col.availableHeight - spacing;
|
|
5294
|
+
// The first slice with its caption in the side column (#729).
|
|
5295
|
+
const asideHere = asideWanted && startRow === 0 && !asideRefused.has(col)
|
|
5296
|
+
? measureInlineAside(raw, blockIdx, col, doc.pages[cursor.pageIndex], ctx, { styleOverride }, spacing)
|
|
5297
|
+
: null;
|
|
5298
|
+
const sliceAt = (s) => (asideHere
|
|
5299
|
+
? measureContentBlock(raw, blockIdx, width, ctx, { styleOverride, ...(s ? { tableSlice: s } : {}), ...asideHere.opts })
|
|
5300
|
+
: measureAt(width, s));
|
|
5002
5301
|
const restSlice = startRow > 0 ? { startRow, endRow: rowCount, continues: false } : undefined;
|
|
5003
|
-
const rest =
|
|
5302
|
+
const rest = sliceAt(restSlice);
|
|
5004
5303
|
if (!rest?.resourceBlock)
|
|
5005
5304
|
return part === 0 ? 'whole' : 'placed';
|
|
5006
5305
|
let placed = rest;
|
|
@@ -5014,7 +5313,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5014
5313
|
continue;
|
|
5015
5314
|
}
|
|
5016
5315
|
const firstBody = startRow > 0 ? Math.max(startRow, headerRows) : headerRows;
|
|
5017
|
-
const probe =
|
|
5316
|
+
const probe = sliceAt({ startRow, endRow: firstBody + 1, continues: true });
|
|
5018
5317
|
const overhead = probe?.resourceBlock ? probe.measured.totalHeight - probe.resourceBlock.bodyRect.height : 0;
|
|
5019
5318
|
// An empty column of full height (or a run of short ones behind)
|
|
5020
5319
|
// takes the smallest slice even when it overflows: a fresh page
|
|
@@ -5024,7 +5323,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5024
5323
|
floor: floorOf(startRow),
|
|
5025
5324
|
force,
|
|
5026
5325
|
split: overflow === 'split',
|
|
5027
|
-
fits: (s) => (
|
|
5326
|
+
fits: (s) => (sliceAt(s)?.measured.totalHeight ?? Infinity) <= avail + FIT_EPS,
|
|
5028
5327
|
});
|
|
5029
5328
|
if (!slice) {
|
|
5030
5329
|
// Not even the head rows fit: the (rest of the) table starts in
|
|
@@ -5034,11 +5333,17 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5034
5333
|
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onAtomicNewPage(minHeightAt(width, startRow)));
|
|
5035
5334
|
continue;
|
|
5036
5335
|
}
|
|
5037
|
-
const m =
|
|
5336
|
+
const m = sliceAt(slice);
|
|
5038
5337
|
if (!m?.resourceBlock)
|
|
5039
5338
|
return part === 0 ? 'whole' : 'placed';
|
|
5040
5339
|
placed = m;
|
|
5041
5340
|
}
|
|
5341
|
+
// The slice's caption (a line longer with its continuation suffix,
|
|
5342
|
+
// perhaps) must still find the side column free.
|
|
5343
|
+
if (asideHere && (placed.asideHeight === undefined || !inlineAsideFree(col, asideHere.sideCol, spacing, placed.asideHeight))) {
|
|
5344
|
+
asideRefused.add(col);
|
|
5345
|
+
continue;
|
|
5346
|
+
}
|
|
5042
5347
|
// The slice's block: the first one is the caller's.
|
|
5043
5348
|
if (part > 0) {
|
|
5044
5349
|
block = createVDTBlock(`block-${blockIdCounter++}`, 'resource', blk.fontString, blk.color, blk.textAlign);
|
|
@@ -5065,6 +5370,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5065
5370
|
col.availableHeight -= spacing;
|
|
5066
5371
|
placeBlockInColumn(block, height, col, cursor);
|
|
5067
5372
|
offsetResourceBlockToAbsolute(rb, block.bbox.x, block.bbox.y);
|
|
5373
|
+
if (asideHere && placed.asideHeight !== undefined)
|
|
5374
|
+
markInlineAside(block, asideHere.sideCol, placed.asideHeight);
|
|
5068
5375
|
doc.blocks.push(block);
|
|
5069
5376
|
enterBand(blockIdx, part);
|
|
5070
5377
|
if (!slice?.continues)
|
|
@@ -5316,6 +5623,188 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5316
5623
|
slackWeight: body.slackWeight,
|
|
5317
5624
|
}).splitAt > 0;
|
|
5318
5625
|
};
|
|
5626
|
+
// --- Short lists kept whole (`bodyText.shortListSplit`, #749) -------------
|
|
5627
|
+
const shortListRule = resolved.bodyText.shortListSplit;
|
|
5628
|
+
/** The short lists of the running text by the content index of their
|
|
5629
|
+
* first item (`null`: a block that opens none). */
|
|
5630
|
+
const shortLists = new Map();
|
|
5631
|
+
/**
|
|
5632
|
+
* The short list content block `idx` opens: a run of list items (seen
|
|
5633
|
+
* through container markers, its nested lists included) of up to
|
|
5634
|
+
* `bodyText.shortListMaxItems` items, `idx` being its first. Not the
|
|
5635
|
+
* entries of the contents or of an index, which are set as list items.
|
|
5636
|
+
*/
|
|
5637
|
+
const shortListFrom = (idx) => {
|
|
5638
|
+
const known = shortLists.get(idx);
|
|
5639
|
+
if (known !== undefined)
|
|
5640
|
+
return known ?? undefined;
|
|
5641
|
+
const isItem = (b) => b?.type === 'listItem' && b.toc === undefined && b.index === undefined;
|
|
5642
|
+
let found = null;
|
|
5643
|
+
if (isItem(contentBlocks[idx]) && prevNonMarkerBlock(contentBlocks, idx)?.type !== 'listItem') {
|
|
5644
|
+
const items = [];
|
|
5645
|
+
let i = idx;
|
|
5646
|
+
for (; i < contentBlocks.length; i++) {
|
|
5647
|
+
const b = contentBlocks[i];
|
|
5648
|
+
if (isMarkerBlock(b))
|
|
5649
|
+
continue;
|
|
5650
|
+
if (!isItem(b))
|
|
5651
|
+
break;
|
|
5652
|
+
items.push(i);
|
|
5653
|
+
if (items.length > resolved.bodyText.shortListMaxItems)
|
|
5654
|
+
break;
|
|
5655
|
+
}
|
|
5656
|
+
if (items.length <= resolved.bodyText.shortListMaxItems)
|
|
5657
|
+
found = { items };
|
|
5658
|
+
}
|
|
5659
|
+
shortLists.set(idx, found);
|
|
5660
|
+
return found ?? undefined;
|
|
5661
|
+
};
|
|
5662
|
+
/** The room a short list takes in a column `width` wide, from the top of
|
|
5663
|
+
* its first line to the foot of its last (the space above it aside),
|
|
5664
|
+
* and its lines, for the notes they cite. Undefined when an item
|
|
5665
|
+
* cannot be measured. */
|
|
5666
|
+
const shortListNeed = (list, width, ctx) => {
|
|
5667
|
+
let height = 0;
|
|
5668
|
+
const lines = [];
|
|
5669
|
+
let prev;
|
|
5670
|
+
for (const idx of list.items) {
|
|
5671
|
+
const raw = contentBlocks[idx];
|
|
5672
|
+
const item = measureContentBlock(raw, idx, width, ctx);
|
|
5673
|
+
if (!item)
|
|
5674
|
+
return undefined;
|
|
5675
|
+
if (prev) {
|
|
5676
|
+
height += listItemGapPx({ spacingPx: listItemSpacingPx(prev, ctx.resolved), depth: prev.depth ?? 1 }, { spacingPx: listItemSpacingPx(raw, ctx.resolved), depth: raw.depth ?? 1 });
|
|
5677
|
+
}
|
|
5678
|
+
height += item.measured.lines.length * item.kind.style.lineHeightPx;
|
|
5679
|
+
lines.push(...item.measured.lines);
|
|
5680
|
+
prev = raw;
|
|
5681
|
+
}
|
|
5682
|
+
return { height, lines };
|
|
5683
|
+
};
|
|
5684
|
+
/**
|
|
5685
|
+
* The room the floats text block `blockIdx` cites would take from the
|
|
5686
|
+
* foot of `col` once their citing lines are placed: for each one still
|
|
5687
|
+
* held back for it, the band of its first slot on the page, when that is
|
|
5688
|
+
* a foot band over `col` that the room the block leaves under it
|
|
5689
|
+
* (`roomAfter`) still holds. Read before the block is placed, so an
|
|
5690
|
+
* estimate: the colon line of a short list set whole counts it, since
|
|
5691
|
+
* the figure that line cites takes the foot of the column right after
|
|
5692
|
+
* it, where the list would have gone.
|
|
5693
|
+
*/
|
|
5694
|
+
const citedFootTake = (blockIdx, col, roomAfter) => {
|
|
5695
|
+
const page = doc.pages[cursor.pageIndex];
|
|
5696
|
+
if (openerFloatRule === 'avoid' && openerPages.has(page))
|
|
5697
|
+
return 0;
|
|
5698
|
+
let take = 0;
|
|
5699
|
+
for (const [id, gate] of citationGates) {
|
|
5700
|
+
if (gate.blockIdx !== blockIdx)
|
|
5701
|
+
continue;
|
|
5702
|
+
const f = pendingFloats.find((p) => p.resourceId === id);
|
|
5703
|
+
const slot = f ? enumerateCurrentPageSlots(page, cursor.columnIndex, f, capKindOf, openerHeadOf)[0] : undefined;
|
|
5704
|
+
if (!f || !slot || slot.side || slot.position !== 'bottom' || !slot.cols.includes(col))
|
|
5705
|
+
continue;
|
|
5706
|
+
const probe = probeFloatBand(page, f, slot.cols, slot.position, slot.pageSpan, false);
|
|
5707
|
+
if (!probe)
|
|
5708
|
+
continue;
|
|
5709
|
+
const band = col.availableHeight - availableAfterBand(col, 'bottom', probe, false);
|
|
5710
|
+
if (band <= roomAfter + FIT_EPS)
|
|
5711
|
+
take = Math.max(take, band);
|
|
5712
|
+
}
|
|
5713
|
+
return take;
|
|
5714
|
+
};
|
|
5715
|
+
/** The short list item `idx` belongs to, and its place in it. */
|
|
5716
|
+
const shortListItemAt = (idx) => {
|
|
5717
|
+
if (contentBlocks[idx]?.type !== 'listItem')
|
|
5718
|
+
return undefined;
|
|
5719
|
+
let start = idx;
|
|
5720
|
+
for (let i = idx - 1, seen = 0; i >= 0 && seen <= resolved.bodyText.shortListMaxItems; i--) {
|
|
5721
|
+
const b = contentBlocks[i];
|
|
5722
|
+
if (isMarkerBlock(b))
|
|
5723
|
+
continue;
|
|
5724
|
+
if (b.type !== 'listItem')
|
|
5725
|
+
break;
|
|
5726
|
+
start = i;
|
|
5727
|
+
seen++;
|
|
5728
|
+
}
|
|
5729
|
+
const list = shortListFrom(start);
|
|
5730
|
+
const item = list ? list.items.indexOf(idx) : -1;
|
|
5731
|
+
return list && item >= 0 ? { list, item } : undefined;
|
|
5732
|
+
};
|
|
5733
|
+
/**
|
|
5734
|
+
* Under `'avoid'`, the short list content block `idx` opens or goes on
|
|
5735
|
+
* with, as the floats offered a slot right before it see a keep-together
|
|
5736
|
+
* box (`slotStarvesBox`): its height at a column width, from that item
|
|
5737
|
+
* on. A float yields to it when the cursor's column holds the list whole
|
|
5738
|
+
* and would not with the float: the figure a list's own lead-in cites
|
|
5739
|
+
* would otherwise take the foot of the column once its citing line is
|
|
5740
|
+
* placed, and cut the list under it.
|
|
5741
|
+
*/
|
|
5742
|
+
const shortListBoxAt = (idx) => {
|
|
5743
|
+
if (shortListRule !== 'avoid')
|
|
5744
|
+
return null;
|
|
5745
|
+
const at = shortListItemAt(idx);
|
|
5746
|
+
if (!at)
|
|
5747
|
+
return null;
|
|
5748
|
+
const ctx = partPlan.byBlock[idx] ? partMeasureCtx : sectionMeasureCtx(sectionPlan.byBlock[idx]);
|
|
5749
|
+
const rest = { items: at.list.items.slice(at.item) };
|
|
5750
|
+
const heights = new Map();
|
|
5751
|
+
return {
|
|
5752
|
+
stays: true,
|
|
5753
|
+
heightAt: (width) => {
|
|
5754
|
+
const key = Math.round(width * 100);
|
|
5755
|
+
let h = heights.get(key);
|
|
5756
|
+
if (h === undefined) {
|
|
5757
|
+
const need = shortListNeed(rest, width, ctx);
|
|
5758
|
+
h = need ? need.height + pendingSpacing : 0;
|
|
5759
|
+
heights.set(key, h);
|
|
5760
|
+
}
|
|
5761
|
+
return h;
|
|
5762
|
+
},
|
|
5763
|
+
};
|
|
5764
|
+
};
|
|
5765
|
+
/** A `shortListSplit` warning for each short list whose items the pass
|
|
5766
|
+
* set in more than one column: all of them under `'warn'`, under
|
|
5767
|
+
* `'avoid'` the ones no column could hold whole. */
|
|
5768
|
+
const shortListWarnings = () => {
|
|
5769
|
+
if (shortListRule === 'allow')
|
|
5770
|
+
return [];
|
|
5771
|
+
// Where each list item of the running text landed (a box's children
|
|
5772
|
+
// carry `containerId`).
|
|
5773
|
+
const placed = new Map();
|
|
5774
|
+
for (const page of doc.pages) {
|
|
5775
|
+
for (const c of page.columns) {
|
|
5776
|
+
for (const b of c.blocks) {
|
|
5777
|
+
if (b.type !== 'listItem' || b.containerId !== undefined || b.contentIndex === undefined)
|
|
5778
|
+
continue;
|
|
5779
|
+
const at = placed.get(b.contentIndex) ?? { pageIndex: page.index, columns: new Set() };
|
|
5780
|
+
at.columns.add(`${page.index}:${c.index}`);
|
|
5781
|
+
placed.set(b.contentIndex, at);
|
|
5782
|
+
}
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5785
|
+
const out = [];
|
|
5786
|
+
for (let idx = 0; idx < contentBlocks.length; idx++) {
|
|
5787
|
+
const list = placed.has(idx) ? shortListFrom(idx) : undefined;
|
|
5788
|
+
if (!list)
|
|
5789
|
+
continue;
|
|
5790
|
+
const columns = new Set();
|
|
5791
|
+
for (const item of list.items)
|
|
5792
|
+
for (const key of placed.get(item)?.columns ?? [])
|
|
5793
|
+
columns.add(key);
|
|
5794
|
+
if (columns.size < 2)
|
|
5795
|
+
continue;
|
|
5796
|
+
const first = contentBlocks[list.items[0]];
|
|
5797
|
+
const last = contentBlocks[list.items[list.items.length - 1]];
|
|
5798
|
+
out.push({
|
|
5799
|
+
kind: 'shortListSplit',
|
|
5800
|
+
items: list.items.length,
|
|
5801
|
+
sourceStart: first.sourceStart + bodyOffset,
|
|
5802
|
+
sourceEnd: last.sourceEnd + bodyOffset,
|
|
5803
|
+
pageIndex: placed.get(idx).pageIndex,
|
|
5804
|
+
});
|
|
5805
|
+
}
|
|
5806
|
+
return out;
|
|
5807
|
+
};
|
|
5319
5808
|
/** The page break into a page of the parity `even` asks (a spread opens
|
|
5320
5809
|
* on a verso, an even page): the page the cursor stands on, an empty
|
|
5321
5810
|
* one, is marked a parity blank and passed while its number is odd. Even
|
|
@@ -5433,6 +5922,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5433
5922
|
inlineGapOwed = pendingSpacing > 0 ? { afterIdx: blockIdx, pending: pendingSpacing, exact: owed } : null;
|
|
5434
5923
|
return undefined;
|
|
5435
5924
|
};
|
|
5925
|
+
/** The first block of the document that sets something: a heading there
|
|
5926
|
+
* opens the document's first page (`openerPages`, #749). */
|
|
5927
|
+
const firstFlowBlockIdx = contentBlocks.findIndex((b) => !isMarkerBlock(b) && b.type !== 'directive');
|
|
5436
5928
|
for (let blockIdx = 0; blockIdx < contentBlocks.length; blockIdx++) {
|
|
5437
5929
|
if (options?.shouldCancel?.())
|
|
5438
5930
|
throw new BuildCancelledError();
|
|
@@ -5606,6 +6098,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5606
6098
|
titleSourceStart,
|
|
5607
6099
|
titleSourceEnd,
|
|
5608
6100
|
}, pageIndexOffset);
|
|
6101
|
+
openerPages.add(doc.pages[cursor.pageIndex]);
|
|
5609
6102
|
flushPendingNumberingAtBoundary();
|
|
5610
6103
|
continue;
|
|
5611
6104
|
}
|
|
@@ -5774,6 +6267,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5774
6267
|
if (rawBlock.type === 'heading' && rawBlock.level) {
|
|
5775
6268
|
const level = headingLevels.forBlock(rawBlock);
|
|
5776
6269
|
const bb = level?.breakBefore;
|
|
6270
|
+
/** The heading opens its page (#749): with its own break, or as the
|
|
6271
|
+
* first block of the document. */
|
|
6272
|
+
let opensPage = blockIdx === firstFlowBlockIdx;
|
|
5777
6273
|
if (bb && bb.enabled) {
|
|
5778
6274
|
pendingSpacing = 0;
|
|
5779
6275
|
closeFlowSegment(blockIdx);
|
|
@@ -5782,6 +6278,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5782
6278
|
enforcePageParity(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, bb.parity);
|
|
5783
6279
|
}
|
|
5784
6280
|
flushPendingNumberingAtBoundary();
|
|
6281
|
+
opensPage = true;
|
|
5785
6282
|
}
|
|
5786
6283
|
// `span: 'page'` headings open a chapter band across the full content
|
|
5787
6284
|
// width. Always start on a fresh page boundary so the band sits at the
|
|
@@ -5795,7 +6292,10 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5795
6292
|
advanceToNextPageBoundary(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx);
|
|
5796
6293
|
cursor.columnIndex = 0;
|
|
5797
6294
|
flushPendingNumberingAtBoundary();
|
|
6295
|
+
opensPage = true;
|
|
5798
6296
|
}
|
|
6297
|
+
if (opensPage)
|
|
6298
|
+
openerPages.add(doc.pages[cursor.pageIndex]);
|
|
5799
6299
|
}
|
|
5800
6300
|
const id = `block-${blockIdCounter++}`;
|
|
5801
6301
|
// Enclosing `:::paragraphs` container (if any). Its last paragraph — the
|
|
@@ -5828,8 +6328,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5828
6328
|
* block keeps its own space in its snap, and the container's
|
|
5829
6329
|
* `marginBottom` follows as pending spacing from the closing marker. */
|
|
5830
6330
|
const containerTail = isContainerTail && rawBlock.type === 'paragraph' ? paragraphContainer : undefined;
|
|
6331
|
+
// (A paragraph style may set the rule for its own containers, #715.)
|
|
5831
6332
|
const collapseTail = containerTail !== undefined
|
|
5832
|
-
&& resolved.bodyText.paragraphContainerSpacing === 'collapse'
|
|
6333
|
+
&& (containerTail.spacing ?? resolved.bodyText.paragraphContainerSpacing) === 'collapse'
|
|
5833
6334
|
&& containerTail.tailStyle.marginBottomPx >= 0;
|
|
5834
6335
|
const tailStyle = collapseTail && blockMeasureCtx.bodyStyle.marginBottomPx > containerTail.tailStyle.marginBottomPx
|
|
5835
6336
|
? { ...containerTail.tailStyle, marginBottomPx: blockMeasureCtx.bodyStyle.marginBottomPx }
|
|
@@ -5872,6 +6373,18 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5872
6373
|
let measuredBlock = tryLoose
|
|
5873
6374
|
? measureLooseParagraph(rawBlock, blockIdx, col.bbox.width, blockMeasureCtx, styleOverride, looseLines, trackingLadder, looseOutcome, looseOffGrid)
|
|
5874
6375
|
: measureContentBlock(rawBlock, blockIdx, measureWidth, blockMeasureCtx, { styleOverride, ...upright, ...figureDelta });
|
|
6376
|
+
// A resource set in the text with `captionSide` (#729): its caption and
|
|
6377
|
+
// note go to the band's side column when that is free beside it, and
|
|
6378
|
+
// the block is as tall as the body alone. Decided again in every
|
|
6379
|
+
// column the block is tried in (see the resource branch below).
|
|
6380
|
+
const asideWanted = measuredBlock?.kind.vdtType === 'resource' && rawBlock.type === 'resourceBlock'
|
|
6381
|
+
&& inlineAsideWanted(measuredBlock.kind.resource, measuredBlock.kind.resourceType, blockPage);
|
|
6382
|
+
let inlineAside = asideWanted
|
|
6383
|
+
? measureInlineAside(rawBlock, blockIdx, col, blockPage, blockMeasureCtx, { styleOverride, ...figureDelta }, Math.max(pendingSpacing, floatGapPx))
|
|
6384
|
+
: null;
|
|
6385
|
+
if (inlineAside)
|
|
6386
|
+
measuredBlock = inlineAside.block;
|
|
6387
|
+
const asideOpts = inlineAside?.opts;
|
|
5875
6388
|
// An inline picture with a safe area a little too tall for the room
|
|
5876
6389
|
// left in its column is cropped within its safe area to stay there
|
|
5877
6390
|
// rather than move on and leave the column short (#442).
|
|
@@ -5881,7 +6394,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5881
6394
|
const over = measuredBlock.measured.totalHeight - room;
|
|
5882
6395
|
if (over > 0.01 && room > 0 && over <= flex.shrink + 0.01) {
|
|
5883
6396
|
const cropped = measureContentBlock(rawBlock, blockIdx, measureWidth, blockMeasureCtx, {
|
|
5884
|
-
styleOverride, ...upright, figureHeightDelta: flex.delta - over,
|
|
6397
|
+
styleOverride, ...upright, ...asideOpts, figureHeightDelta: flex.delta - over,
|
|
5885
6398
|
});
|
|
5886
6399
|
if (cropped && cropped.measured.totalHeight <= room + 0.01)
|
|
5887
6400
|
measuredBlock = cropped;
|
|
@@ -5905,7 +6418,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5905
6418
|
width = current.bodyRect.width * Math.min(scale, 0.99);
|
|
5906
6419
|
if (width < rb.bodyRect.width * MIN_INLINE_FIGURE_SCALE)
|
|
5907
6420
|
break;
|
|
5908
|
-
const smaller = measureContentBlock(rawBlock, blockIdx, col.bbox.width, blockMeasureCtx, { styleOverride, figureMaxBodyWidth: width });
|
|
6421
|
+
const smaller = measureContentBlock(rawBlock, blockIdx, col.bbox.width, blockMeasureCtx, { styleOverride, ...asideOpts, figureMaxBodyWidth: width });
|
|
5909
6422
|
if (!smaller)
|
|
5910
6423
|
break;
|
|
5911
6424
|
measuredBlock = smaller;
|
|
@@ -5915,10 +6428,13 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5915
6428
|
// Still too tall at the smallest acceptable size: back to full size
|
|
5916
6429
|
// and on to the next column, as without the option.
|
|
5917
6430
|
if (measuredBlock.measured.totalHeight > room + FIT_EPS) {
|
|
5918
|
-
measuredBlock = measureContentBlock(rawBlock, blockIdx, col.bbox.width, blockMeasureCtx, { styleOverride });
|
|
6431
|
+
measuredBlock = measureContentBlock(rawBlock, blockIdx, col.bbox.width, blockMeasureCtx, { styleOverride, ...asideOpts });
|
|
5919
6432
|
}
|
|
5920
6433
|
}
|
|
5921
6434
|
}
|
|
6435
|
+
// The fits above keep the caption at the side: they work on the body.
|
|
6436
|
+
if (inlineAside)
|
|
6437
|
+
inlineAside = measuredBlock?.asideHeight !== undefined ? { ...inlineAside, block: measuredBlock } : null;
|
|
5922
6438
|
if (tryLoose && budget !== undefined && knownOutcome === undefined && typeof looseOutcome.get(blockIdx) === 'number') {
|
|
5923
6439
|
looseGained.set(budget.group, (looseGained.get(budget.group) ?? 0) + 1);
|
|
5924
6440
|
}
|
|
@@ -5931,7 +6447,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5931
6447
|
let capInfo = measuredBlock.dropCap;
|
|
5932
6448
|
/** Tracking the block's lines are set with; a paragraph moved whole into
|
|
5933
6449
|
* a column of another width is measured again, and may change it. */
|
|
5934
|
-
let { letterSpacingPx } = measuredBlock;
|
|
6450
|
+
let { letterSpacingPx, runtTracking } = measuredBlock;
|
|
5935
6451
|
const { vdtType, headingLevel, numberPrefix, numberSeparator, headingNumber, listBullet, listDepth, listKind, bulletXOffsetInColumn, strikethroughText } = kind;
|
|
5936
6452
|
// A structural heading (`hidden`) is placed like any heading — its
|
|
5937
6453
|
// break, keep-with-next and grid snap apply — but with no line height
|
|
@@ -5950,8 +6466,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5950
6466
|
// --- Resource blocks (image / svg / table + caption) -----------------
|
|
5951
6467
|
// Placed atomically (kept-together) — no mid-content split for v1.
|
|
5952
6468
|
if (vdtType === 'resource') {
|
|
5953
|
-
|
|
5954
|
-
|
|
6469
|
+
let resourceBlock = measuredBlock.resourceBlock;
|
|
6470
|
+
let groupHeight = measured.totalHeight;
|
|
5955
6471
|
const blk = createVDTBlock(id, 'resource', style.fontString, style.color, style.textAlign);
|
|
5956
6472
|
blk.contentIndex = blockIdx;
|
|
5957
6473
|
stampBlockExtras(blk, rawBlock);
|
|
@@ -6010,7 +6526,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6010
6526
|
// An inline table that does not fit the room left in its column is
|
|
6011
6527
|
// cut between rows (#634), by the rules of a floated one.
|
|
6012
6528
|
const sliced = !wraps && !resourceBlock.rotation && resourceBlock.table && kind.resource
|
|
6013
|
-
? placeInlineTableSlices(rawBlock, blockIdx, blk, blockMeasureCtx, styleOverride, kind.resource, groupHeight, spacingBefore)
|
|
6529
|
+
? placeInlineTableSlices(rawBlock, blockIdx, blk, blockMeasureCtx, styleOverride, kind.resource, groupHeight, spacingBefore, asideWanted)
|
|
6014
6530
|
: 'whole';
|
|
6015
6531
|
if (sliced === 'dropped') {
|
|
6016
6532
|
flushPendingNumberingAtBoundary();
|
|
@@ -6019,6 +6535,44 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6019
6535
|
const columnBefore = col;
|
|
6020
6536
|
if (sliced === 'whole') {
|
|
6021
6537
|
enterBand(blockIdx, 0);
|
|
6538
|
+
// A side caption is decided where the block is placed (#729): an
|
|
6539
|
+
// embed that does not fit its column moves on by the rule of
|
|
6540
|
+
// `placeAtomicBlock`, and in each column it reaches its caption
|
|
6541
|
+
// goes to the side when the side column is free there, else under
|
|
6542
|
+
// the body.
|
|
6543
|
+
if (asideWanted) {
|
|
6544
|
+
let decidedFor = col;
|
|
6545
|
+
let plain = inlineAside ? undefined : measuredBlock;
|
|
6546
|
+
for (let guard = 0;; guard++) {
|
|
6547
|
+
const c = currentColumn(doc, cursor);
|
|
6548
|
+
if (c !== decidedFor) {
|
|
6549
|
+
decidedFor = c;
|
|
6550
|
+
inlineAside = measureInlineAside(rawBlock, blockIdx, c, doc.pages[cursor.pageIndex], blockMeasureCtx, { styleOverride, ...figureDelta }, spacingBefore);
|
|
6551
|
+
if (!inlineAside && plain === undefined) {
|
|
6552
|
+
plain = measureContentBlock(rawBlock, blockIdx, measureWidth, blockMeasureCtx, { styleOverride, ...figureDelta });
|
|
6553
|
+
}
|
|
6554
|
+
const next = inlineAside?.block ?? plain;
|
|
6555
|
+
if (next?.resourceBlock) {
|
|
6556
|
+
resourceBlock = next.resourceBlock;
|
|
6557
|
+
groupHeight = next.measured.totalHeight;
|
|
6558
|
+
}
|
|
6559
|
+
else {
|
|
6560
|
+
inlineAside = null;
|
|
6561
|
+
}
|
|
6562
|
+
}
|
|
6563
|
+
const available = c.availableHeight - (c.blocks.length === 0 ? 0 : spacingBefore);
|
|
6564
|
+
if (groupHeight <= available + FIT_EPS)
|
|
6565
|
+
break;
|
|
6566
|
+
if (c.blocks.length === 0 && c.availableHeight >= 0.5 && groupHeight > contentArea.height + FIT_EPS)
|
|
6567
|
+
break;
|
|
6568
|
+
if (guard >= 8)
|
|
6569
|
+
break;
|
|
6570
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onAtomicNewPage(groupHeight));
|
|
6571
|
+
}
|
|
6572
|
+
blk.resourceBlock = resourceBlock;
|
|
6573
|
+
blk.lines[0].bbox = { x: 0, y: 0, width: resourceBlock.bodyRect.width, height: groupHeight };
|
|
6574
|
+
}
|
|
6575
|
+
const decidedColumn = currentColumn(doc, cursor);
|
|
6022
6576
|
placeAtomicBlock(blk, groupHeight, spacingBefore, cursor, doc, geomResolved, contentArea, pageWidthPx, pageHeightPx, onAtomicNewPage(groupHeight));
|
|
6023
6577
|
enterBand(blockIdx, 0);
|
|
6024
6578
|
// Too tall for the room left in its column, a wrapped picture moved
|
|
@@ -6033,6 +6587,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6033
6587
|
// resource's own caption/table lines live on `resourceBlock` and must be
|
|
6034
6588
|
// offset to absolute page coordinates here using the placed bbox origin.
|
|
6035
6589
|
offsetResourceBlockToAbsolute(resourceBlock, blk.bbox.x, blk.bbox.y);
|
|
6590
|
+
if (inlineAside && inlineAside.block.asideHeight !== undefined && currentColumn(doc, cursor) === decidedColumn) {
|
|
6591
|
+
markInlineAside(blk, inlineAside.sideCol, inlineAside.block.asideHeight);
|
|
6592
|
+
}
|
|
6036
6593
|
const grown = figureGrowPx > 0 ? resourceBlock.bodyFlex?.delta ?? 0 : 0;
|
|
6037
6594
|
if (grown > 0.01) {
|
|
6038
6595
|
blk.balancing = { levers: ['flexFigure'], spaceAbove: 0, bodyGrowth: grown };
|
|
@@ -6219,6 +6776,23 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6219
6776
|
/** Whether the paragraph was already re-broken to keep a hyphen off
|
|
6220
6777
|
* the last line of a column (`bodyText.hyphenateAcrossColumns`). */
|
|
6221
6778
|
let columnEndHyphenRetried = false;
|
|
6779
|
+
/** The lines (1-based, counted from the first line still to place) the
|
|
6780
|
+
* guard keeps a hyphen off: the line the split falls after and one
|
|
6781
|
+
* every full column after it, or, under `'withinPage'` (#701), those
|
|
6782
|
+
* of them that close a page — the j-th column end from here does when
|
|
6783
|
+
* the `rest` columns left on this page that still take a line of this
|
|
6784
|
+
* text are used up and a whole number of fresh pages, of `perPage`
|
|
6785
|
+
* flow columns each, has gone by. */
|
|
6786
|
+
const guardedColumnEnds = (mode, splitAt, lineCount, fullColumn, page, columnIndex) => {
|
|
6787
|
+
const ends = [];
|
|
6788
|
+
const rest = mode === false ? 0 : flowColumnsAfter(page, columnIndex, style.lineHeightPx);
|
|
6789
|
+
const perPage = mode === false ? 1 : freshPageFlowColumns();
|
|
6790
|
+
for (let n = splitAt, j = 0; n < lineCount; n += fullColumn, j++) {
|
|
6791
|
+
if (j >= rest && (j - rest) % perPage === 0)
|
|
6792
|
+
ends.push(n);
|
|
6793
|
+
}
|
|
6794
|
+
return ends;
|
|
6795
|
+
};
|
|
6222
6796
|
/** `hyphenateAcrossColumns: false`: the paragraph's lines as set now
|
|
6223
6797
|
* (a re-break replaces them) and where the breaker broke them, the
|
|
6224
6798
|
* lines (1-based) its last re-break kept a hyphen off, and the part
|
|
@@ -6288,6 +6862,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6288
6862
|
laterWidths = [];
|
|
6289
6863
|
wrapInsets = [];
|
|
6290
6864
|
letterSpacingPx = again.letterSpacingPx;
|
|
6865
|
+
runtTracking = again.runtTracking;
|
|
6291
6866
|
remainingLines = [...raggedLooseLines(again.measured.lines, style.textAlign)];
|
|
6292
6867
|
paragraphLines = remainingLines;
|
|
6293
6868
|
paragraphBreaks = again.measured.breaks;
|
|
@@ -6462,6 +7037,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6462
7037
|
if (placed === 0) {
|
|
6463
7038
|
capInfo = again.dropCap;
|
|
6464
7039
|
letterSpacingPx = again.letterSpacingPx;
|
|
7040
|
+
runtTracking = again.runtTracking;
|
|
6465
7041
|
guardedEnds = [];
|
|
6466
7042
|
columnEndHyphenRetried = false;
|
|
6467
7043
|
}
|
|
@@ -6493,7 +7069,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6493
7069
|
// block fits when its lines and all their notes do, and a split
|
|
6494
7070
|
// keeps the lines whose notes fit under them.
|
|
6495
7071
|
const noteCosts = vdtType === 'mathDisplay' ? undefined : notesPrefixCost(curCol, remainingLines);
|
|
6496
|
-
|
|
7072
|
+
let effectiveAvailable = curCol.availableHeight - spacingBefore - (noteCosts ? noteCosts[noteCosts.length - 1] : 0);
|
|
6497
7073
|
// A hair of tolerance: room of exactly N lines (grid arithmetic in
|
|
6498
7074
|
// floats — a column cut by a band cap, a balancing extra line) must
|
|
6499
7075
|
// hold N lines, not N - 1.
|
|
@@ -6567,6 +7143,28 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6567
7143
|
headingDesign = { lvl, info };
|
|
6568
7144
|
}
|
|
6569
7145
|
}
|
|
7146
|
+
// With `headings.columnHeadSpace: 'remainder'` (#706) a heading that
|
|
7147
|
+
// opens a column drops its space above in whole grid lines only: what is
|
|
7148
|
+
// left of a line stays above it, so its text starts as far under it
|
|
7149
|
+
// as under the same heading set after a paragraph. The foot of its
|
|
7150
|
+
// box stays on the grid line the snap puts it on, and no line of body
|
|
7151
|
+
// text moves. A heading the grid does not snap, a hidden one, a
|
|
7152
|
+
// `lineSpan` band, a page-span opener and a heading painted from its
|
|
7153
|
+
// own design (its band is the design's, drawn from the column's head)
|
|
7154
|
+
// keep the head of the column; so does the first block of a column
|
|
7155
|
+
// under an opener band, which is set level with the first block
|
|
7156
|
+
// under the opener (`openerHead`).
|
|
7157
|
+
if (vdtType === 'heading' && partIndex === 0 && !hiddenHeading && lineSpan === undefined
|
|
7158
|
+
&& resolved.headings.columnHeadSpace === 'remainder'
|
|
7159
|
+
&& (isFirstInColumn || underOpenerHeadFloat(curCol)) && openerHead === undefined
|
|
7160
|
+
&& !headingSetsOwnBand(headingLevels.forBlock(rawBlock))) {
|
|
7161
|
+
const usedHeight = curCol.bbox.height - curCol.availableHeight;
|
|
7162
|
+
const kept = columnHeadKept(blockIdx, rawBlock, usedHeight, effectiveRemainHeight, style, shouldSnapToGrid, curCol, blockMeasureCtx);
|
|
7163
|
+
if (kept > 0) {
|
|
7164
|
+
spacingBefore += kept;
|
|
7165
|
+
effectiveAvailable -= kept;
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
6570
7168
|
// Keep-with-list: if this colon-paragraph would fit but would leave no
|
|
6571
7169
|
// room for the first list item, split off the colon line (or push the
|
|
6572
7170
|
// whole paragraph when it is a single line or the split would leave a
|
|
@@ -6595,6 +7193,17 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6595
7193
|
effectiveGap = Math.ceil((paragraphBottom + effectiveGap - 0.01) / baselineGrid) * baselineGrid - paragraphBottom;
|
|
6596
7194
|
}
|
|
6597
7195
|
const minSpaceForList = effectiveGap + bodyStyle.lineHeightPx;
|
|
7196
|
+
// A short list set whole (`shortListSplit: 'avoid'`, #749) needs
|
|
7197
|
+
// all its room under the colon line, when a column can hold the
|
|
7198
|
+
// line and the list at all — less what a figure this paragraph
|
|
7199
|
+
// cites will take from the column's foot (`citedFootTake`).
|
|
7200
|
+
let listIdx = blockIdx + 1;
|
|
7201
|
+
while (listIdx < contentBlocks.length && isMarkerBlock(contentBlocks[listIdx]))
|
|
7202
|
+
listIdx++;
|
|
7203
|
+
const wholeList = shortListRule === 'avoid' ? shortListFrom(listIdx) : undefined;
|
|
7204
|
+
const wholeNeed = wholeList ? shortListNeed(wholeList, curCol.bbox.width, blockMeasureCtx) : undefined;
|
|
7205
|
+
const keepsListWhole = wholeNeed !== undefined
|
|
7206
|
+
&& style.lineHeightPx + effectiveGap + wholeNeed.height <= contentArea.height + FIT_EPS;
|
|
6598
7207
|
// A line of room is not always enough (EF-110): with
|
|
6599
7208
|
// `colonListRoom: 'item'` the first item has to be able to start
|
|
6600
7209
|
// there, by the rules that split it — a two-line item the orphan
|
|
@@ -6602,7 +7211,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6602
7211
|
// check, one line.
|
|
6603
7212
|
if (availableAfter < minSpaceForList - FIT_EPS
|
|
6604
7213
|
|| (resolved.bodyText.colonListRoom === 'item'
|
|
6605
|
-
&& !firstListItemStarts(blockIdx, availableAfter - effectiveGap, curCol.bbox.width, blockMeasureCtx))
|
|
7214
|
+
&& !firstListItemStarts(blockIdx, availableAfter - effectiveGap, curCol.bbox.width, blockMeasureCtx))
|
|
7215
|
+
|| (keepsListWhole && availableAfter - effectiveGap - citedFootTake(blockIdx, curCol, availableAfter) < wholeNeed.height - FIT_EPS)) {
|
|
6606
7216
|
const effectiveWidowMin = resolved.bodyText.avoidWidows
|
|
6607
7217
|
? Math.max(1, resolved.bodyText.widowMinLines)
|
|
6608
7218
|
: 1;
|
|
@@ -6615,6 +7225,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6615
7225
|
applyStyleAttrs(blk, style);
|
|
6616
7226
|
if (letterSpacingPx !== undefined)
|
|
6617
7227
|
blk.letterSpacing = letterSpacingPx;
|
|
7228
|
+
if (runtTracking !== undefined)
|
|
7229
|
+
blk.runtFix = { tracking: runtTracking };
|
|
6618
7230
|
blk.contentIndex = blockIdx;
|
|
6619
7231
|
stampBlockExtras(blk, rawBlock);
|
|
6620
7232
|
blk.headingLevel = headingLevel;
|
|
@@ -6719,6 +7331,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6719
7331
|
applyStyleAttrs(blk, style);
|
|
6720
7332
|
if (letterSpacingPx !== undefined)
|
|
6721
7333
|
blk.letterSpacing = letterSpacingPx;
|
|
7334
|
+
if (runtTracking !== undefined)
|
|
7335
|
+
blk.runtFix = { tracking: runtTracking };
|
|
6722
7336
|
blk.contentIndex = blockIdx;
|
|
6723
7337
|
stampBlockExtras(blk, rawBlock);
|
|
6724
7338
|
blk.lines = resetLinePositions(splitLines, style.lineHeightPx);
|
|
@@ -6759,6 +7373,40 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6759
7373
|
}
|
|
6760
7374
|
}
|
|
6761
7375
|
}
|
|
7376
|
+
// A short list is set whole (`bodyText.shortListSplit: 'avoid'`,
|
|
7377
|
+
// #749): when its items do not all fit under what the column holds
|
|
7378
|
+
// and an empty column would hold them, the list opens the next
|
|
7379
|
+
// column, with the headings right above it. Not a list a colon line
|
|
7380
|
+
// introduces: that line already took the list's room into account,
|
|
7381
|
+
// and the two stay together. Nor one that opens its column, or
|
|
7382
|
+
// stands under nothing but headings: it cannot do better anywhere.
|
|
7383
|
+
if (vdtType === 'listItem' && partIndex === 0 && shortListRule === 'avoid' && curCol.blocks.length > 0) {
|
|
7384
|
+
const list = shortListFrom(blockIdx);
|
|
7385
|
+
const headingRun = trailingHeadingRun(curCol);
|
|
7386
|
+
const lead = list ? prevNonMarkerBlock(contentBlocks, blockIdx) : undefined;
|
|
7387
|
+
const colonLed = lead?.type === 'paragraph' && resolved.bodyText.keepColonWithList && /[::︰﹕]\s*$/.test(lead.text);
|
|
7388
|
+
const need = list && !colonLed && headingRun < curCol.blocks.length
|
|
7389
|
+
? shortListNeed(list, curCol.bbox.width, blockMeasureCtx)
|
|
7390
|
+
: undefined;
|
|
7391
|
+
if (need && need.height <= contentArea.height + FIT_EPS) {
|
|
7392
|
+
const listNotes = notesPrefixCost(curCol, need.lines);
|
|
7393
|
+
const room = curCol.availableHeight - spacingBefore - (listNotes ? listNotes[listNotes.length - 1] : 0);
|
|
7394
|
+
if (need.height > room + FIT_EPS) {
|
|
7395
|
+
if (resolved.headings.keepWithNext && headingRun > 0) {
|
|
7396
|
+
const rolledBack = rollbackHeadings(curCol);
|
|
7397
|
+
if (rolledBack.length > 0) {
|
|
7398
|
+
blockIdx = (rolledBack[0].contentIndex ?? blockIdx - rolledBack.length) - 1;
|
|
7399
|
+
pendingSpacing = 0;
|
|
7400
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onNewPage);
|
|
7401
|
+
break;
|
|
7402
|
+
}
|
|
7403
|
+
}
|
|
7404
|
+
pendingSpacing = 0;
|
|
7405
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onNewPage);
|
|
7406
|
+
continue;
|
|
7407
|
+
}
|
|
7408
|
+
}
|
|
7409
|
+
}
|
|
6762
7410
|
// A block opening a column normally stays (no column can take it any
|
|
6763
7411
|
// better), except in a column at least a line shorter than the content
|
|
6764
7412
|
// area — the band under a page-span box, or a column cut by a float:
|
|
@@ -6833,6 +7481,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6833
7481
|
applyStyleAttrs(blk, style);
|
|
6834
7482
|
if (letterSpacingPx !== undefined)
|
|
6835
7483
|
blk.letterSpacing = letterSpacingPx;
|
|
7484
|
+
if (runtTracking !== undefined)
|
|
7485
|
+
blk.runtFix = { tracking: runtTracking };
|
|
6836
7486
|
blk.contentIndex = blockIdx;
|
|
6837
7487
|
stampBlockExtras(blk, rawBlock);
|
|
6838
7488
|
if (partIndex === 0) {
|
|
@@ -6911,6 +7561,21 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6911
7561
|
if (vdtType === 'heading' && effectiveRemainHeight > totalRemainHeight && h > curCol.availableHeight + FIT_EPS) {
|
|
6912
7562
|
h = Math.max(effectiveRemainHeight, curCol.availableHeight);
|
|
6913
7563
|
}
|
|
7564
|
+
// A block whose lines fit, and whose snap would reach the grid line
|
|
7565
|
+
// under the column's foot (a foot the notes reserved there took off
|
|
7566
|
+
// the grid, or a bottom margin on the column's last line), ends at
|
|
7567
|
+
// the foot (#716): its box stays inside its column and the room left
|
|
7568
|
+
// reads 0, not a negative height. The space it still owed is dropped,
|
|
7569
|
+
// as pending spacing is at any column's end. A column cut by a band
|
|
7570
|
+
// cap keeps the overrun: there it is how the block's bottom margin
|
|
7571
|
+
// reaches the page-span box under the cut (`bandUsedBottomWithSide`).
|
|
7572
|
+
if (shouldSnapToGrid && partIndex === 0
|
|
7573
|
+
&& !uncappedBottoms.has(curCol)
|
|
7574
|
+
&& h > curCol.availableHeight + FIT_EPS
|
|
7575
|
+
&& effectiveRemainHeight <= curCol.availableHeight + FIT_EPS) {
|
|
7576
|
+
h = Math.max(effectiveRemainHeight, curCol.availableHeight);
|
|
7577
|
+
tailOwed = 0;
|
|
7578
|
+
}
|
|
6914
7579
|
placeBlockInColumn(blk, h, curCol, cursor);
|
|
6915
7580
|
citedLinesPlaced(blockIdx, blk);
|
|
6916
7581
|
finalizeListItem(blk, partIndex === 0);
|
|
@@ -6942,6 +7607,18 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6942
7607
|
}
|
|
6943
7608
|
break;
|
|
6944
7609
|
}
|
|
7610
|
+
// An index entry that leaves the column takes the entries of its
|
|
7611
|
+
// group the keep rule does not let stay with it (#712): the roll-back
|
|
7612
|
+
// comes before any cut between its own lines.
|
|
7613
|
+
if (rawBlock.index && partIndex === 0 && curCol.blocks.length > 0) {
|
|
7614
|
+
const rolledBack = rollbackIndexGroup(curCol, rawBlock, blockMeasureCtx.resolved.index.groups.splitMinEntries);
|
|
7615
|
+
if (rolledBack.length > 0) {
|
|
7616
|
+
blockIdx = (rolledBack[0].contentIndex ?? blockIdx - rolledBack.length) - 1;
|
|
7617
|
+
pendingSpacing = 0;
|
|
7618
|
+
advanceToNextColumn(doc, cursor, geomResolved, contentArea, pageWidthPx, pageHeightPx, onNewPage);
|
|
7619
|
+
break;
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
6945
7622
|
// Block doesn't fit — try to split (orphan/widow-aware)
|
|
6946
7623
|
const inList = vdtType === 'listItem';
|
|
6947
7624
|
const effectiveAvoidOrphans = resolved.bodyText.avoidOrphans
|
|
@@ -6999,19 +7676,23 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6999
7676
|
// placement then starts over with its lines. Only a paragraph set
|
|
7000
7677
|
// from its first line here — its earlier lines are not placed yet —
|
|
7001
7678
|
// and never one the balancing is running long.
|
|
7679
|
+
//
|
|
7680
|
+
// `'withinPage'` (#701) guards only the ends that close a page: this
|
|
7681
|
+
// column's when no later column of its page takes text, and then
|
|
7682
|
+
// one every page of full columns. With none in the paragraph,
|
|
7683
|
+
// nothing is measured again.
|
|
7684
|
+
const hyphenGuard = resolved.bodyText.hyphenateAcrossColumns;
|
|
7002
7685
|
if (choice.splitAt > 0
|
|
7003
|
-
&&
|
|
7686
|
+
&& hyphenGuard !== true
|
|
7004
7687
|
&& !columnEndHyphenRetried
|
|
7005
7688
|
&& partIndex === 0
|
|
7006
7689
|
&& looseLines === undefined) {
|
|
7007
7690
|
const fullColumn = Math.max(1, Math.floor((contentArea.height + 0.01) / style.lineHeightPx));
|
|
7008
|
-
const ends = [];
|
|
7009
|
-
for (let n = choice.splitAt; n < remainingLines.length; n += fullColumn)
|
|
7010
|
-
ends.push(n);
|
|
7691
|
+
const ends = guardedColumnEnds(hyphenGuard, choice.splitAt, remainingLines.length, fullColumn, doc.pages[cursor.pageIndex], cursor.columnIndex);
|
|
7011
7692
|
/** How a setting ends its guarded lines: whether this column's
|
|
7012
7693
|
* last line is hyphenated, and how many guarded lines are. */
|
|
7013
7694
|
const columnEndHyphens = (lines) => ({
|
|
7014
|
-
first: lines[choice.splitAt - 1]?.hyphenated === true,
|
|
7695
|
+
first: ends[0] === choice.splitAt && lines[choice.splitAt - 1]?.hyphenated === true,
|
|
7015
7696
|
count: ends.filter((n) => lines[n - 1]?.hyphenated).length,
|
|
7016
7697
|
});
|
|
7017
7698
|
const natural = columnEndHyphens(remainingLines);
|
|
@@ -7050,18 +7731,19 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
7050
7731
|
// this column's end (or fewer at the ends still to come). The
|
|
7051
7732
|
// placed lines are checked again all the same: a break trace from
|
|
7052
7733
|
// the other measuring path cannot keep them.
|
|
7734
|
+
// Under `'withinPage'` only from a column that closes its page.
|
|
7053
7735
|
if (choice.splitAt > 0
|
|
7054
|
-
&&
|
|
7736
|
+
&& hyphenGuard !== true
|
|
7055
7737
|
&& partIndex > 0
|
|
7056
7738
|
&& columnEndHyphenPart !== partIndex
|
|
7057
7739
|
&& looseLines === undefined
|
|
7058
|
-
&& remainingLines[choice.splitAt - 1]?.hyphenated === true
|
|
7740
|
+
&& remainingLines[choice.splitAt - 1]?.hyphenated === true
|
|
7741
|
+
&& (hyphenGuard === false || columnClosesPage(doc.pages[cursor.pageIndex], cursor.columnIndex, style.lineHeightPx))) {
|
|
7059
7742
|
columnEndHyphenPart = partIndex;
|
|
7060
7743
|
const placed = paragraphLines.length - remainingLines.length;
|
|
7061
7744
|
const fullColumn = Math.max(1, Math.floor((contentArea.height + 0.01) / style.lineHeightPx));
|
|
7062
|
-
const later = []
|
|
7063
|
-
|
|
7064
|
-
later.push(placed + n);
|
|
7745
|
+
const later = guardedColumnEnds(hyphenGuard, choice.splitAt, remainingLines.length, fullColumn, doc.pages[cursor.pageIndex], cursor.columnIndex)
|
|
7746
|
+
.map((n) => placed + n);
|
|
7065
7747
|
// The ends already placed keep their guard; the later ones the
|
|
7066
7748
|
// last re-break assumed give way to where the columns now end.
|
|
7067
7749
|
const ends = [...guardedEnds.filter((n) => n <= placed), ...later];
|
|
@@ -7123,6 +7805,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
7123
7805
|
applyStyleAttrs(blk, style);
|
|
7124
7806
|
if (letterSpacingPx !== undefined)
|
|
7125
7807
|
blk.letterSpacing = letterSpacingPx;
|
|
7808
|
+
if (runtTracking !== undefined)
|
|
7809
|
+
blk.runtFix = { tracking: runtTracking };
|
|
7126
7810
|
blk.contentIndex = blockIdx;
|
|
7127
7811
|
stampBlockExtras(blk, rawBlock);
|
|
7128
7812
|
if (partIndex === 0) {
|
|
@@ -7226,6 +7910,8 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
7226
7910
|
applyStyleAttrs(blk, style);
|
|
7227
7911
|
if (letterSpacingPx !== undefined)
|
|
7228
7912
|
blk.letterSpacing = letterSpacingPx;
|
|
7913
|
+
if (runtTracking !== undefined)
|
|
7914
|
+
blk.runtFix = { tracking: runtTracking };
|
|
7229
7915
|
blk.contentIndex = blockIdx;
|
|
7230
7916
|
stampBlockExtras(blk, rawBlock);
|
|
7231
7917
|
// Stamp the prefix as the other placement branches do: a full-page
|
|
@@ -7444,6 +8130,10 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
7444
8130
|
floatShrinkWarningsByDoc.set(doc, shrunk);
|
|
7445
8131
|
if (textWrapNotes.length > 0 || columnsNotes.length > 0)
|
|
7446
8132
|
textWrapWarningsByDoc.set(doc, [...textWrapNotes, ...columnsNotes]);
|
|
8133
|
+
// The composition rules (#749): short lists cut, floats on opener pages.
|
|
8134
|
+
const ruleNotes = [...shortListWarnings(), ...openerFloatNotes];
|
|
8135
|
+
if (ruleNotes.length > 0)
|
|
8136
|
+
compositionWarningsByDoc.set(doc, ruleNotes);
|
|
7447
8137
|
const { proposals: citingPageProposals, refused: citingPageRefused } = settleCitingPageFloats();
|
|
7448
8138
|
return { doc, forcedBreakPages, bandCapProposals, spanPlacedInBand, bandCapsApplied, looseOutcome, looseOffGrid, captionUnderProposals, citingPageProposals, citingPageRefused };
|
|
7449
8139
|
}
|
|
@@ -7514,7 +8204,7 @@ export function* buildDocumentGen(content, config, cache, options) {
|
|
|
7514
8204
|
// cap; words of a joining script that run past their line, and styles
|
|
7515
8205
|
// whose letter-spacing such words do not take.
|
|
7516
8206
|
// Line numbers set over a float of the side column (#621).
|
|
7517
|
-
const loose = [...cjkLooseLineWarnings(doc), ...wordOverflowWarnings(doc), ...(joiningSpacingWarnings.get(doc) ?? []), ...(dropCapWarningsByDoc.get(doc) ?? []), ...lineNumberWarnings(doc), ...codeOverflowWarnings(doc), ...(floatShrinkWarningsByDoc.get(doc) ?? []), ...(textWrapWarningsByDoc.get(doc) ?? [])];
|
|
8207
|
+
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) ?? [])];
|
|
7518
8208
|
// Side boxes and side floats set on pages after the text, and what the
|
|
7519
8209
|
// layout could place nowhere (#639).
|
|
7520
8210
|
loose.push(...afterTextWarnings(doc), ...(unplacedByDoc.get(doc) ?? []));
|
|
@@ -7573,6 +8263,9 @@ const floatShrinkWarningsByDoc = new WeakMap();
|
|
|
7573
8263
|
/** The `textWrap` warnings of a build (#627) and its `columnsTooNarrow`
|
|
7574
8264
|
* ones (#634), found by its last pass. */
|
|
7575
8265
|
const textWrapWarningsByDoc = new WeakMap();
|
|
8266
|
+
/** The `shortListSplit` and `openerFloat` warnings of a build (#749),
|
|
8267
|
+
* found by its last pass. */
|
|
8268
|
+
const compositionWarningsByDoc = new WeakMap();
|
|
7576
8269
|
/** What a pass set in the side column of a page opened after the text of
|
|
7577
8270
|
* its chapter (#639): a side box's frame, a side float's block, with the
|
|
7578
8271
|
* source range an `afterText` warning points at. Read from the finished
|
|
@@ -8017,16 +8710,25 @@ citing = { hints: new Map(), refused: new Set() }) {
|
|
|
8017
8710
|
return false;
|
|
8018
8711
|
if (newLines.length === 0 && newLoose.length === 0)
|
|
8019
8712
|
return false;
|
|
8713
|
+
// Where the headings hold lines back for the loose paragraphs (#707),
|
|
8714
|
+
// a pass that tried both in the columns at fault blames the paragraphs
|
|
8715
|
+
// first: run a line long, they are what moves text across a column
|
|
8716
|
+
// break, and a heading blacklisted with them could never take the lines
|
|
8717
|
+
// it took alone up to 1.27. The spacing levers are tried again without
|
|
8718
|
+
// them, and blacklisted in their turn if the cascade is theirs.
|
|
8719
|
+
const looseFirst = balancing.maxLinesBeforeLoose < balancing.maxLinesPerHeading;
|
|
8020
8720
|
const blacklist = (cands) => {
|
|
8021
8721
|
let hit = false;
|
|
8022
|
-
for (const k of
|
|
8722
|
+
for (const k of newLoose)
|
|
8023
8723
|
if (!cands || cands.has(k)) {
|
|
8024
|
-
s.
|
|
8724
|
+
s.failedLoose.add(k);
|
|
8025
8725
|
hit = true;
|
|
8026
8726
|
}
|
|
8027
|
-
|
|
8727
|
+
if (hit && looseFirst)
|
|
8728
|
+
return true;
|
|
8729
|
+
for (const k of newLines)
|
|
8028
8730
|
if (!cands || cands.has(k)) {
|
|
8029
|
-
s.
|
|
8731
|
+
s.failedLines.add(k);
|
|
8030
8732
|
hit = true;
|
|
8031
8733
|
}
|
|
8032
8734
|
return hit;
|
|
@@ -8056,10 +8758,13 @@ citing = { hints: new Map(), refused: new Set() }) {
|
|
|
8056
8758
|
}
|
|
8057
8759
|
const proposal = proposeBalanceLines(best.doc, best.forcedBreakPages, applied, {
|
|
8058
8760
|
maxLinesPerHeading: balancing.maxLinesPerHeading,
|
|
8761
|
+
maxLinesBeforeLoose: balancing.maxLinesBeforeLoose,
|
|
8059
8762
|
stretchAfterLists: balancing.stretchAfterLists,
|
|
8060
8763
|
maxLinesAfterList: balancing.maxLinesAfterList,
|
|
8764
|
+
stretchAfterDisplays: balancing.stretchAfterDisplays,
|
|
8061
8765
|
stretchAfterFloats: balancing.stretchAfterFloats,
|
|
8062
8766
|
maxLinesAfterFloat: balancing.maxLinesAfterFloat,
|
|
8767
|
+
stretchAfterWideFloats: balancing.stretchAfterWideFloats,
|
|
8063
8768
|
looseParagraphs: balancing.looseParagraphs,
|
|
8064
8769
|
maxLooseParagraphs: balancing.maxLooseParagraphs,
|
|
8065
8770
|
optimalLineBreaking: best.doc.config.bodyText.optimalLineBreaking,
|