postext 1.14.1 → 1.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/arabic/blockLanguageDigits.test.d.ts +2 -0
- package/dist/__tests__/arabic/blockLanguageDigits.test.d.ts.map +1 -0
- package/dist/__tests__/arabic/blockLanguageDigits.test.js +54 -0
- package/dist/__tests__/arabic/blockLanguageDigits.test.js.map +1 -0
- package/dist/__tests__/arabic/emphasis.test.d.ts +2 -0
- package/dist/__tests__/arabic/emphasis.test.d.ts.map +1 -0
- package/dist/__tests__/arabic/emphasis.test.js +206 -0
- package/dist/__tests__/arabic/emphasis.test.js.map +1 -0
- package/dist/__tests__/arabic/footnotes.test.d.ts +2 -0
- package/dist/__tests__/arabic/footnotes.test.d.ts.map +1 -0
- package/dist/__tests__/arabic/footnotes.test.js +118 -0
- package/dist/__tests__/arabic/footnotes.test.js.map +1 -0
- package/dist/__tests__/arabic/harakat.test.d.ts +2 -0
- package/dist/__tests__/arabic/harakat.test.d.ts.map +1 -0
- package/dist/__tests__/arabic/harakat.test.js +167 -0
- package/dist/__tests__/arabic/harakat.test.js.map +1 -0
- package/dist/__tests__/arabic/ornateBrackets.test.d.ts +2 -0
- package/dist/__tests__/arabic/ornateBrackets.test.d.ts.map +1 -0
- package/dist/__tests__/arabic/ornateBrackets.test.js +71 -0
- package/dist/__tests__/arabic/ornateBrackets.test.js.map +1 -0
- package/dist/__tests__/arabic/tashkil.test.d.ts +2 -0
- package/dist/__tests__/arabic/tashkil.test.d.ts.map +1 -0
- package/dist/__tests__/arabic/tashkil.test.js +106 -0
- package/dist/__tests__/arabic/tashkil.test.js.map +1 -0
- package/dist/__tests__/arabicLocale.test.d.ts +2 -0
- package/dist/__tests__/arabicLocale.test.d.ts.map +1 -0
- package/dist/__tests__/arabicLocale.test.js +232 -0
- package/dist/__tests__/arabicLocale.test.js.map +1 -0
- package/dist/__tests__/arabicNumberWords.test.d.ts +2 -0
- package/dist/__tests__/arabicNumberWords.test.d.ts.map +1 -0
- package/dist/__tests__/arabicNumberWords.test.js +176 -0
- package/dist/__tests__/arabicNumberWords.test.js.map +1 -0
- package/dist/__tests__/arabicNumbering.test.d.ts +2 -0
- package/dist/__tests__/arabicNumbering.test.d.ts.map +1 -0
- package/dist/__tests__/arabicNumbering.test.js +257 -0
- package/dist/__tests__/arabicNumbering.test.js.map +1 -0
- package/dist/__tests__/arabicWords.test.d.ts +2 -0
- package/dist/__tests__/arabicWords.test.d.ts.map +1 -0
- package/dist/__tests__/arabicWords.test.js +302 -0
- package/dist/__tests__/arabicWords.test.js.map +1 -0
- package/dist/__tests__/bidi.test.d.ts +2 -0
- package/dist/__tests__/bidi.test.d.ts.map +1 -0
- package/dist/__tests__/bidi.test.js +282 -0
- package/dist/__tests__/bidi.test.js.map +1 -0
- package/dist/__tests__/blockHints.test.d.ts +2 -0
- package/dist/__tests__/blockHints.test.d.ts.map +1 -0
- package/dist/__tests__/blockHints.test.js +79 -0
- package/dist/__tests__/blockHints.test.js.map +1 -0
- package/dist/__tests__/chineseLocale.test.js +2 -2
- package/dist/__tests__/chineseLocale.test.js.map +1 -1
- package/dist/__tests__/cjk/grid.test.js +2 -2
- package/dist/__tests__/cjk/grid.test.js.map +1 -1
- package/dist/__tests__/cjk/justifyRender.test.js +2 -1
- package/dist/__tests__/cjk/justifyRender.test.js.map +1 -1
- package/dist/__tests__/defaults/folio.test.js +16 -1
- package/dist/__tests__/defaults/folio.test.js.map +1 -1
- package/dist/__tests__/direction.test.d.ts +2 -0
- package/dist/__tests__/direction.test.d.ts.map +1 -0
- package/dist/__tests__/direction.test.js +117 -0
- package/dist/__tests__/direction.test.js.map +1 -0
- package/dist/__tests__/exports.test.js +29 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/__tests__/headingLetterSpacing.test.js +1 -1
- package/dist/__tests__/headingLetterSpacing.test.js.map +1 -1
- package/dist/__tests__/headingNumberPosition.test.d.ts +2 -0
- package/dist/__tests__/headingNumberPosition.test.d.ts.map +1 -0
- package/dist/__tests__/headingNumberPosition.test.js +87 -0
- package/dist/__tests__/headingNumberPosition.test.js.map +1 -0
- package/dist/__tests__/htmlCopyText.test.d.ts +2 -0
- package/dist/__tests__/htmlCopyText.test.d.ts.map +1 -0
- package/dist/__tests__/htmlCopyText.test.js +153 -0
- package/dist/__tests__/htmlCopyText.test.js.map +1 -0
- package/dist/__tests__/kashida.test.d.ts +2 -0
- package/dist/__tests__/kashida.test.d.ts.map +1 -0
- package/dist/__tests__/kashida.test.js +281 -0
- package/dist/__tests__/kashida.test.js.map +1 -0
- package/dist/__tests__/kashidaPatterns.test.d.ts +2 -0
- package/dist/__tests__/kashidaPatterns.test.d.ts.map +1 -0
- package/dist/__tests__/kashidaPatterns.test.js +143 -0
- package/dist/__tests__/kashidaPatterns.test.js.map +1 -0
- package/dist/__tests__/links.test.js +3 -1
- package/dist/__tests__/links.test.js.map +1 -1
- package/dist/__tests__/parse/anchors.test.js +17 -0
- package/dist/__tests__/parse/anchors.test.js.map +1 -1
- package/dist/__tests__/parse/containers.test.js +1 -1
- package/dist/__tests__/parse/containers.test.js.map +1 -1
- package/dist/__tests__/rtl/designText.test.d.ts +2 -0
- package/dist/__tests__/rtl/designText.test.d.ts.map +1 -0
- package/dist/__tests__/rtl/designText.test.js +301 -0
- package/dist/__tests__/rtl/designText.test.js.map +1 -0
- package/dist/__tests__/rtl/designTextPaint.test.d.ts +2 -0
- package/dist/__tests__/rtl/designTextPaint.test.d.ts.map +1 -0
- package/dist/__tests__/rtl/designTextPaint.test.js +140 -0
- package/dist/__tests__/rtl/designTextPaint.test.js.map +1 -0
- package/dist/__tests__/rtl/htmlRtl.test.d.ts +2 -0
- package/dist/__tests__/rtl/htmlRtl.test.d.ts.map +1 -0
- package/dist/__tests__/rtl/htmlRtl.test.js +175 -0
- package/dist/__tests__/rtl/htmlRtl.test.js.map +1 -0
- package/dist/__tests__/rtl/mirroredFrame.test.d.ts +2 -0
- package/dist/__tests__/rtl/mirroredFrame.test.d.ts.map +1 -0
- package/dist/__tests__/rtl/mirroredFrame.test.js +313 -0
- package/dist/__tests__/rtl/mirroredFrame.test.js.map +1 -0
- package/dist/__tests__/rtl/mirroredPaint.test.d.ts +2 -0
- package/dist/__tests__/rtl/mirroredPaint.test.d.ts.map +1 -0
- package/dist/__tests__/rtl/mirroredPaint.test.js +116 -0
- package/dist/__tests__/rtl/mirroredPaint.test.js.map +1 -0
- package/dist/__tests__/rtl/oppositeBlocks.test.d.ts +2 -0
- package/dist/__tests__/rtl/oppositeBlocks.test.d.ts.map +1 -0
- package/dist/__tests__/rtl/oppositeBlocks.test.js +273 -0
- package/dist/__tests__/rtl/oppositeBlocks.test.js.map +1 -0
- package/dist/__tests__/rtl/segmentLang.test.d.ts +2 -0
- package/dist/__tests__/rtl/segmentLang.test.d.ts.map +1 -0
- package/dist/__tests__/rtl/segmentLang.test.js +54 -0
- package/dist/__tests__/rtl/segmentLang.test.js.map +1 -0
- package/dist/__tests__/rtlLines.test.d.ts +2 -0
- package/dist/__tests__/rtlLines.test.d.ts.map +1 -0
- package/dist/__tests__/rtlLines.test.js +180 -0
- package/dist/__tests__/rtlLines.test.js.map +1 -0
- package/dist/__tests__/tocNumberColumn.test.d.ts +2 -0
- package/dist/__tests__/tocNumberColumn.test.d.ts.map +1 -0
- package/dist/__tests__/tocNumberColumn.test.js +67 -0
- package/dist/__tests__/tocNumberColumn.test.js.map +1 -0
- package/dist/__tests__/verse.test.d.ts +2 -0
- package/dist/__tests__/verse.test.d.ts.map +1 -0
- package/dist/__tests__/verse.test.js +232 -0
- package/dist/__tests__/verse.test.js.map +1 -0
- package/dist/__tests__/vertical/geometry.test.js +2 -2
- package/dist/__tests__/vertical/geometry.test.js.map +1 -1
- package/dist/__tests__/vertical/htmlTurnedCells.test.js +2 -2
- package/dist/__tests__/vertical/htmlTurnedCells.test.js.map +1 -1
- package/dist/arabicMarks.d.ts +80 -0
- package/dist/arabicMarks.d.ts.map +1 -0
- package/dist/arabicMarks.js +267 -0
- package/dist/arabicMarks.js.map +1 -0
- package/dist/arabicNumberWords.d.ts +43 -0
- package/dist/arabicNumberWords.d.ts.map +1 -0
- package/dist/arabicNumberWords.js +163 -0
- package/dist/arabicNumberWords.js.map +1 -0
- package/dist/arabicNumerals.d.ts +54 -0
- package/dist/arabicNumerals.d.ts.map +1 -0
- package/dist/arabicNumerals.js +143 -0
- package/dist/arabicNumerals.js.map +1 -0
- package/dist/bidi.d.ts +186 -0
- package/dist/bidi.d.ts.map +1 -0
- package/dist/bidi.js +851 -0
- package/dist/bidi.js.map +1 -0
- package/dist/bidiData.d.ts +13 -0
- package/dist/bidiData.d.ts.map +1 -0
- package/dist/bidiData.js +318 -0
- package/dist/bidiData.js.map +1 -0
- package/dist/canvas-backend/blockRender.d.ts.map +1 -1
- package/dist/canvas-backend/blockRender.js +58 -27
- package/dist/canvas-backend/blockRender.js.map +1 -1
- package/dist/canvas-backend/chip.d.ts.map +1 -1
- package/dist/canvas-backend/chip.js +16 -2
- 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 +7 -3
- package/dist/canvas-backend/headerFooter.js.map +1 -1
- package/dist/canvas-backend/index.d.ts.map +1 -1
- package/dist/canvas-backend/index.js +9 -4
- package/dist/canvas-backend/index.js.map +1 -1
- package/dist/canvas-backend/mirrorFrame.d.ts +38 -0
- package/dist/canvas-backend/mirrorFrame.d.ts.map +1 -0
- package/dist/canvas-backend/mirrorFrame.js +129 -0
- package/dist/canvas-backend/mirrorFrame.js.map +1 -0
- package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
- package/dist/canvas-backend/renderResourceBlock.js +16 -5
- package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
- package/dist/canvas-backend/runDirection.d.ts +21 -0
- package/dist/canvas-backend/runDirection.d.ts.map +1 -0
- package/dist/canvas-backend/runDirection.js +46 -0
- package/dist/canvas-backend/runDirection.js.map +1 -0
- package/dist/canvas-backend/wordRuns.d.ts +49 -0
- package/dist/canvas-backend/wordRuns.d.ts.map +1 -0
- package/dist/canvas-backend/wordRuns.js +111 -0
- package/dist/canvas-backend/wordRuns.js.map +1 -0
- package/dist/columnClip.d.ts +4 -1
- package/dist/columnClip.d.ts.map +1 -1
- package/dist/columnClip.js +8 -3
- package/dist/columnClip.js.map +1 -1
- package/dist/configWarnings.d.ts +3 -1
- package/dist/configWarnings.d.ts.map +1 -1
- package/dist/configWarnings.js +59 -5
- package/dist/configWarnings.js.map +1 -1
- package/dist/defaults/bodyText.d.ts +28 -6
- package/dist/defaults/bodyText.d.ts.map +1 -1
- package/dist/defaults/bodyText.js +158 -30
- package/dist/defaults/bodyText.js.map +1 -1
- package/dist/defaults/calloutStyles.js +1 -1
- package/dist/defaults/calloutStyles.js.map +1 -1
- package/dist/defaults/captionStyle.js +5 -5
- package/dist/defaults/captionStyle.js.map +1 -1
- package/dist/defaults/folio.d.ts +4 -0
- package/dist/defaults/folio.d.ts.map +1 -1
- package/dist/defaults/folio.js +12 -1
- package/dist/defaults/folio.js.map +1 -1
- package/dist/defaults/footnotes.d.ts.map +1 -1
- package/dist/defaults/footnotes.js +12 -2
- package/dist/defaults/footnotes.js.map +1 -1
- package/dist/defaults/headerFooter.d.ts.map +1 -1
- package/dist/defaults/headerFooter.js +1 -0
- package/dist/defaults/headerFooter.js.map +1 -1
- package/dist/defaults/headingStyles.d.ts.map +1 -1
- package/dist/defaults/headingStyles.js +2 -1
- package/dist/defaults/headingStyles.js.map +1 -1
- package/dist/defaults/headings.d.ts.map +1 -1
- package/dist/defaults/headings.js +9 -2
- package/dist/defaults/headings.js.map +1 -1
- package/dist/defaults/index.d.ts +1 -1
- package/dist/defaults/index.d.ts.map +1 -1
- package/dist/defaults/index.js +7 -1
- package/dist/defaults/index.js.map +1 -1
- package/dist/defaults/indexConfig.d.ts +6 -2
- package/dist/defaults/indexConfig.d.ts.map +1 -1
- package/dist/defaults/indexConfig.js +25 -5
- package/dist/defaults/indexConfig.js.map +1 -1
- package/dist/defaults/page.d.ts +7 -4
- package/dist/defaults/page.d.ts.map +1 -1
- package/dist/defaults/page.js +10 -7
- package/dist/defaults/page.js.map +1 -1
- package/dist/defaults/paragraphStyles.js +2 -2
- package/dist/defaults/paragraphStyles.js.map +1 -1
- package/dist/defaults/parts.d.ts.map +1 -1
- package/dist/defaults/parts.js +2 -1
- package/dist/defaults/parts.js.map +1 -1
- package/dist/defaults/resourceTypes.d.ts +1 -1
- package/dist/defaults/resourceTypes.d.ts.map +1 -1
- package/dist/defaults/resourceTypes.js +10 -2
- package/dist/defaults/resourceTypes.js.map +1 -1
- package/dist/defaults/shared.d.ts +9 -0
- package/dist/defaults/shared.d.ts.map +1 -1
- package/dist/defaults/shared.js +15 -0
- package/dist/defaults/shared.js.map +1 -1
- package/dist/defaults/tableStyle.d.ts.map +1 -1
- package/dist/defaults/tableStyle.js +5 -1
- package/dist/defaults/tableStyle.js.map +1 -1
- package/dist/design/bidiText.d.ts +89 -0
- package/dist/design/bidiText.d.ts.map +1 -0
- package/dist/design/bidiText.js +165 -0
- package/dist/design/bidiText.js.map +1 -0
- package/dist/design/layout.d.ts +20 -0
- package/dist/design/layout.d.ts.map +1 -1
- package/dist/design/layout.js +46 -5
- package/dist/design/layout.js.map +1 -1
- package/dist/design/placeholders.d.ts +7 -1
- package/dist/design/placeholders.d.ts.map +1 -1
- package/dist/design/placeholders.js +6 -3
- package/dist/design/placeholders.js.map +1 -1
- package/dist/design/richText.d.ts +5 -2
- package/dist/design/richText.d.ts.map +1 -1
- package/dist/design/richText.js +35 -2
- package/dist/design/richText.js.map +1 -1
- package/dist/emphasisOverline.d.ts +27 -0
- package/dist/emphasisOverline.d.ts.map +1 -0
- package/dist/emphasisOverline.js +107 -0
- package/dist/emphasisOverline.js.map +1 -0
- package/dist/frontmatter.d.ts +25 -6
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +51 -10
- package/dist/frontmatter.js.map +1 -1
- package/dist/html-backend.d.ts +4 -1
- package/dist/html-backend.d.ts.map +1 -1
- package/dist/html-backend.js +363 -87
- package/dist/html-backend.js.map +1 -1
- package/dist/hyphenate.d.ts.map +1 -1
- package/dist/hyphenate.js +4 -1
- package/dist/hyphenate.js.map +1 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/knuthPlass/breakpoints.d.ts.map +1 -1
- package/dist/knuthPlass/breakpoints.js +3 -0
- package/dist/knuthPlass/breakpoints.js.map +1 -1
- package/dist/knuthPlass/pretextAdapter.d.ts.map +1 -1
- package/dist/knuthPlass/pretextAdapter.js +9 -3
- package/dist/knuthPlass/pretextAdapter.js.map +1 -1
- package/dist/knuthPlass/richAdapter.d.ts +11 -0
- package/dist/knuthPlass/richAdapter.d.ts.map +1 -1
- package/dist/knuthPlass/richAdapter.js +11 -4
- package/dist/knuthPlass/richAdapter.js.map +1 -1
- package/dist/knuthPlass/tracking.d.ts +2 -1
- package/dist/knuthPlass/tracking.d.ts.map +1 -1
- package/dist/knuthPlass/tracking.js +5 -2
- package/dist/knuthPlass/tracking.js.map +1 -1
- package/dist/knuthPlass/types.d.ts +4 -0
- package/dist/knuthPlass/types.d.ts.map +1 -1
- package/dist/locale.d.ts +63 -9
- package/dist/locale.d.ts.map +1 -1
- package/dist/locale.js +129 -12
- package/dist/locale.js.map +1 -1
- package/dist/measure/bidiLines.d.ts +91 -0
- package/dist/measure/bidiLines.d.ts.map +1 -0
- package/dist/measure/bidiLines.js +293 -0
- package/dist/measure/bidiLines.js.map +1 -0
- package/dist/measure/cache.d.ts.map +1 -1
- package/dist/measure/cache.js +10 -4
- package/dist/measure/cache.js.map +1 -1
- package/dist/measure/joining.d.ts +39 -0
- package/dist/measure/joining.d.ts.map +1 -0
- package/dist/measure/joining.js +91 -0
- package/dist/measure/joining.js.map +1 -0
- package/dist/measure/joiningGroups.d.ts +7 -0
- package/dist/measure/joiningGroups.d.ts.map +1 -0
- package/dist/measure/joiningGroups.js +110 -0
- package/dist/measure/joiningGroups.js.map +1 -0
- package/dist/measure/kashida.d.ts +97 -0
- package/dist/measure/kashida.d.ts.map +1 -0
- package/dist/measure/kashida.js +285 -0
- package/dist/measure/kashida.js.map +1 -0
- package/dist/measure/kashidaPatterns.d.ts +109 -0
- package/dist/measure/kashidaPatterns.d.ts.map +1 -0
- package/dist/measure/kashidaPatterns.js +519 -0
- package/dist/measure/kashidaPatterns.js.map +1 -0
- package/dist/measure/links.d.ts.map +1 -1
- package/dist/measure/links.js +5 -2
- package/dist/measure/links.js.map +1 -1
- package/dist/measure/plain.d.ts.map +1 -1
- package/dist/measure/plain.js +31 -0
- package/dist/measure/plain.js.map +1 -1
- package/dist/measure/rich.d.ts +24 -0
- package/dist/measure/rich.d.ts.map +1 -1
- package/dist/measure/rich.js +250 -22
- package/dist/measure/rich.js.map +1 -1
- package/dist/measure/types.d.ts +14 -0
- package/dist/measure/types.d.ts.map +1 -1
- package/dist/measure/types.js.map +1 -1
- package/dist/numberWords.d.ts +17 -4
- package/dist/numberWords.d.ts.map +1 -1
- package/dist/numberWords.js +19 -13
- package/dist/numberWords.js.map +1 -1
- package/dist/numbering.d.ts +49 -11
- package/dist/numbering.d.ts.map +1 -1
- package/dist/numbering.js +117 -21
- package/dist/numbering.js.map +1 -1
- package/dist/parse/annotations.d.ts +6 -3
- package/dist/parse/annotations.d.ts.map +1 -1
- package/dist/parse/annotations.js +31 -7
- package/dist/parse/annotations.js.map +1 -1
- package/dist/parse/attrs.d.ts +3 -3
- package/dist/parse/attrs.d.ts.map +1 -1
- package/dist/parse/attrs.js +5 -4
- package/dist/parse/attrs.js.map +1 -1
- package/dist/parse/blockParser.d.ts.map +1 -1
- package/dist/parse/blockParser.js +158 -14
- package/dist/parse/blockParser.js.map +1 -1
- package/dist/parse/index.d.ts +1 -1
- package/dist/parse/index.d.ts.map +1 -1
- package/dist/parse/index.js.map +1 -1
- package/dist/parse/indexMarks.d.ts.map +1 -1
- package/dist/parse/indexMarks.js +32 -10
- package/dist/parse/indexMarks.js.map +1 -1
- package/dist/parse/inlineFormatting.d.ts.map +1 -1
- package/dist/parse/inlineFormatting.js +5 -4
- package/dist/parse/inlineFormatting.js.map +1 -1
- package/dist/parse/types.d.ts +63 -1
- package/dist/parse/types.d.ts.map +1 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +161 -43
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/buildBlockKind.d.ts +2 -0
- package/dist/pipeline/buildBlockKind.d.ts.map +1 -1
- package/dist/pipeline/buildBlockKind.js +67 -2
- package/dist/pipeline/buildBlockKind.js.map +1 -1
- package/dist/pipeline/buildHelpers.d.ts +22 -1
- package/dist/pipeline/buildHelpers.d.ts.map +1 -1
- package/dist/pipeline/buildHelpers.js +55 -5
- package/dist/pipeline/buildHelpers.js.map +1 -1
- package/dist/pipeline/calloutLayout.d.ts +6 -1
- package/dist/pipeline/calloutLayout.d.ts.map +1 -1
- package/dist/pipeline/calloutLayout.js +63 -18
- package/dist/pipeline/calloutLayout.js.map +1 -1
- package/dist/pipeline/citations.d.ts +2 -1
- package/dist/pipeline/citations.d.ts.map +1 -1
- package/dist/pipeline/citations.js +29 -9
- package/dist/pipeline/citations.js.map +1 -1
- package/dist/pipeline/cjkGrid.d.ts +3 -2
- package/dist/pipeline/cjkGrid.d.ts.map +1 -1
- package/dist/pipeline/cjkGrid.js +3 -2
- package/dist/pipeline/cjkGrid.js.map +1 -1
- package/dist/pipeline/config.d.ts +13 -1
- package/dist/pipeline/config.d.ts.map +1 -1
- package/dist/pipeline/config.js +32 -3
- package/dist/pipeline/config.js.map +1 -1
- package/dist/pipeline/contentWarnings.d.ts +10 -0
- package/dist/pipeline/contentWarnings.d.ts.map +1 -1
- package/dist/pipeline/contentWarnings.js +88 -0
- package/dist/pipeline/contentWarnings.js.map +1 -1
- package/dist/pipeline/continuation.d.ts.map +1 -1
- package/dist/pipeline/continuation.js +1 -1
- package/dist/pipeline/continuation.js.map +1 -1
- package/dist/pipeline/crossRefs.d.ts.map +1 -1
- package/dist/pipeline/crossRefs.js +2 -0
- package/dist/pipeline/crossRefs.js.map +1 -1
- package/dist/pipeline/floatPlacement.d.ts.map +1 -1
- package/dist/pipeline/floatPlacement.js +2 -1
- package/dist/pipeline/floatPlacement.js.map +1 -1
- package/dist/pipeline/footnotes.d.ts +13 -5
- package/dist/pipeline/footnotes.d.ts.map +1 -1
- package/dist/pipeline/footnotes.js +19 -8
- package/dist/pipeline/footnotes.js.map +1 -1
- package/dist/pipeline/headerFooter.d.ts +4 -0
- package/dist/pipeline/headerFooter.d.ts.map +1 -1
- package/dist/pipeline/headerFooter.js +41 -13
- package/dist/pipeline/headerFooter.js.map +1 -1
- package/dist/pipeline/headingDesignCuts.d.ts +1 -1
- package/dist/pipeline/headingDesignCuts.d.ts.map +1 -1
- package/dist/pipeline/headingDesignCuts.js +2 -1
- package/dist/pipeline/headingDesignCuts.js.map +1 -1
- package/dist/pipeline/headingStyles.d.ts +10 -0
- package/dist/pipeline/headingStyles.d.ts.map +1 -1
- package/dist/pipeline/headingStyles.js +46 -0
- package/dist/pipeline/headingStyles.js.map +1 -1
- package/dist/pipeline/indexDirective.d.ts.map +1 -1
- package/dist/pipeline/indexDirective.js +33 -6
- package/dist/pipeline/indexDirective.js.map +1 -1
- package/dist/pipeline/indexGroups.d.ts +23 -1
- package/dist/pipeline/indexGroups.d.ts.map +1 -1
- package/dist/pipeline/indexGroups.js +50 -1
- package/dist/pipeline/indexGroups.js.map +1 -1
- package/dist/pipeline/lists.d.ts +16 -4
- package/dist/pipeline/lists.d.ts.map +1 -1
- package/dist/pipeline/lists.js +51 -12
- package/dist/pipeline/lists.js.map +1 -1
- package/dist/pipeline/measureContentBlock.d.ts +5 -0
- package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
- package/dist/pipeline/measureContentBlock.js +63 -4
- package/dist/pipeline/measureContentBlock.js.map +1 -1
- package/dist/pipeline/mirrorFrame.d.ts +37 -0
- package/dist/pipeline/mirrorFrame.d.ts.map +1 -0
- package/dist/pipeline/mirrorFrame.js +143 -0
- package/dist/pipeline/mirrorFrame.js.map +1 -0
- package/dist/pipeline/outline.d.ts +2 -2
- package/dist/pipeline/outline.d.ts.map +1 -1
- package/dist/pipeline/outline.js +33 -6
- package/dist/pipeline/outline.js.map +1 -1
- package/dist/pipeline/paragraphContainers.d.ts +5 -0
- package/dist/pipeline/paragraphContainers.d.ts.map +1 -1
- package/dist/pipeline/paragraphContainers.js +12 -0
- package/dist/pipeline/paragraphContainers.js.map +1 -1
- package/dist/pipeline/parts.d.ts +1 -1
- package/dist/pipeline/parts.d.ts.map +1 -1
- package/dist/pipeline/parts.js +3 -2
- package/dist/pipeline/parts.js.map +1 -1
- package/dist/pipeline/placeholders.d.ts +13 -6
- package/dist/pipeline/placeholders.d.ts.map +1 -1
- package/dist/pipeline/placeholders.js +15 -11
- package/dist/pipeline/placeholders.js.map +1 -1
- package/dist/pipeline/placement.d.ts +3 -2
- package/dist/pipeline/placement.d.ts.map +1 -1
- package/dist/pipeline/placement.js +18 -6
- package/dist/pipeline/placement.js.map +1 -1
- package/dist/pipeline/resourceLayout.d.ts.map +1 -1
- package/dist/pipeline/resourceLayout.js +70 -7
- package/dist/pipeline/resourceLayout.js.map +1 -1
- package/dist/pipeline/resourceNumbering.d.ts +5 -3
- package/dist/pipeline/resourceNumbering.d.ts.map +1 -1
- package/dist/pipeline/resourceNumbering.js +11 -8
- package/dist/pipeline/resourceNumbering.js.map +1 -1
- package/dist/pipeline/styles.d.ts +6 -1
- package/dist/pipeline/styles.d.ts.map +1 -1
- package/dist/pipeline/styles.js +44 -14
- package/dist/pipeline/styles.js.map +1 -1
- package/dist/pipeline/tashkil.d.ts +27 -0
- package/dist/pipeline/tashkil.d.ts.map +1 -0
- package/dist/pipeline/tashkil.js +161 -0
- package/dist/pipeline/tashkil.js.map +1 -0
- package/dist/pipeline/toc.d.ts +12 -0
- package/dist/pipeline/toc.d.ts.map +1 -1
- package/dist/pipeline/toc.js +64 -4
- package/dist/pipeline/toc.js.map +1 -1
- package/dist/pipeline/verse.d.ts +65 -0
- package/dist/pipeline/verse.d.ts.map +1 -0
- package/dist/pipeline/verse.js +252 -0
- package/dist/pipeline/verse.js.map +1 -0
- package/dist/pipeline/verticalMetrics.d.ts +1 -1
- package/dist/pipeline/verticalMetrics.d.ts.map +1 -1
- package/dist/pipeline/verticalMetrics.js +7 -5
- package/dist/pipeline/verticalMetrics.js.map +1 -1
- package/dist/table/model.d.ts +4 -3
- package/dist/table/model.d.ts.map +1 -1
- package/dist/table/model.js.map +1 -1
- package/dist/types.d.ts +286 -36
- package/dist/types.d.ts.map +1 -1
- package/dist/uprightArabic.d.ts +39 -0
- package/dist/uprightArabic.d.ts.map +1 -0
- package/dist/uprightArabic.js +105 -0
- package/dist/uprightArabic.js.map +1 -0
- package/dist/vdt.d.ts +276 -11
- package/dist/vdt.d.ts.map +1 -1
- package/dist/vdt.js +46 -9
- package/dist/vdt.js.map +1 -1
- package/package.json +1 -1
package/dist/html-backend.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { footnoteRuleSegments } from './columnRule';
|
|
2
|
-
import { tableCellFillRects, tableFrameOutline } from './vdt';
|
|
2
|
+
import { lineTextAlign, tableCellFillRects, tableFrameOutline } from './vdt';
|
|
3
3
|
import { dimensionToPx } from './units';
|
|
4
4
|
import { documentInkHex, isSingleInkSvgUrl, singleInkColorMatrix } from './svg/singleInk';
|
|
5
5
|
import { lineInkExtent, lineTrailingTracking } from './lineInk';
|
|
6
6
|
import { CHARACTER_GRID_COLOR, cjkGridCells } from './pipeline/cjkGrid';
|
|
7
7
|
import { renderLangOf } from './locale';
|
|
8
8
|
import { hasCJK } from './measure/cjk';
|
|
9
|
-
import {
|
|
9
|
+
import { joiningScriptIn } from './measure/joining';
|
|
10
|
+
import { DEFAULT_CENTRAL_BASELINE, verticalFlowOf } from './vdt';
|
|
10
11
|
import { holdsTurnedMark, segmentOrientation, verticalRuns } from './writingMode';
|
|
11
12
|
import { graphemesOf } from './measure/graphemes';
|
|
12
13
|
import { fontFamilyOf } from './measure/vertical';
|
|
@@ -44,6 +45,93 @@ function lineCjkDecl(line) {
|
|
|
44
45
|
function segmentCjk(seg, lineDecl) {
|
|
45
46
|
return lineDecl ? 'line' : hasCJK(seg.text) ? 'own' : false;
|
|
46
47
|
}
|
|
48
|
+
/** The `dir` attribute of a box of text running `own`, inside boxes that
|
|
49
|
+
* run `inherited` (#379): only where the two differ, so the markup of a
|
|
50
|
+
* left-to-right document, whose text never runs right to left, carries
|
|
51
|
+
* none. A box with `dir` is also a bidi isolate (the HTML default), so its
|
|
52
|
+
* neutrals — a full stop, a bracket — resolve inside it, as the engine
|
|
53
|
+
* resolved them in the run it measured. */
|
|
54
|
+
function dirAttr(own, inherited) {
|
|
55
|
+
return own === inherited ? '' : ` dir="${own}"`;
|
|
56
|
+
}
|
|
57
|
+
const PLAIN_BOX = { attrs: '', decl: '' };
|
|
58
|
+
/**
|
|
59
|
+
* The box of a word segment of a line (#379): its direction against the
|
|
60
|
+
* one it inherits, the language the author named for its text
|
|
61
|
+
* (`VDTLineSegment.lang`) where it is not the root's (`rootLang`), its
|
|
62
|
+
* letters untracked when they are of a joining script on a tracked line
|
|
63
|
+
* (`tracking`), and its styled runs (`VDTLineSegment.runs`) painted by
|
|
64
|
+
* `paint` around the segment's own `font` / `color`.
|
|
65
|
+
*/
|
|
66
|
+
function segmentBox(seg, inherited, rootLang, tracking, font, color, paint) {
|
|
67
|
+
const attrs = dirAttr(seg.rtl ? 'rtl' : 'ltr', inherited) + (seg.lang !== undefined && seg.lang !== rootLang ? ` lang="${esc(seg.lang)}"` : '');
|
|
68
|
+
const decl = tracking !== 0 && joiningScriptIn(seg.text) ? 'letter-spacing:0;' : '';
|
|
69
|
+
const html = seg.runs && seg.runs.length > 0 ? wordRunsHtml(seg, font, color, paint)
|
|
70
|
+
: seg.kashida && seg.kashida.length > 0 ? kashidaTextHtml(seg.text, seg.kashida) : undefined;
|
|
71
|
+
if (!attrs && !decl && html === undefined)
|
|
72
|
+
return PLAIN_BOX;
|
|
73
|
+
return html === undefined ? { attrs, decl } : { attrs, decl, html };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A word whose letters change style inside it (`VDTLineSegment.runs`: a
|
|
77
|
+
* bold letter, a coloured haraka) as one run of text with inline spans for
|
|
78
|
+
* the styled parts. The browser shapes the word whole across the spans, so
|
|
79
|
+
* the letters of a joining script stay joined, where boxes positioned one
|
|
80
|
+
* by one would break them apart. A run in the segment's own font and colour
|
|
81
|
+
* is plain text; one in another face takes no line height, so it sits on
|
|
82
|
+
* the segment's baseline without growing its box.
|
|
83
|
+
*/
|
|
84
|
+
function wordRunsHtml(seg, font, color, paint) {
|
|
85
|
+
// Where each run starts in the segment's text, for its inserted
|
|
86
|
+
// tatweels (`VDTLineSegment.kashida`).
|
|
87
|
+
let at = 0;
|
|
88
|
+
return seg.runs.map((run) => {
|
|
89
|
+
const start = at;
|
|
90
|
+
at += run.text.length;
|
|
91
|
+
const text = kashidaTextHtml(run.text, seg.kashida, start);
|
|
92
|
+
const probe = {
|
|
93
|
+
kind: 'text', text: run.text, width: 0,
|
|
94
|
+
...(run.bold ? { bold: true } : {}),
|
|
95
|
+
...(run.italic ? { italic: true } : {}),
|
|
96
|
+
...(seg.fontString ? { fontString: seg.fontString } : {}),
|
|
97
|
+
};
|
|
98
|
+
const own = paint(probe);
|
|
99
|
+
const runColor = run.color ?? own.color;
|
|
100
|
+
const decl = (own.font !== font ? `font:${own.font};line-height:0;` : '') + (runColor !== color ? `color:${runColor};` : '');
|
|
101
|
+
return decl ? `<span style="${decl}">${text}</span>` : text;
|
|
102
|
+
}).join('');
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* `text` escaped, with the tatweels kashida justification inserted into it
|
|
106
|
+
* (#375; `offsets` into the segment's text, of which `text` starts at
|
|
107
|
+
* `base`) in spans that cannot be selected: they are painted, joined to
|
|
108
|
+
* the letters around them (the browser shapes one font's text whole
|
|
109
|
+
* across spans), but a copy of the page reads the words as written, as
|
|
110
|
+
* the PDF's text does. A tatweel the author typed is not among the
|
|
111
|
+
* offsets and copies. Plain `esc(text)` when none falls in it.
|
|
112
|
+
*/
|
|
113
|
+
function kashidaTextHtml(text, offsets, base = 0) {
|
|
114
|
+
if (!offsets || offsets.length === 0)
|
|
115
|
+
return esc(text);
|
|
116
|
+
let out = '';
|
|
117
|
+
let last = 0;
|
|
118
|
+
for (let k = 0; k < offsets.length; k++) {
|
|
119
|
+
const i = offsets[k] - base;
|
|
120
|
+
if (i < last || i >= text.length)
|
|
121
|
+
continue;
|
|
122
|
+
// Consecutive tatweels (a longer elongation) share one span.
|
|
123
|
+
let j = i + 1;
|
|
124
|
+
while (k + 1 < offsets.length && offsets[k + 1] - base === j && j < text.length) {
|
|
125
|
+
j++;
|
|
126
|
+
k++;
|
|
127
|
+
}
|
|
128
|
+
out += `${esc(text.slice(last, i))}<span style="${KASHIDA_DECL}">${esc(text.slice(i, j))}</span>`;
|
|
129
|
+
last = j;
|
|
130
|
+
}
|
|
131
|
+
return out + esc(text.slice(last));
|
|
132
|
+
}
|
|
133
|
+
/** Inserted tatweels: painted, never selected or copied. */
|
|
134
|
+
const KASHIDA_DECL = '-webkit-user-select:none;user-select:none;';
|
|
47
135
|
/**
|
|
48
136
|
* The resources this document anchors in its HTML (`id="pt-res-<id>"`):
|
|
49
137
|
* those whose embed (a first slice, for a split table) is on one of its
|
|
@@ -231,25 +319,27 @@ tracking = 0,
|
|
|
231
319
|
/** Whether the browser's punctuation spacing is off for the segment
|
|
232
320
|
* (see {@link CJK_TEXT_DECL}): set by its line (`'line'`) or on its own
|
|
233
321
|
* box (`'own'`); a box in another face repeats the features either way. */
|
|
234
|
-
cjk = false
|
|
322
|
+
cjk = false,
|
|
323
|
+
/** Its direction where it differs from its line's (see {@link segmentBox}). */
|
|
324
|
+
box = PLAIN_BOX) {
|
|
235
325
|
const spacingDecl = seg.tracking !== undefined ? `letter-spacing:${tracking + seg.tracking}px;` : '';
|
|
236
326
|
// A compressed CJK mark is painted before its box (`inkOffset`).
|
|
237
327
|
const left = seg.inkOffset !== undefined ? x + seg.inkOffset : x;
|
|
238
328
|
const scaleDecl = seg.inkScale !== undefined ? inkScaleDecl(seg.inkScale) : '';
|
|
239
|
-
const pos = `position:absolute;left:${left.toFixed(3)}px;top:${top};white-space:pre;${spacingDecl}${cjk === 'own' ? CJK_TEXT_DECL : ''}${scaleDecl}`;
|
|
329
|
+
const pos = `position:absolute;left:${left.toFixed(3)}px;top:${top};white-space:pre;${spacingDecl}${cjk === 'own' ? CJK_TEXT_DECL : ''}${scaleDecl}${box.decl}`;
|
|
240
330
|
// Text set with emphasis dots is emphasis (#193); the dots are the
|
|
241
331
|
// line's marks.
|
|
242
|
-
const text = seg.cjkMarks?.dots ? `<em style="font-style:inherit;">${esc(seg.text)}</em>` : esc(seg.text);
|
|
332
|
+
const text = seg.cjkMarks?.dots ? `<em style="font-style:inherit;">${esc(seg.text)}</em>` : box.html ?? esc(seg.text);
|
|
243
333
|
const featuresDecl = !fontDecl ? '' : scaleDecl ? DASH_FEATURES_DECL : cjk ? CJK_FEATURES_DECL : '';
|
|
244
334
|
if (seg.refResourceId !== undefined) {
|
|
245
335
|
// Anchors carry an explicit color so the UA link blue never leaks in.
|
|
246
336
|
const inner = `<a href="${refAnchorHref(refKey(seg))}" style="text-decoration:none;${fontDecl}${featuresDecl}${fontDecl ? 'line-height:0;' : ''}color:${color};">${text}</a>`;
|
|
247
|
-
return `<span style="${pos}">${inner}</span>`;
|
|
337
|
+
return `<span${box.attrs} style="${pos}">${inner}</span>`;
|
|
248
338
|
}
|
|
249
339
|
if (fontDecl) {
|
|
250
|
-
return `<span style="${pos}"><span style="${fontDecl}${featuresDecl}line-height:0;${colorDecl}">${text}</span></span>`;
|
|
340
|
+
return `<span${box.attrs} style="${pos}"><span style="${fontDecl}${featuresDecl}line-height:0;${colorDecl}">${text}</span></span>`;
|
|
251
341
|
}
|
|
252
|
-
return `<span style="${pos}${colorDecl}">${text}</span>`;
|
|
342
|
+
return `<span${box.attrs} style="${pos}${colorDecl}">${text}</span>`;
|
|
253
343
|
}
|
|
254
344
|
/**
|
|
255
345
|
* {@link renderTextSegment} for a segment of a line set word by word (not
|
|
@@ -260,38 +350,40 @@ cjk = false) {
|
|
|
260
350
|
* punctuation spacing off on its own box (see {@link CJK_TEXT_DECL}), its
|
|
261
351
|
* text in `<em>` when it is set with emphasis dots.
|
|
262
352
|
*/
|
|
263
|
-
function renderWordTextSegment(seg, x, top, fontDecl, colorDecl, color, cjk
|
|
353
|
+
function renderWordTextSegment(seg, x, top, fontDecl, colorDecl, color, cjk,
|
|
354
|
+
/** Its direction, tracking and styled runs (see {@link segmentBox}). */
|
|
355
|
+
box = PLAIN_BOX) {
|
|
264
356
|
if (cjk || seg.cjkMarks)
|
|
265
|
-
return renderMarkedWordSegment(seg, x, top, fontDecl, colorDecl, color, cjk);
|
|
266
|
-
const pos = `position:absolute;left:${x.toFixed(3)}px;top:${top};white-space:pre
|
|
267
|
-
const text = esc(seg.text);
|
|
357
|
+
return renderMarkedWordSegment(seg, x, top, fontDecl, colorDecl, color, cjk, box);
|
|
358
|
+
const pos = `position:absolute;left:${x.toFixed(3)}px;top:${top};white-space:pre;${box.decl}`;
|
|
359
|
+
const text = box.html ?? esc(seg.text);
|
|
268
360
|
if (seg.refResourceId !== undefined) {
|
|
269
361
|
// Anchors carry an explicit color so the UA link blue never leaks in.
|
|
270
362
|
const inner = `<a href="${refAnchorHref(refKey(seg))}" style="text-decoration:none;${fontDecl}${fontDecl ? 'line-height:0;' : ''}color:${color};">${text}</a>`;
|
|
271
|
-
return `<span style="${pos}">${inner}</span>`;
|
|
363
|
+
return `<span${box.attrs} style="${pos}">${inner}</span>`;
|
|
272
364
|
}
|
|
273
365
|
if (fontDecl) {
|
|
274
|
-
return `<span style="${pos}"><span style="${fontDecl}line-height:0;${colorDecl}">${text}</span></span>`;
|
|
366
|
+
return `<span${box.attrs} style="${pos}"><span style="${fontDecl}line-height:0;${colorDecl}">${text}</span></span>`;
|
|
275
367
|
}
|
|
276
|
-
return `<span style="${pos}${colorDecl}">${text}</span>`;
|
|
368
|
+
return `<span${box.attrs} style="${pos}${colorDecl}">${text}</span>`;
|
|
277
369
|
}
|
|
278
370
|
/** {@link renderWordTextSegment} for a segment that holds CJK text (`cjk`)
|
|
279
371
|
* or carries Chinese marks. */
|
|
280
|
-
function renderMarkedWordSegment(seg, x, top, fontDecl, colorDecl, color, cjk) {
|
|
281
|
-
const pos = `position:absolute;left:${x.toFixed(3)}px;top:${top};white-space:pre;${cjk ? CJK_TEXT_DECL : ''}`;
|
|
372
|
+
function renderMarkedWordSegment(seg, x, top, fontDecl, colorDecl, color, cjk, box = PLAIN_BOX) {
|
|
373
|
+
const pos = `position:absolute;left:${x.toFixed(3)}px;top:${top};white-space:pre;${cjk ? CJK_TEXT_DECL : ''}${box.decl}`;
|
|
282
374
|
// Text set with emphasis dots is emphasis (#193); the dots are the
|
|
283
375
|
// line's marks.
|
|
284
|
-
const text = seg.cjkMarks?.dots ? `<em style="font-style:inherit;">${esc(seg.text)}</em>` : esc(seg.text);
|
|
376
|
+
const text = seg.cjkMarks?.dots ? `<em style="font-style:inherit;">${esc(seg.text)}</em>` : box.html ?? esc(seg.text);
|
|
285
377
|
const featuresDecl = fontDecl && cjk ? CJK_FEATURES_DECL : '';
|
|
286
378
|
if (seg.refResourceId !== undefined) {
|
|
287
379
|
// Anchors carry an explicit color so the UA link blue never leaks in.
|
|
288
380
|
const inner = `<a href="${refAnchorHref(refKey(seg))}" style="text-decoration:none;${fontDecl}${featuresDecl}${fontDecl ? 'line-height:0;' : ''}color:${color};">${text}</a>`;
|
|
289
|
-
return `<span style="${pos}">${inner}</span>`;
|
|
381
|
+
return `<span${box.attrs} style="${pos}">${inner}</span>`;
|
|
290
382
|
}
|
|
291
383
|
if (fontDecl) {
|
|
292
|
-
return `<span style="${pos}"><span style="${fontDecl}${featuresDecl}line-height:0;${colorDecl}">${text}</span></span>`;
|
|
384
|
+
return `<span${box.attrs} style="${pos}"><span style="${fontDecl}${featuresDecl}line-height:0;${colorDecl}">${text}</span></span>`;
|
|
293
385
|
}
|
|
294
|
-
return `<span style="${pos}${colorDecl}">${text}</span>`;
|
|
386
|
+
return `<span${box.attrs} style="${pos}${colorDecl}">${text}</span>`;
|
|
295
387
|
}
|
|
296
388
|
/** A `:ref` painted as several runs (a label in small capitals: one run per
|
|
297
389
|
* case) from `segs[start]` on. Every run is placed as measured, and all of
|
|
@@ -314,11 +406,16 @@ function renderRefRuns(segs, start, x, color, paint, linked = true) {
|
|
|
314
406
|
}
|
|
315
407
|
/** Wraps each run of segments of one link (`VDTLineSegment.href`) in an
|
|
316
408
|
* `<a>`: `at` returns the markup to emit before a segment with that link
|
|
317
|
-
* (closing the previous anchor, opening its own), `
|
|
318
|
-
* closes the line. The segments stay absolutely positioned inside it; the
|
|
409
|
+
* (closing the previous anchor, opening its own), `space` the markup to
|
|
410
|
+
* emit before a word space, `end` the markup that closes the line. The segments stay absolutely positioned inside it; the
|
|
319
411
|
* anchor takes the text colour, so a link reads as the surrounding text. */
|
|
320
412
|
function linkRuns() {
|
|
321
413
|
let open;
|
|
414
|
+
const end = () => {
|
|
415
|
+
const close = open !== undefined ? '</a>' : '';
|
|
416
|
+
open = undefined;
|
|
417
|
+
return close;
|
|
418
|
+
};
|
|
322
419
|
return {
|
|
323
420
|
at(href) {
|
|
324
421
|
if (href === open)
|
|
@@ -329,11 +426,11 @@ function linkRuns() {
|
|
|
329
426
|
? `<a href="${esc(href)}" rel="noopener noreferrer" style="color:inherit;text-decoration:none;">`
|
|
330
427
|
: '');
|
|
331
428
|
},
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
429
|
+
/** Before a word space: closes the open anchor unless the word after
|
|
430
|
+
* the space (`next`) is part of the same link, so a link's text never
|
|
431
|
+
* ends on a space (#403). */
|
|
432
|
+
space: (next) => (next === open ? '' : end()),
|
|
433
|
+
end,
|
|
337
434
|
};
|
|
338
435
|
}
|
|
339
436
|
/** A segment's link, unless it is a `:ref` (which links to its resource):
|
|
@@ -350,6 +447,60 @@ function segmentHref(seg) {
|
|
|
350
447
|
return `#${pageElementId(seg.pageLink)}`;
|
|
351
448
|
return undefined;
|
|
352
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* A word space of a line, or what separates it from the next, as text a
|
|
452
|
+
* selection copies (#403). Every word sits in its own absolutely positioned
|
|
453
|
+
* box, so without these the browser copies a line's words run together. The
|
|
454
|
+
* box is placed where the space falls (`x`) and paints nothing: the layout
|
|
455
|
+
* is unchanged. A space stretched by justification takes the stretch as
|
|
456
|
+
* `word-spacing`, so a selection's highlight spans the gap the reader sees.
|
|
457
|
+
* The markup is in logical order like the words', so a right-to-left line
|
|
458
|
+
* copies as written. Empty `text` (a gap the composer added, see
|
|
459
|
+
* `VDTLineSegment.autospace`) emits nothing.
|
|
460
|
+
*/
|
|
461
|
+
function copyTextHtml(text, x, stretch = 0) {
|
|
462
|
+
if (!text)
|
|
463
|
+
return '';
|
|
464
|
+
const spacing = Math.abs(stretch) >= 0.0005 ? `word-spacing:${stretch.toFixed(3)}px;` : '';
|
|
465
|
+
return `<span style="position:absolute;left:${x.toFixed(3)}px;top:0;white-space:pre;${spacing}">${esc(text)}</span>`;
|
|
466
|
+
}
|
|
467
|
+
/** {@link copyTextHtml} for what follows a line (see {@link lineEndText}):
|
|
468
|
+
* transparent, so a selection's highlight never runs past the line's end.
|
|
469
|
+
* The text still copies; clipped (`overflow:hidden` on a box of no width)
|
|
470
|
+
* it would not, Chrome leaves clipped text out of a selection's string. */
|
|
471
|
+
const LINE_END_DECL = 'opacity:0;';
|
|
472
|
+
function lineEndHtml(text, x) {
|
|
473
|
+
if (!text)
|
|
474
|
+
return '';
|
|
475
|
+
return `<span style="position:absolute;left:${x.toFixed(3)}px;top:0;${LINE_END_DECL}white-space:pre;">${esc(text)}</span>`;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* What a copy puts between a line and the one after it in the same block
|
|
479
|
+
* (`next`), or after a block's last line (#403): nothing after a line that
|
|
480
|
+
* ends inside a word or on a hyphen or dash (`VDTLine.hyphenated`); a
|
|
481
|
+
* newline after a line of verse and after the last line of a paragraph (or
|
|
482
|
+
* of a heading, a caption, a cell); between two lines of a block, a space
|
|
483
|
+
* where the break consumed one — the plain text skips a character between
|
|
484
|
+
* them (`plainEnd` / `plainStart`) — and nothing where it did not (between
|
|
485
|
+
* two ideographs). Lines without those offsets, and a block's last line
|
|
486
|
+
* whose paragraph goes on in the next column or page (`isLastLine:
|
|
487
|
+
* false`), take a space unless the break has a CJK character on either
|
|
488
|
+
* side.
|
|
489
|
+
*/
|
|
490
|
+
function lineEndText(line, next) {
|
|
491
|
+
if (line.hyphenated)
|
|
492
|
+
return '';
|
|
493
|
+
if (line.verse || (!next && line.isLastLine !== false))
|
|
494
|
+
return '\n';
|
|
495
|
+
if (next && line.plainEnd !== undefined && next.plainStart !== undefined)
|
|
496
|
+
return next.plainStart > line.plainEnd ? ' ' : '';
|
|
497
|
+
return cjkAt(Array.from(line.text.trimEnd()).pop()) || cjkAt(next && Array.from(next.text.trimStart())[0]) ? '' : ' ';
|
|
498
|
+
}
|
|
499
|
+
/** Whether `char` is CJK; no CJK character sits below U+1100, so a Latin
|
|
500
|
+
* page never gets as far as the test. */
|
|
501
|
+
function cjkAt(char) {
|
|
502
|
+
return char !== undefined && char.codePointAt(0) >= 0x1100 && hasCJK(char);
|
|
503
|
+
}
|
|
353
504
|
/**
|
|
354
505
|
* The segments of a horizontal line. A line of the CJK composer goes to
|
|
355
506
|
* {@link renderComposedSegments}. Any other line was set word by word and
|
|
@@ -361,25 +512,36 @@ function segmentHref(seg) {
|
|
|
361
512
|
* line's `text` holds the text of every segment, except the leader of a
|
|
362
513
|
* contents entry (`tocEntry`).
|
|
363
514
|
*/
|
|
364
|
-
function renderSegments(line, block, targets
|
|
515
|
+
function renderSegments(line, block, targets, rootDir = 'ltr', rootLang,
|
|
516
|
+
/** What a copy puts after the line (see {@link lineEndText}). */
|
|
517
|
+
end = '') {
|
|
365
518
|
if (line.cjkComposed)
|
|
366
|
-
return renderComposedSegments(line, block, targets);
|
|
519
|
+
return renderComposedSegments(line, block, targets, rootDir, end);
|
|
367
520
|
// The tracking after the last glyph is advance, not ink: centring and
|
|
368
521
|
// right alignment leave it out (EF-153), as the canvas does.
|
|
369
|
-
const
|
|
522
|
+
const tracking = (block.letterSpacing ?? 0) + (line.letterSpacing ?? 0);
|
|
523
|
+
const trailing = lineTrailingTracking(line, tracking);
|
|
524
|
+
// A line of a block set against its frame's direction aligns in its span
|
|
525
|
+
// (`VDTLine.measure`) from that span's right, its start side (#371).
|
|
526
|
+
const span = line.measure;
|
|
527
|
+
const align = lineTextAlign(line, block.textAlign);
|
|
528
|
+
// Where the span starts inside the line's box (0 but for such a line).
|
|
529
|
+
const origin = span ? span.x - line.bbox.x : 0;
|
|
370
530
|
if (!line.segments || line.segments.length === 0) {
|
|
371
|
-
const plainIndent = line.bbox.x - block.bbox.x;
|
|
531
|
+
const plainIndent = span ? span.x - block.bbox.x : line.bbox.x - block.bbox.x;
|
|
532
|
+
const room = span ? span.width : block.bbox.width - plainIndent;
|
|
372
533
|
const plainWidth = line.bbox.width - trailing;
|
|
373
|
-
const plainLeft =
|
|
374
|
-
? Math.max(0,
|
|
375
|
-
:
|
|
376
|
-
? Math.max(0, (
|
|
377
|
-
: 0;
|
|
378
|
-
|
|
534
|
+
const plainLeft = origin + (align === 'right'
|
|
535
|
+
? Math.max(0, room - plainWidth)
|
|
536
|
+
: align === 'center'
|
|
537
|
+
? Math.max(0, (room - plainWidth) / 2)
|
|
538
|
+
: 0);
|
|
539
|
+
const plainDir = dirAttr(block.direction ?? rootDir, rootDir);
|
|
540
|
+
return `<span${plainDir} style="position:absolute;left:${plainLeft.toFixed(3)}px;top:0;white-space:pre;">${esc(line.text)}</span>` + lineEndHtml(end, plainLeft + plainWidth);
|
|
379
541
|
}
|
|
380
542
|
// Match canvas justification: stretch inter-word spaces to fill effective width.
|
|
381
|
-
const lineIndent = line.bbox.x - block.bbox.x;
|
|
382
|
-
const effectiveWidth = block.bbox.width - lineIndent;
|
|
543
|
+
const lineIndent = span ? span.x - block.bbox.x : line.bbox.x - block.bbox.x;
|
|
544
|
+
const effectiveWidth = span ? span.width : block.bbox.width - lineIndent;
|
|
383
545
|
let wordWidth = 0;
|
|
384
546
|
let spaceCount = 0;
|
|
385
547
|
for (const seg of line.segments) {
|
|
@@ -399,13 +561,18 @@ function renderSegments(line, block, targets) {
|
|
|
399
561
|
? (effectiveWidth - wordWidth) / spaceCount
|
|
400
562
|
: 0;
|
|
401
563
|
// Centred / right alignment — math display blocks, ragged-left paragraph
|
|
402
|
-
// styles. Distribute the leading gap.
|
|
564
|
+
// styles. Distribute the leading gap. A justified line fills its span.
|
|
403
565
|
const slack = Math.max(0, effectiveWidth - (contentWidth - trailing));
|
|
404
|
-
const leadingGap =
|
|
566
|
+
const leadingGap = origin + (useJustify ? 0 : align === 'center' ? slack / 2 : align === 'right' ? slack : 0);
|
|
405
567
|
const parts = [];
|
|
406
568
|
const links = linkRuns();
|
|
407
569
|
let x = leadingGap;
|
|
408
570
|
const segs = line.segments;
|
|
571
|
+
// Segments advance along the line in `line.order` when it has one (a
|
|
572
|
+
// line with right-to-left runs, or any line of a mirrored page): their
|
|
573
|
+
// x are taken in that order; the markup stays in logical order, so the
|
|
574
|
+
// text copies as written.
|
|
575
|
+
const at = line.order ? orderedOffsets(segs, line.order, leadingGap, useJustify ? justifiedSpaceWidth : undefined) : undefined;
|
|
409
576
|
const cjk = block.tocEntry !== undefined || hasCJK(line.text);
|
|
410
577
|
const paintText = (seg, at, inLink = false) => {
|
|
411
578
|
const font = quoteFontString(pickSegmentFont(seg, block));
|
|
@@ -413,11 +580,16 @@ function renderSegments(line, block, targets) {
|
|
|
413
580
|
const fontDecl = font !== quoteFontString(block.fontString) ? `font:${font};` : '';
|
|
414
581
|
const colorDecl = color !== block.color ? `color:${color};` : '';
|
|
415
582
|
const top = seg.baselineShift ? `${seg.baselineShift.toFixed(3)}px` : '0';
|
|
416
|
-
return renderWordTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, color, cjk && hasCJK(seg.text));
|
|
583
|
+
return renderWordTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, color, cjk && hasCJK(seg.text), segmentBox(seg, rootDir, rootLang, tracking, font, color, (probe) => ({ font: quoteFontString(pickSegmentFont(probe, block)), color: pickSegmentColor(probe, block) })));
|
|
417
584
|
};
|
|
418
585
|
for (let i = 0; i < segs.length; i++) {
|
|
419
586
|
const seg = segs[i];
|
|
587
|
+
if (at)
|
|
588
|
+
x = at[i];
|
|
420
589
|
if (seg.kind === 'space') {
|
|
590
|
+
// The space as text, for copying (#403).
|
|
591
|
+
parts.push(links.space(segs[i + 1] && segmentHref(segs[i + 1])));
|
|
592
|
+
parts.push(copyTextHtml(seg.text, x, useJustify ? justifiedSpaceWidth - seg.width : 0));
|
|
421
593
|
x += useJustify ? justifiedSpaceWidth : seg.width;
|
|
422
594
|
continue;
|
|
423
595
|
}
|
|
@@ -433,7 +605,7 @@ function renderSegments(line, block, targets) {
|
|
|
433
605
|
continue;
|
|
434
606
|
}
|
|
435
607
|
if (seg.chip) {
|
|
436
|
-
parts.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, quoteFontString(block.fontString), block.color, (run) => pickSegmentColor({ kind: 'text', text: run.text, width: run.width, bold: run.bold, italic: run.italic }, block)));
|
|
608
|
+
parts.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, quoteFontString(block.fontString), block.color, (run) => pickSegmentColor({ kind: 'text', text: run.text, width: run.width, bold: run.bold, italic: run.italic }, block), rootDir));
|
|
437
609
|
x += seg.width;
|
|
438
610
|
continue;
|
|
439
611
|
}
|
|
@@ -448,15 +620,31 @@ function renderSegments(line, block, targets) {
|
|
|
448
620
|
x += seg.width;
|
|
449
621
|
}
|
|
450
622
|
parts.push(links.end());
|
|
623
|
+
parts.push(lineEndHtml(end, x));
|
|
451
624
|
// Emphasis dots, proper-name and book-title lines (#193).
|
|
452
625
|
if (line.marks)
|
|
453
626
|
parts.push(lineMarksHtml(line, block.color));
|
|
454
627
|
return parts.join('');
|
|
455
628
|
}
|
|
629
|
+
/** The x of each segment (by index) of a line whose segments advance in
|
|
630
|
+
* `order` from `start`, spaces taking `spaceWidth` when the line is
|
|
631
|
+
* justified. */
|
|
632
|
+
function orderedOffsets(segs, order, start, spaceWidth) {
|
|
633
|
+
const out = new Array(segs.length).fill(start);
|
|
634
|
+
let x = start;
|
|
635
|
+
for (const i of order) {
|
|
636
|
+
const seg = segs[i];
|
|
637
|
+
if (!seg)
|
|
638
|
+
continue;
|
|
639
|
+
out[i] = x;
|
|
640
|
+
x += seg.kind === 'space' && spaceWidth !== undefined ? spaceWidth : seg.width;
|
|
641
|
+
}
|
|
642
|
+
return out;
|
|
643
|
+
}
|
|
456
644
|
/** {@link renderSegments} for a line of the CJK composer: hung marks and
|
|
457
645
|
* Han–Latin spaces kept out of the justification, each segment with its
|
|
458
646
|
* own tracking, ink offset and scale, warichu notes and ruby readings. */
|
|
459
|
-
function renderComposedSegments(line, block, targets) {
|
|
647
|
+
function renderComposedSegments(line, block, targets, rootDir = 'ltr', end = '') {
|
|
460
648
|
// The tracking after the last glyph is advance, not ink: centring and
|
|
461
649
|
// right alignment leave it out (EF-153), as the canvas does.
|
|
462
650
|
const lineTracking = (block.letterSpacing ?? 0) + (line.letterSpacing ?? 0);
|
|
@@ -469,7 +657,7 @@ function renderComposedSegments(line, block, targets) {
|
|
|
469
657
|
: block.textAlign === 'center'
|
|
470
658
|
? Math.max(0, (block.bbox.width - plainIndent - plainWidth) / 2)
|
|
471
659
|
: 0;
|
|
472
|
-
return `<span style="position:absolute;left:${plainLeft.toFixed(3)}px;top:0;white-space:pre;">${esc(line.text)}</span
|
|
660
|
+
return `<span style="position:absolute;left:${plainLeft.toFixed(3)}px;top:0;white-space:pre;">${esc(line.text)}</span>` + lineEndHtml(end, plainLeft + plainWidth);
|
|
473
661
|
}
|
|
474
662
|
// Match canvas justification: stretch inter-word spaces to fill effective width.
|
|
475
663
|
const lineIndent = line.bbox.x - block.bbox.x;
|
|
@@ -511,12 +699,20 @@ function renderComposedSegments(line, block, targets) {
|
|
|
511
699
|
const fontDecl = font !== quoteFontString(block.fontString) ? `font:${font};` : '';
|
|
512
700
|
const colorDecl = color !== block.color ? `color:${color};` : '';
|
|
513
701
|
const top = seg.baselineShift ? `${seg.baselineShift.toFixed(3)}px` : '0';
|
|
514
|
-
|
|
702
|
+
// The composer sets left-to-right text: in a right-to-left document
|
|
703
|
+
// its boxes say so (#379).
|
|
704
|
+
const dir = dirAttr(seg.rtl ? 'rtl' : 'ltr', rootDir);
|
|
705
|
+
return renderTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, color, lineTracking, segmentCjk(seg, lineDecl), dir ? { attrs: dir, decl: '' } : PLAIN_BOX);
|
|
515
706
|
};
|
|
516
707
|
for (let i = 0; i < segs.length; i++) {
|
|
517
708
|
const seg = segs[i];
|
|
518
709
|
if (seg.kind === 'space') {
|
|
519
|
-
|
|
710
|
+
// The space as text, for copying (#403): a Han–Latin gap only where
|
|
711
|
+
// the author typed one (its `text`).
|
|
712
|
+
const gap = useJustify && !seg.autospace ? justifiedSpaceWidth : seg.width;
|
|
713
|
+
parts.push(links.space(segs[i + 1] && segmentHref(segs[i + 1])));
|
|
714
|
+
parts.push(copyTextHtml(seg.text, x, gap - seg.width));
|
|
715
|
+
x += gap;
|
|
520
716
|
continue;
|
|
521
717
|
}
|
|
522
718
|
parts.push(links.at(segmentHref(seg)));
|
|
@@ -531,7 +727,7 @@ function renderComposedSegments(line, block, targets) {
|
|
|
531
727
|
continue;
|
|
532
728
|
}
|
|
533
729
|
if (seg.chip) {
|
|
534
|
-
parts.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, quoteFontString(block.fontString), block.color, (run) => pickSegmentColor({ kind: 'text', text: run.text, width: run.width, bold: run.bold, italic: run.italic }, block)));
|
|
730
|
+
parts.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, quoteFontString(block.fontString), block.color, (run) => pickSegmentColor({ kind: 'text', text: run.text, width: run.width, bold: run.bold, italic: run.italic }, block), rootDir));
|
|
535
731
|
x += seg.width;
|
|
536
732
|
continue;
|
|
537
733
|
}
|
|
@@ -555,6 +751,7 @@ function renderComposedSegments(line, block, targets) {
|
|
|
555
751
|
x += seg.width;
|
|
556
752
|
}
|
|
557
753
|
parts.push(links.end());
|
|
754
|
+
parts.push(lineEndHtml(end, x));
|
|
558
755
|
// Emphasis dots, proper-name and book-title lines (#193).
|
|
559
756
|
if (line.marks)
|
|
560
757
|
parts.push(lineMarksHtml(line, block.color));
|
|
@@ -574,7 +771,9 @@ function renderSwatch(x, baselineOffset, side, fill, ink) {
|
|
|
574
771
|
* gap margin), then the text runs as ordinary text spans on the line's
|
|
575
772
|
* baseline (`baselineOffset` from the line top), so the words stay real,
|
|
576
773
|
* selectable text. `lineFont` / `lineColor` are the line box's own. */
|
|
577
|
-
function renderChip(chip, x, baselineOffset, lineFont, lineColor, inkFor
|
|
774
|
+
function renderChip(chip, x, baselineOffset, lineFont, lineColor, inkFor,
|
|
775
|
+
/** The direction the document's root declares (see {@link dirAttr}). */
|
|
776
|
+
rootDir = 'ltr') {
|
|
578
777
|
const bx = x + chip.marginLeft;
|
|
579
778
|
const parts = [];
|
|
580
779
|
if (chip.background || (chip.borderColor && chip.borderWidth > 0)) {
|
|
@@ -586,19 +785,27 @@ function renderChip(chip, x, baselineOffset, lineFont, lineColor, inkFor) {
|
|
|
586
785
|
`"></span>`);
|
|
587
786
|
}
|
|
588
787
|
let tx = bx + chip.borderWidth + chip.paddingX;
|
|
589
|
-
|
|
788
|
+
// The runs in the chip's paint order (`VDTChip.order`); a right-to-left
|
|
789
|
+
// run's box reads right to left.
|
|
790
|
+
const order = chip.order && chip.order.length === chip.runs.length ? chip.order : undefined;
|
|
791
|
+
for (let k = 0; k < chip.runs.length; k++) {
|
|
792
|
+
const run = chip.runs[order ? order[k] : k];
|
|
590
793
|
const font = quoteFontString(run.fontString);
|
|
591
794
|
const color = chip.color ?? inkFor(run);
|
|
592
795
|
const fontDecl = font !== lineFont ? `font:${font};` : '';
|
|
593
796
|
const colorDecl = color !== lineColor ? `color:${color};` : '';
|
|
594
797
|
const top = run.baselineShift ? `${run.baselineShift.toFixed(3)}px` : '0';
|
|
595
798
|
// A chip's runs were measured one by one, as a whole each.
|
|
596
|
-
|
|
799
|
+
// A run whose direction differs from what it inherits says so, so its
|
|
800
|
+
// neutral characters are ordered and its brackets mirrored as the
|
|
801
|
+
// engine resolved them.
|
|
802
|
+
const dir = dirAttr(run.rtl ? 'rtl' : 'ltr', rootDir);
|
|
803
|
+
parts.push(renderTextSegment({ kind: 'text', text: run.text, width: run.width }, tx, top, fontDecl, colorDecl, color, 0, hasCJK(run.text) ? 'own' : false, dir ? { attrs: dir, decl: '' } : PLAIN_BOX));
|
|
597
804
|
tx += run.width;
|
|
598
805
|
}
|
|
599
806
|
return parts.join('');
|
|
600
807
|
}
|
|
601
|
-
function renderBullet(block) {
|
|
808
|
+
function renderBullet(block, rootDir = 'ltr') {
|
|
602
809
|
if (block.type !== 'listItem' ||
|
|
603
810
|
!block.bulletText ||
|
|
604
811
|
block.bulletOffsetX === undefined) {
|
|
@@ -622,7 +829,10 @@ function renderBullet(block) {
|
|
|
622
829
|
const onBaseline = block.bulletBaselineY !== undefined;
|
|
623
830
|
const lineFont = quoteFontString(block.fontString);
|
|
624
831
|
const baselineShift = onBaseline ? block.bulletBaselineY - firstLine.baseline : 0;
|
|
625
|
-
|
|
832
|
+
// A marker reads in its item's direction: `١.` with its full stop on the
|
|
833
|
+
// left in an Arabic list (#379).
|
|
834
|
+
const markerDir = dirAttr(block.direction ?? rootDir, rootDir);
|
|
835
|
+
const markerDiv = (cls, x, font, color, text) => `<div class="${cls}" aria-hidden="true"${markerDir} style="` +
|
|
626
836
|
`position:absolute;` +
|
|
627
837
|
`left:${x}px;` +
|
|
628
838
|
`top:${firstLine.bbox.y + baselineShift}px;` +
|
|
@@ -648,7 +858,9 @@ function renderBullet(block) {
|
|
|
648
858
|
}
|
|
649
859
|
return html;
|
|
650
860
|
}
|
|
651
|
-
function renderLine(line, block, targets
|
|
861
|
+
function renderLine(line, block, targets, rootDir = 'ltr', rootLang,
|
|
862
|
+
/** The block's line after this one (see {@link lineEndText}). */
|
|
863
|
+
next) {
|
|
652
864
|
const font = quoteFontString(block.fontString);
|
|
653
865
|
const strikethroughDecl = block.strikethroughText ? 'text-decoration:line-through;' : '';
|
|
654
866
|
// Tracking — the block's (column balancing, a runt set short) and the
|
|
@@ -666,7 +878,7 @@ function renderLine(line, block, targets) {
|
|
|
666
878
|
strikethroughDecl +
|
|
667
879
|
trackingDecl +
|
|
668
880
|
(lineCjkDecl(line) ? CJK_TEXT_DECL : '') +
|
|
669
|
-
`">${renderSegments(line, block, targets)}</div>`);
|
|
881
|
+
`">${renderSegments(line, block, targets, rootDir, rootLang, lineEndText(line, next))}</div>`);
|
|
670
882
|
}
|
|
671
883
|
// ---------------------------------------------------------------------------
|
|
672
884
|
// Vertical text (`VDTPage.flow`)
|
|
@@ -779,7 +991,7 @@ function verticalAnnotationRuns(runs, x, color, v, axisOf) {
|
|
|
779
991
|
/** A body line of a vertical page: its text segments down an upright box,
|
|
780
992
|
* its formulas, swatches and chips sideways where the canvas paints them
|
|
781
993
|
* (see the section comment). */
|
|
782
|
-
function renderVerticalLine(line, block, v, targets) {
|
|
994
|
+
function renderVerticalLine(line, block, v, targets, next) {
|
|
783
995
|
const lineTracking = (block.letterSpacing ?? 0) + (line.letterSpacing ?? 0);
|
|
784
996
|
const trailing = lineTrailingTracking(line, lineTracking);
|
|
785
997
|
const lineIndent = line.bbox.x - block.bbox.x;
|
|
@@ -808,8 +1020,12 @@ function renderVerticalLine(line, block, v, targets) {
|
|
|
808
1020
|
const justifiedSpaceWidth = useJustify ? (effectiveWidth - wordWidth) / spaceCount : 0;
|
|
809
1021
|
const slack = Math.max(0, effectiveWidth - (contentWidth - trailing));
|
|
810
1022
|
let x = block.textAlign === 'center' ? slack / 2 : block.textAlign === 'right' ? slack : 0;
|
|
1023
|
+
const spaceAxis = axisOf(block.fontString);
|
|
811
1024
|
for (const seg of segs) {
|
|
812
1025
|
if (seg.kind === 'space') {
|
|
1026
|
+
// The space as text, for copying (#403).
|
|
1027
|
+
if (seg.text)
|
|
1028
|
+
inner.push(verticalSpan(x, spaceAxis, esc(seg.text)));
|
|
813
1029
|
x += useJustify && !seg.autospace ? justifiedSpaceWidth : seg.width;
|
|
814
1030
|
continue;
|
|
815
1031
|
}
|
|
@@ -868,6 +1084,9 @@ function renderVerticalLine(line, block, v, targets) {
|
|
|
868
1084
|
// flow with the line's box.
|
|
869
1085
|
if (line.marks)
|
|
870
1086
|
sideways.push(verticalLineMarksHtml(line, block.color));
|
|
1087
|
+
const end = lineEndText(line, next);
|
|
1088
|
+
if (end)
|
|
1089
|
+
inner.push(verticalSpan(x, spaceAxis, esc(end), LINE_END_DECL));
|
|
871
1090
|
const width = Math.max(line.bbox.width, effectiveWidth);
|
|
872
1091
|
const decl = `font:${blockFont};color:${block.color};`
|
|
873
1092
|
+ (block.strikethroughText ? 'text-decoration:line-through;' : '')
|
|
@@ -952,7 +1171,13 @@ function pickResourceFont(seg, fonts) {
|
|
|
952
1171
|
* Alignment and justification are baked into the measured geometry, so
|
|
953
1172
|
* segments paint sequentially from the line origin — `:ref` segments in the
|
|
954
1173
|
* link colour, `captionLabel` segments in the label colour. */
|
|
955
|
-
function renderResourceLine(line, fonts, color, linkColor, labelColor = color, targets
|
|
1174
|
+
function renderResourceLine(line, fonts, color, linkColor, labelColor = color, targets,
|
|
1175
|
+
/** The direction the document's root declares (see {@link dirAttr}). */
|
|
1176
|
+
rootDir = 'ltr',
|
|
1177
|
+
/** The language the document's root declares. */
|
|
1178
|
+
rootLang,
|
|
1179
|
+
/** What a copy puts after the line (see {@link lineEndText}). */
|
|
1180
|
+
end = '') {
|
|
956
1181
|
const baseFont = quoteFontString(fonts.normal);
|
|
957
1182
|
const parts = [];
|
|
958
1183
|
const lineDecl = lineCjkDecl(line);
|
|
@@ -960,6 +1185,10 @@ function renderResourceLine(line, fonts, color, linkColor, labelColor = color, t
|
|
|
960
1185
|
const segs = line.segments;
|
|
961
1186
|
const composed = line.cjkComposed === true;
|
|
962
1187
|
const cjk = !composed && hasCJK(line.text);
|
|
1188
|
+
// A caption or cell line with right-to-left runs, or on a mirrored
|
|
1189
|
+
// page, advances through its segments in `order` (#379).
|
|
1190
|
+
const at = line.order && line.order.length === segs.length ? orderedOffsets(segs, line.order, 0, undefined) : undefined;
|
|
1191
|
+
const tracking = line.letterSpacing ?? 0;
|
|
963
1192
|
const segColorOf = (seg) => (seg.refResourceId !== undefined
|
|
964
1193
|
? linkColor
|
|
965
1194
|
: seg.captionLabel
|
|
@@ -971,17 +1200,24 @@ function renderResourceLine(line, fonts, color, linkColor, labelColor = color, t
|
|
|
971
1200
|
const fontDecl = font !== baseFont ? `font:${font};` : '';
|
|
972
1201
|
const colorDecl = segColor !== color ? `color:${segColor};` : '';
|
|
973
1202
|
const top = seg.baselineShift ? `${seg.baselineShift.toFixed(3)}px` : '0';
|
|
1203
|
+
// Its direction, untracked joining letters and styled runs (#379).
|
|
1204
|
+
const box = segmentBox(seg, rootDir, rootLang, tracking, font, segColor, (probe) => ({ font: quoteFontString(pickResourceFont(probe, fonts)), color: segColor }));
|
|
974
1205
|
// A line set word by word as every line was before the CJK
|
|
975
1206
|
// features (see `renderSegments`).
|
|
976
1207
|
return composed
|
|
977
|
-
? renderTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, segColor, line.letterSpacing ?? 0, segmentCjk(seg, lineDecl))
|
|
978
|
-
: renderWordTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, segColor, cjk && hasCJK(seg.text));
|
|
1208
|
+
? renderTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, segColor, line.letterSpacing ?? 0, segmentCjk(seg, lineDecl), box)
|
|
1209
|
+
: renderWordTextSegment(inLink ? { ...seg, refResourceId: undefined } : seg, at, top, fontDecl, colorDecl, segColor, cjk && hasCJK(seg.text), box);
|
|
979
1210
|
};
|
|
980
1211
|
const links = linkRuns();
|
|
981
1212
|
let x = 0;
|
|
982
1213
|
for (let i = 0; i < segs.length; i++) {
|
|
983
1214
|
const seg = segs[i];
|
|
1215
|
+
if (at)
|
|
1216
|
+
x = at[i];
|
|
984
1217
|
if (seg.kind === 'space') {
|
|
1218
|
+
// The space as text, for copying (#403).
|
|
1219
|
+
parts.push(links.space(segs[i + 1] && segmentHref(segs[i + 1])));
|
|
1220
|
+
parts.push(copyTextHtml(seg.text, x));
|
|
985
1221
|
x += seg.width;
|
|
986
1222
|
continue;
|
|
987
1223
|
}
|
|
@@ -992,7 +1228,7 @@ function renderResourceLine(line, fonts, color, linkColor, labelColor = color, t
|
|
|
992
1228
|
continue;
|
|
993
1229
|
}
|
|
994
1230
|
if (seg.chip) {
|
|
995
|
-
parts.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, baseFont, color, () => color));
|
|
1231
|
+
parts.push(renderChip(seg.chip, x, line.baseline - line.bbox.y, baseFont, color, () => color, rootDir));
|
|
996
1232
|
x += seg.width;
|
|
997
1233
|
continue;
|
|
998
1234
|
}
|
|
@@ -1007,9 +1243,11 @@ function renderResourceLine(line, fonts, color, linkColor, labelColor = color, t
|
|
|
1007
1243
|
x += seg.width;
|
|
1008
1244
|
}
|
|
1009
1245
|
parts.push(links.end());
|
|
1246
|
+
parts.push(lineEndHtml(end, x));
|
|
1010
1247
|
}
|
|
1011
1248
|
else {
|
|
1012
1249
|
parts.push(`<span style="position:absolute;left:0;top:0;white-space:pre;">${esc(line.text)}</span>`);
|
|
1250
|
+
parts.push(lineEndHtml(end, line.bbox.width));
|
|
1013
1251
|
}
|
|
1014
1252
|
return (`<div class="pt-line" style="` +
|
|
1015
1253
|
`position:absolute;` +
|
|
@@ -1134,9 +1372,9 @@ function renderResourceTable(rb, bx, by, options) {
|
|
|
1134
1372
|
for (const cell of t.cells) {
|
|
1135
1373
|
const fonts = cell.isHeader ? headerFonts : bodyFonts;
|
|
1136
1374
|
const color = cell.isHeader ? t.headerColor : t.color;
|
|
1137
|
-
|
|
1138
|
-
parts.push(renderResourceLine(line, fonts, color, rb.linkColor, color, options.linkTargets));
|
|
1139
|
-
}
|
|
1375
|
+
cell.lines.forEach((line, i) => {
|
|
1376
|
+
parts.push(renderResourceLine(line, fonts, color, rb.linkColor, color, options.linkTargets, options.dir, options.rootLang, lineEndText(line, cell.lines[i + 1])));
|
|
1377
|
+
});
|
|
1140
1378
|
}
|
|
1141
1379
|
return parts.join('');
|
|
1142
1380
|
}
|
|
@@ -1183,18 +1421,19 @@ function renderResourceBlockHtml(block, paint) {
|
|
|
1183
1421
|
italic: rb.captionItalicFontString,
|
|
1184
1422
|
boldItalic: rb.captionBoldItalicFontString,
|
|
1185
1423
|
};
|
|
1186
|
-
|
|
1187
|
-
parts.push(renderResourceLine(line, captionFonts, rb.captionColor, rb.linkColor, rb.captionLabelColor, options.linkTargets));
|
|
1188
|
-
}
|
|
1424
|
+
rb.captionLines.forEach((line, i) => {
|
|
1425
|
+
parts.push(renderResourceLine(line, captionFonts, rb.captionColor, rb.linkColor, rb.captionLabelColor, options.linkTargets, options.dir, options.rootLang, lineEndText(line, rb.captionLines[i + 1])));
|
|
1426
|
+
});
|
|
1189
1427
|
const noteFonts = {
|
|
1190
1428
|
normal: rb.noteFontString,
|
|
1191
1429
|
bold: rb.noteBoldFontString,
|
|
1192
1430
|
italic: rb.noteItalicFontString,
|
|
1193
1431
|
boldItalic: rb.noteBoldItalicFontString,
|
|
1194
1432
|
};
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1433
|
+
const noteLines = [...rb.noteLines, ...(rb.continuesLines ?? [])];
|
|
1434
|
+
noteLines.forEach((line, i) => {
|
|
1435
|
+
parts.push(renderResourceLine(line, noteFonts, rb.noteColor, rb.linkColor, rb.noteColor, options.linkTargets, options.dir, options.rootLang, lineEndText(line, noteLines[i + 1])));
|
|
1436
|
+
});
|
|
1198
1437
|
if (!rot)
|
|
1199
1438
|
return anchor + parts.join('');
|
|
1200
1439
|
return (anchor +
|
|
@@ -1262,7 +1501,11 @@ function renderDesignTextBlock(block, options) {
|
|
|
1262
1501
|
// A justified line: its word spaces widened as the canvas and the PDF
|
|
1263
1502
|
// advance its runs (EF-109).
|
|
1264
1503
|
const wordSpacingDecl = line.wordSpacingPx ? `word-spacing:${line.wordSpacingPx.toFixed(3)}px;` : '';
|
|
1265
|
-
|
|
1504
|
+
// A right-to-left text: the line box reads at that base direction, and
|
|
1505
|
+
// the browser orders its runs (written in logical order) as the engine
|
|
1506
|
+
// did (`VDTDesignTextLine.order`), which keeps copied text logical.
|
|
1507
|
+
const lineDir = dirAttr(block.direction === 'rtl' ? 'rtl' : 'ltr', options?.dir ?? 'ltr');
|
|
1508
|
+
lineParts.push(`<span${lineDir} style="` +
|
|
1266
1509
|
`position:absolute;` +
|
|
1267
1510
|
`left:${line.xOffset.toFixed(3)}px;` +
|
|
1268
1511
|
`top:${top.toFixed(3)}px;` +
|
|
@@ -1402,10 +1645,11 @@ function renderBlockInner(block, options) {
|
|
|
1402
1645
|
return renderResourceBlockHtml(block, options);
|
|
1403
1646
|
const parts = [];
|
|
1404
1647
|
const v = options.vertical;
|
|
1405
|
-
parts.push(v ? renderVerticalBullet(block, v) : renderBullet(block));
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1648
|
+
parts.push(v ? renderVerticalBullet(block, v) : renderBullet(block, options.dir));
|
|
1649
|
+
block.lines.forEach((line, i) => {
|
|
1650
|
+
const next = block.lines[i + 1];
|
|
1651
|
+
parts.push(v ? renderVerticalLine(line, block, v, options.linkTargets, next) : renderLine(line, block, options.linkTargets, options.dir, options.rootLang, next));
|
|
1652
|
+
});
|
|
1409
1653
|
return parts.join('');
|
|
1410
1654
|
}
|
|
1411
1655
|
/**
|
|
@@ -1449,8 +1693,9 @@ verticalRegion, verticalDigits) {
|
|
|
1449
1693
|
? { ...pageOptions, ink: { id: `pt-ink-${ink.hex.replace(/[^0-9a-z]/gi, '')}-${page.index}`, matrix: ink.matrix } }
|
|
1450
1694
|
: pageOptions;
|
|
1451
1695
|
// A vertical page's flow sets its text down the column.
|
|
1452
|
-
const
|
|
1453
|
-
|
|
1696
|
+
const vflow = verticalFlowOf(page);
|
|
1697
|
+
const options = vflow
|
|
1698
|
+
? { ...inked, vertical: { region: verticalRegion ?? 'mainland', uprightDigits: verticalDigits ?? 2, ...(vflow.centralBaselines ? { axes: vflow.centralBaselines } : {}), ...(vflow.dashAdvances ? { dashes: vflow.dashAdvances } : {}) } }
|
|
1454
1699
|
: inked;
|
|
1455
1700
|
const blocks = [];
|
|
1456
1701
|
for (const col of page.columns) {
|
|
@@ -1480,7 +1725,7 @@ verticalRegion, verticalDigits) {
|
|
|
1480
1725
|
const defsHtml = options.ink ? inkFilterDefs(options.ink) : '';
|
|
1481
1726
|
// The separators above the footnotes of the columns.
|
|
1482
1727
|
const footnoteRulesHtml = footnoteRuleSegments(page).map((r) => `<div class="pt-footnote-rule" style="position:absolute;left:${r.x}px;top:${r.y - r.lineWidthPx / 2}px;width:${r.width}px;height:${r.lineWidthPx}px;background:${r.color};"></div>`).join('');
|
|
1483
|
-
const gridHtml = gridCells ? renderCharacterGridSvg(gridCells,
|
|
1728
|
+
const gridHtml = gridCells ? renderCharacterGridSvg(gridCells, vflow ? page.height : page.width, vflow ? page.width : page.height) : '';
|
|
1484
1729
|
const decorationHtml = defsHtml + gridHtml + openerHtml + footnoteRulesHtml + slotParts.join('');
|
|
1485
1730
|
// A vertical page's flow: one box turned a quarter turn clockwise, its
|
|
1486
1731
|
// text lines turned back and set vertically (see `renderVerticalLine`).
|
|
@@ -1489,10 +1734,19 @@ verticalRegion, verticalDigits) {
|
|
|
1489
1734
|
.map((a) => zeroSizeAnchor(anchorElementId(a.id), a.x, a.y))
|
|
1490
1735
|
.join('');
|
|
1491
1736
|
const flowHtml = gridHtml + openerHtml + anchorsHtml + blocksHtml + footnoteRulesHtml;
|
|
1492
|
-
|
|
1737
|
+
// A right-to-left page's flow: one box turned over the sheet's vertical
|
|
1738
|
+
// axis, every text run and picture in it turned back about its own box
|
|
1739
|
+
// (`MIRRORED_FLOW_STYLE`), so the layout lands mirrored and reads as
|
|
1740
|
+
// written.
|
|
1741
|
+
const innerHtml = defsHtml + (vflow
|
|
1493
1742
|
? `<div class="pt-flow" style="position:absolute;left:0;top:0;width:${page.height}px;height:${page.width}px;transform:translate(${page.width}px,0) rotate(90deg);transform-origin:0 0;">${flowHtml}</div>`
|
|
1494
|
-
:
|
|
1495
|
-
|
|
1743
|
+
: page.flow?.writingMode === 'horizontal-tb'
|
|
1744
|
+
? `<div class="pt-flow pt-flow-mirrored" style="position:absolute;left:0;top:0;width:${page.width}px;height:${page.height}px;transform:scaleX(-1);transform-origin:${page.flow.mirror.originX / 2}px 0;">${MIRRORED_FLOW_STYLE}${flowHtml}</div>`
|
|
1745
|
+
: flowHtml) + slotParts.join('');
|
|
1746
|
+
// A right-to-left document's pages say so, with its language, for a host
|
|
1747
|
+
// that mounts them apart from the document's root (#379).
|
|
1748
|
+
const pageAttrs = options.dir === 'rtl' ? ` dir="rtl"${options.lang ? ` lang="${options.lang}"` : ''}` : '';
|
|
1749
|
+
const outerHtml = `<div class="pt-page" id="${pageElementId((options.pageIndexOffset ?? 0) + page.index)}" data-page="${page.index}"${pageAttrs} style="` +
|
|
1496
1750
|
`position:relative;` +
|
|
1497
1751
|
`width:${page.width}px;` +
|
|
1498
1752
|
`height:${page.height}px;` +
|
|
@@ -1502,6 +1756,15 @@ verticalRegion, verticalDigits) {
|
|
|
1502
1756
|
`">${innerHtml}</div>`;
|
|
1503
1757
|
return { outerHtml, innerHtml, blocks, decorationHtml };
|
|
1504
1758
|
}
|
|
1759
|
+
/** What turns the runs and pictures of a mirrored flow back (see
|
|
1760
|
+
* `VDTMirroredFlowFrame`): every text run of the output is an absolutely
|
|
1761
|
+
* positioned box set `white-space:pre` (line segments, plain lines, list
|
|
1762
|
+
* markers, design text lines), and pictures are `<img>` or inline `<svg>`
|
|
1763
|
+
* (formulas). Each turns about its own centre, so it stays where the
|
|
1764
|
+
* mirrored layout put it. A box that sets a transform of its own (a
|
|
1765
|
+
* stretched dash, a turned design picture) keeps it and stays mirrored. */
|
|
1766
|
+
const MIRRORED_FLOW_STYLE = '<style>.pt-flow-mirrored [style*="white-space:pre"],.pt-flow-mirrored img,' +
|
|
1767
|
+
'.pt-flow-mirrored svg:not(.pt-char-grid){transform:scaleX(-1);}</style>';
|
|
1505
1768
|
/** The character grid (稿纸) as one SVG path over the page, under the
|
|
1506
1769
|
* text (see `cjkGridCells`). */
|
|
1507
1770
|
function renderCharacterGridSvg(cells, width, height) {
|
|
@@ -1528,7 +1791,10 @@ function renderCharacterGridSvg(cells, width, height) {
|
|
|
1528
1791
|
* or a `line-height` on an ancestor would otherwise widen or change the
|
|
1529
1792
|
* glyph runs and make lines overprint. The `.pt-doc` root carries them
|
|
1530
1793
|
* before its own layout declarations; a host that mounts the pages'
|
|
1531
|
-
* `innerHtml` in containers of its own sets them on its root.
|
|
1794
|
+
* `innerHtml` in containers of its own sets them on its root. The root of
|
|
1795
|
+
* a right-to-left document (`ResolvedConfig.direction`) sets
|
|
1796
|
+
* `direction:rtl` in their place, and `dir="rtl"`: such a host does the
|
|
1797
|
+
* same (#379).
|
|
1532
1798
|
*/
|
|
1533
1799
|
export const HTML_TEXT_RESET = 'letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;' +
|
|
1534
1800
|
'white-space:normal;word-break:normal;overflow-wrap:normal;' +
|
|
@@ -1549,9 +1815,16 @@ export function renderToHtmlIndexed(doc, options = {}) {
|
|
|
1549
1815
|
const gap = options.columnGap ?? 24;
|
|
1550
1816
|
const padding = options.padding ?? 24;
|
|
1551
1817
|
const background = options.background ?? doc.config.page.backgroundColor.hex ?? 'transparent';
|
|
1552
|
-
// A right-
|
|
1818
|
+
// A right-to-left document runs right to left from its root (#379): the
|
|
1819
|
+
// browser resolves the text of every box in that direction unless the
|
|
1820
|
+
// box declares its own (see `dirAttr`).
|
|
1821
|
+
const rtl = doc.config.direction === 'rtl';
|
|
1822
|
+
const docLang = renderLangOf(doc.config);
|
|
1823
|
+
// A right-bound book lays its pages out right to left in a row: a row
|
|
1824
|
+
// already runs that way in a right-to-left root.
|
|
1825
|
+
const reversed = (doc.binding === 'right') !== rtl;
|
|
1553
1826
|
const docStyle = mode === 'multi'
|
|
1554
|
-
? `display:flex;flex-direction:${
|
|
1827
|
+
? `display:flex;flex-direction:${reversed ? 'row-reverse' : 'row'};gap:${gap}px;align-items:flex-start;padding:${padding}px;box-sizing:border-box;width:max-content;`
|
|
1555
1828
|
: `display:flex;flex-direction:column;align-items:center;padding:${padding}px 0;box-sizing:border-box;`;
|
|
1556
1829
|
// Single-ink diagrams: SVG pictures are filtered to the ink when the host
|
|
1557
1830
|
// asks (its URLs are not recoloured already).
|
|
@@ -1569,6 +1842,8 @@ export function renderToHtmlIndexed(doc, options = {}) {
|
|
|
1569
1842
|
const anchorPaint = {
|
|
1570
1843
|
...(doc.anchors ? { anchors: doc.anchors } : {}),
|
|
1571
1844
|
pageIndexOffset: doc.pageIndexOffset ?? 0,
|
|
1845
|
+
...(docLang ? { rootLang: docLang } : {}),
|
|
1846
|
+
...(rtl ? { dir: 'rtl', ...(docLang ? { lang: docLang } : {}) } : {}),
|
|
1572
1847
|
};
|
|
1573
1848
|
const bleedInset = doc.trimOffset > 0
|
|
1574
1849
|
? Math.max(0, doc.trimOffset - dimensionToPx(doc.config.page.cutLines.bleed, doc.config.page.dpi))
|
|
@@ -1601,9 +1876,10 @@ export function renderToHtmlIndexed(doc, options = {}) {
|
|
|
1601
1876
|
}
|
|
1602
1877
|
// The host's inherited text properties are reset first (EF-96). A
|
|
1603
1878
|
// Chinese, Japanese or Korean document declares its language, so the
|
|
1604
|
-
// browser picks the region's glyph forms
|
|
1605
|
-
|
|
1606
|
-
const
|
|
1879
|
+
// browser picks the region's glyph forms, and so does a right-to-left one,
|
|
1880
|
+
// with its direction (see `renderLangOf`).
|
|
1881
|
+
const reset = rtl ? HTML_TEXT_RESET.replace('direction:ltr;', 'direction:rtl;') : HTML_TEXT_RESET;
|
|
1882
|
+
const html = `<div class="pt-doc"${docLang ? ` lang="${docLang}"` : ''}${rtl ? ' dir="rtl"' : ''} data-mode="${mode}" style="${reset}${docStyle}">` +
|
|
1607
1883
|
pageHtmlParts.join('') +
|
|
1608
1884
|
`</div>`;
|
|
1609
1885
|
return { html, mode, pages: indexedPages };
|