/** * Punctuation widths, Han–Latin spacing and hanging punctuation of CJK * text (clreq §6.1.3, §6.2.2, §6.3.2, §6.3.3), for the CJK composer * (`cjkCompose.ts`). * * The model is additive, as in metal type and every CJK composer since: a * full-width mark is half an em of glyph and half an em of blank on one * side — before the glyph for an opening bracket or quote, after it for a * closing one and for the mainland's pause and stop marks (set in the * corner of their box), a quarter em on each side for the marks Taiwan and * Hong Kong centre. What is adjusted is the blank, never the glyph: a mark * that gives up blank on its start side is painted that far before its box * (`VDTLineSegment.inkOffset`), so its ink stays where the reader expects * it. * * The width decisions go through {@link punctuationBox} (the style and the * region), {@link compressPair} (two marks that meet), the line edges * ({@link lineStartTrim}, {@link lineEndTrim}) and the reduction a line * makes to take one more character ({@link punctuationShrink}). All of them * work on the inline axis only: vertical text passes `vertical: true`, * which fixes :;?! at one em (clreq §6.3.2.1), and otherwise reuses them * as they are. * * Japanese full-width text (`japan`, `fullwidth`) follows JLReq where it * differs from clreq ({@link isJlreqSpacing}): ・:; hold a quarter em * each side and ?! none; the half em after a closing mark or 、。 stays * at the end of a line and is the first blank given up, all of it, to * take one more character; inside the line 、「」・ give theirs up and 。 * never does (JLReq §3.1, §3.8.3). * * Which blank a region's glyphs carry is decided by the region, not by the * font: a Traditional Chinese font set under a mainland tag (or the * reverse) puts its marks where its designer did, and compression then * trims the wrong side. Books should be set in a face of their region * (Noto Serif SC for the mainland, TC for Taiwan, HK for Hong Kong). */ import type { CjkHangingPunctuation, CjkParagraphStartBracket, CjkPunctuationWidth, CjkRegion, ResolvedCjkConfig } from '../types.js'; import { type CjkClass } from './cjkClasses.js'; /** How CJK text is composed: the resolved `cjk` settings, as the composer * reads them. */ export interface CjkComposition { region: CjkRegion; punctuationWidth: CjkPunctuationWidth; compressAdjacent: boolean; trimLineStart: boolean; hangingPunctuation: CjkHangingPunctuation; /** The space between Han and Latin: in em of the CJK text's font size * (`em`), or in px when `cjk.latinSpacing` was a length (`px`). Zero * turns it off. */ latinSpacing: { em: number; px?: undefined; } | { px: number; em?: undefined; }; /** The text runs down the page (vertical-rl): :;?! keep one em. */ vertical?: boolean; /** The document's language, the primary subtag of its locale in lower * case (`zh`, `ja`, `ko`, `en`…); unset when unknown. Japanese and * Korean text keeps the marks it shares with Latin text at their own * advance (see {@link routesSharedMarks}). */ language?: string; /** One em of blank after a ? or ! that ends a sentence inside the * paragraph (`cjk.spaceAfterQuestion`, JLReq §3.1.6); unset: none. */ spaceAfterQuestion?: boolean; /** How an opening bracket that starts an indented paragraph is set * (`cjk.paragraphStartBracket`); unset: as at any line start. */ paragraphStartBracket?: CjkParagraphStartBracket; /** Lines break only at spaces and next to punctuation, never between * two letters (`cjk.wordBreak: 'keep-all'`); unset: between any two * characters the line-break level allows. A paragraph may set its own * (`MeasureBlockOptions.cjkWordBreak`). */ keepAll?: boolean; /** How many characters of a book title (`《…》`, `〈…〉`, a `:book[…]` * span) a line break leaves on either side of it at least * (`cjk.titleMinChars`, #637); unset: {@link DEFAULT_TITLE_MIN_CHARS}. * 1 lets a line break anywhere in a title the level allows. */ titleMinChars?: number; /** `'western'`: the circled numbers ①–⑳ and their kin are Western * letters, as up to 1.24 (`cjk.circledNumbers`, #637); unset: Chinese * characters (see `setCjkCircledNumbers`). */ circledNumbers?: 'western'; /** Design text (openers, heading designs, running heads, page designs) * is wrapped word by word at the font's own advances, as up to 1.24 * (`cjk.composeDesignText: false`, #637); unset: a design text that * composes as CJK is set by the CJK composer. */ plainDesignText?: true; /** `'western'`: a Western word that holds a letter or a digit takes the * Han–Latin space on a side that ends in a bracket or a sign too * (`cjk.latinSpacingEdge`, #721); unset: on a side that ends in a * letter or a digit only. */ latinSpacingEdge?: 'western'; /** How many characters of a warichu note a line break leaves on either * side of it at least (`cjk.warichu.minChars`, #720); unset: * {@link DEFAULT_NOTE_MIN_CHARS}. 1 lets a line break anywhere in a * note the level allows. */ noteMinChars?: number; /** The document's character grid keeps its full lines full * (`cjk.grid.fullLines`, #718): the runt rule carries no character down * from a line that is not justified, which it could not spread. */ gridFullLines?: true; } /** Characters of a book title a line break leaves on either side of it by * default (`cjk.titleMinChars`). */ export declare const DEFAULT_TITLE_MIN_CHARS = 2; /** Characters of a warichu note a line break leaves on either side of it * by default (`cjk.warichu.minChars`). */ export declare const DEFAULT_NOTE_MIN_CHARS = 2; /** The composition outside a build: every mark at its full advance, no * compression, no hanging, no Han–Latin space — CJK text set as the * composer set it before these settings existed. A build replaces it with * the document's (`setCjkComposition`). */ export declare const PLAIN_CJK_COMPOSITION: CjkComposition; /** Set the composition CJK text is set with when a measurement names none * (the build does, from the resolved `cjk`), as `setCjkLineBreak` sets the * line-break level. `undefined` restores {@link PLAIN_CJK_COMPOSITION}. */ export declare function setCjkComposition(composition: CjkComposition | undefined): void; /** The composition set by {@link setCjkComposition}. */ export declare function getCjkComposition(): CjkComposition; /** The composition of a resolved `cjk` config: `latinSpacing` in em when it * is written in em (or rem), else converted to px at `dpi`. `locale` is * the document language (`language`). */ export declare function cjkCompositionOf(cjk: ResolvedCjkConfig, dpi: number, locale?: string): CjkComposition; /** * Whether the marks Latin text shares with Chinese (“ ” ‘ ’ … — ·) may take * a Chinese mark's box in a paragraph of `text` (clreq's context routing, * `cjkCompose.ts`). They do in Chinese text: in a Chinese document, and in * a CJK paragraph of a document in another language (or none) unless it * holds kana or hangul. Never in a Japanese or Korean document, whose * typography sets them otherwise (Korean at their proportional width). */ export declare function routesSharedMarks(c: CjkComposition, text: string): boolean; /** * Whether a two-em dash (―― or ——, 2倍ダッシュ) is drawn as one stroke in * a paragraph of `text` whose shared marks are not routed * (`routesSharedMarks`): in Japanese text (#680), a Japanese document or a * paragraph with kana in a document of no CJK language. JLReq names the * pair as one mark (the double dash of its line-breaking rules), and a * face whose dash leaves blank at both ends of its em (Noto Serif JP's ―, * 0.07 em) would print it as two. Not in Korean, whose dashes are Latin. */ export declare function joinsDashPairs(c: CjkComposition, text: string): boolean; /** `c` for text set in the writing mode `vertical` names: the same * composition, flagged `vertical` when the text runs down the page (the * composer derives it from the writing mode it measures in, so a * horizontal heading in a vertical book, or a caption, is set as * horizontal text). */ export declare function compositionFor(c: CjkComposition, vertical: boolean): CjkComposition; /** The settings of a composition as a cache key: measurements of CJK text * under other settings never share an entry. */ export declare function cjkCompositionKey(c: CjkComposition): string; /** Whether a composition changes nothing: the text is set as without it. */ export declare function isPlainComposition(c: CjkComposition): boolean; /** * Whether marks are spaced as JLReq sets Japanese full-width text (§3.1, * Appendix B): the `japan` region with `fullwidth` marks (its default). * Then ・:; hold a quarter em on each side ({@link punctuationSide}), a * closing mark or 、。 keeps its half em at a line end * ({@link lineEndTrim}), and a line takes one more character by giving up * blank in JLReq's order ({@link jlreqShrinkStep}); a Chinese region, or * Japan under another width style, keeps clreq's rules. */ export declare function isJlreqSpacing(c: CjkComposition): boolean; /** Where a full-width mark keeps the blank it may give up: before its * glyph (`start`), after it (`end`), a quarter em on each side (`both`), * or nowhere (`none`: a mark fixed at its advance). */ export type PunctuationSide = 'start' | 'end' | 'both' | 'none'; /** * The side of a mark's blank along the line (clreq §6.3.2.1): opening * brackets and quotes before their glyph, closing ones after it; the * pause and stop marks of the mainland (、,。.;:?!, in the corner of * their box) and Japan's 、,。. after it; the marks Taiwan and Hong Kong * centre (、,。.;:), Japan's :; (a quarter em each side, as ・, JLReq * §3.1.2 cl-05) and interpuncts on both sides. ?! are fixed at one em in * horizontal Taiwan, Hong Kong and Japanese text (JLReq cl-04: a * full-width glyph), and :;?! in vertical text everywhere. Any other * character has no blank. */ export declare function punctuationSide(grapheme: string, cls: CjkClass, region: CjkRegion, vertical?: boolean): PunctuationSide; /** A mark and the blank it gives up. */ export interface PunctuationBox { cls: CjkClass; grapheme: string; side: PunctuationSide; /** The em of the mark's font (px). */ em: number; /** The blank the mark may give up, px: its advance less half an em. Zero * for a mark fixed at its advance and for a glyph narrower than three * quarters of an em (a proportional mark from a Latin face), which is * never adjusted. */ blank: number; /** Blank given up before the glyph and after it (px). */ cutStart: number; cutEnd: number; /** Of `cutStart` and `cutEnd`, the blank given up to the mark before it * and after it ({@link compressPair}): it comes back when a line breaks * between the two ({@link applyLineEdges}). */ pairStart?: number; pairEnd?: number; /** The blank of a Kaiming stop before it that a closing mark holds after * its glyph, px ({@link carryStopBlank}): it goes when the mark opens a * line ({@link applyLineEdges}). */ carry?: number; } /** A mark's advance now: its full advance less the blank it gave up. */ export declare function boxCut(box: PunctuationBox): number; /** The blank a mark still holds on each side. */ export declare function blankStart(box: PunctuationBox): number; export declare function blankEnd(box: PunctuationBox): number; /** * A mark (`grapheme` of class `cls`, full advance `advance` px, font em * `em` px) with the blank its style sets aside (clreq §6.3.2.1): none under * `fullwidth` and `lineEndHalf`, all of it under `halfwidth`, and under * `kaiming` all but for the stop marks 。.?!. The mainland interpunct is * half an em under every style (GB/T 15834, clreq §5.1), centred, in either * writing mode: a full-width glyph gives up its blank here, and in vertical * text its cell is half an em already (`verticalCellEms`), so it is no * adjustable mark there. The Japanese ・ keeps its em (half a glyph and a * quarter em each side, JLReq §3.1.2), as in Taiwan and Hong Kong. * Undefined for a character that is no adjustable mark. */ export declare function punctuationBox(grapheme: string, cls: CjkClass, advance: number, em: number, c: CjkComposition): PunctuationBox | undefined; /** * Two marks that meet (`a` then `b`) give up the blank between them, so the * pair takes 1.5 em instead of 2 (clreq §6.3.2.2, the eight rules of the * earlier clreq drafts): a closing bracket after another or after a * mainland pause or stop mark (。」, not the centred marks of Taiwan and * Hong Kong), a pause or stop mark after a closing bracket (」,), an * opening bracket after any of them or after another opening one (,「 * 》( 「『); a quarter em between an interpunct and a closing bracket * before it or an opening one after it. Only the blank between the two is * given up — the bracket's first — and never more than takes the pair to * 1.5 em, so a Kaiming pair that already takes 1.5 em (。”) keeps it. * * With `jlreq` ({@link isJlreqSpacing}) the same rules give JLReq §3.1.4's * table: 、」 。」 」、 」。 」」 「「 solid, 、「 」「 half an em between, * and 」・ ・「 (and :; in place of ・) a quarter em between: the * bracket's whole half em goes, the middle dot keeps its quarter. */ export declare function compressPair(a: PunctuationBox, b: PunctuationBox, jlreq?: boolean): void; /** * Under Kaiming a stop mark keeps its blank inside the line and a closing * mark gives its own up, so where the two meet (。” ?” 。)) the stop's half * em would stand between them and the quote would read as the next * character's. The blank goes after the closing mark instead: 。”␣, the * glyphs together, as full width with `compressAdjacent` sets them; the * pair keeps its width. A closing mark after that one takes the blank on * (。”)␣). The blank is still the stop's: it goes at a line end * ({@link lineEndTrim}), gives way with the stop marks' to take in a * character ({@link punctuationShrink}), and returns to the stop when the * line breaks between the two. Mainland marks only (in the corner of their * box): a centred mark keeps its blank on both sides. */ export declare function carryStopBlank(a: PunctuationBox, b: PunctuationBox): void; /** The blank a mark gives up when it opens a line: an opening bracket or * quote its start half, with `trimLineStart` (clreq §6.3.2.3). */ export declare function lineStartTrim(box: PunctuationBox | undefined, c: CjkComposition): number; /** The blank a mark gives up when it ends a line: every mark under * `lineEndHalf` (GB/T 15834—2011 §5.1.10), the stop marks under * `kaiming` (the rest are half already, but for a closing mark holding a * stop's blank, {@link carryStopBlank}), a closing bracket or quote with * `trimLineStart` (clreq §6.3.2.3) but in JLReq spacing, which keeps it * (§3.1.9: the line gives it up only to take one more character, * {@link punctuationShrink}). A centred mark gives up a quarter em each * side. */ export declare function lineEndTrim(box: PunctuationBox | undefined, c: CjkComposition): number; /** Apply the edge trims of a line to a mark: `start` from * {@link lineStartTrim}, `end` from {@link lineEndTrim}. */ export declare function applyLineTrim(box: PunctuationBox, start: number, end: number): void; /** * A mark at a line edge — it opens the line (`start`), ends it (`end`) or * both: the blank it gave up to the mark across the break comes back, as * the two no longer meet (clreq §6.3.2.2 compresses marks that meet on a * line), then the edge trims apply ({@link lineStartTrim}, * {@link lineEndTrim}). Changes `box`; returns the blank given up at the * edges less the blank that came back, px (negative when the mark grows: * a full-width `,` whose `「` went to the next line is one em again). */ export declare function applyLineEdges(box: PunctuationBox, c: CjkComposition, start: boolean, end: boolean): number; /** What {@link applyLineEdges} would give up at the edges, leaving `box` * as it is. */ export declare function lineEdgeCut(box: PunctuationBox, c: CjkComposition, start: boolean, end: boolean): number; /** * The blank a mark may still give up when its line is compressed to take * one more character that may not open the next line (push-in, clreq * §6.2.2.3), after its style, its neighbours and the line edges took * theirs. `fullwidth` marks give up nothing (a full-width book keeps its * grid); `halfwidth` marks have nothing left; `kaiming` lets its stop marks * go down to half an em, last (only to resolve a prohibition: a line that * merely falls short is spread, so Kaiming keeps 。?! one em inside the * line), and with them the stop's blank a closing mark holds * ({@link carryStopBlank}); `lineEndHalf` lets every mark go down to half an * em. * * JLReq spacing ({@link isJlreqSpacing}, §3.8.3) gives up more: a mark * that ends the line (`atEnd`) the blank after its glyph, a middle dot * (・:;) inside the line its quarter em on each side, and an opening * bracket, a closing one or 、, inside the line their half em; never the * half em after 。. inside the line. */ export declare function punctuationShrink(box: PunctuationBox | undefined, c: CjkComposition, atEnd?: boolean): number; /** Give up `amount` px of a mark's blank to compress its line (see * {@link punctuationShrink}); returns what it gave. `atEnd`: only the * blank after the glyph of a mark that ends the line (JLReq spacing). */ export declare function shrinkPunctuation(box: PunctuationBox, amount: number, atEnd?: boolean): number; /** The step of clreq §6.2.2.3's reduction order a mark belongs to: * interpuncts, then brackets, then pause marks, then (after the Han–Latin * spaces) stop marks, and a closing mark holding a stop's blank. */ export declare function shrinkStep(box: PunctuationBox): number; /** * The step of JLReq §3.8.3's reduction order (Table 3) a mark belongs to, * after the word spaces (1): at the end of the line, the half em after a * closing mark or 、。 (2), then the quarter em after a middle dot (3), * each all or nothing (JLReq §3.1.9); inside the line, the middle dots' * quarter ems (4), then the half ems of brackets and 、, (5); the space * between Japanese and Latin text comes last (6). */ export declare function jlreqShrinkStep(box: PunctuationBox, atEnd: boolean): number; /** * The advance of one mark and where its glyph is painted, px — the width * decision of {@link punctuationBox} and the line edges, for a single mark * with no neighbour: the reuse point for renderers and vertical text. * Characters that are no adjustable mark keep `advance`. */ export declare function punctuationAdvance(grapheme: string, cls: CjkClass, advance: number, em: number, c: CjkComposition, edges?: { lineStart?: boolean; lineEnd?: boolean; }): { advance: number; inkOffset: number; }; /** * Whether a mark may hang past the end of its line * (`cjk.hangingPunctuation`, clreq §6.1.3): 、,。. everywhere and, on the * mainland (whose marks sit at the start of their box), every pause and * stop mark; under `'allow'`, never in horizontal Taiwan and Hong Kong * text, whose centred marks look cut off. Japan hangs 、,。. only, in * either writing mode (ぶら下げ, JLReq §2.5.1: closing brackets and ?! * never hang). */ export declare function mayHang(grapheme: string, cls: CjkClass, c: CjkComposition): boolean; /** Whether a grapheme takes the Han–Latin space on its Latin side: a letter * or a digit (not a sign such as ¥ or %). */ export declare function isLatinSpacingLatin(grapheme: string | undefined): boolean; /** Whether a grapheme takes the Han–Latin space on its Han side. */ export declare function isLatinSpacingHan(grapheme: string | undefined): boolean; /** The Han–Latin space in px for text whose CJK font has an em of `em` * px. */ export declare function latinSpacingPx(c: CjkComposition, em: number): number; //# sourceMappingURL=cjkPunctuation.d.ts.map