import { F as FontFamily, M as MejiroBrowserOptions, h as LayoutOptions, B as BreakResult, C as ChapterLayoutOptions, j as ChapterLayoutResult, I as InlineAnnotation } from '../types-DnPOMbQV.js'; export { k as InlineEmAnnotation, l as InlineEmphasisAnnotation, m as InlineFootnoteAnnotation, n as InlineLinkAnnotation, o as InlineRubyAnnotation, q as InlineStrongAnnotation, r as InlineTcyAnnotation, P as ParagraphInput, s as ParagraphLayoutResult, g as RubyInputAnnotation, t as normalizeFontFamily, u as toFontSpec } from '../types-DnPOMbQV.js'; import { I as ImageOverlayRect } from '../overlay-x44omB1X.js'; /** * Manages font loading via the CSS Font Loading API. * Ensures fonts are fully loaded before measurement begins. */ declare class FontLoader { private loaded; private inFlight; /** * Bumped whenever cached readiness is invalidated, so a load started before * the invalidation cannot record its now-stale answer afterwards. */ private generation; /** * Subscribes to the document's `loadingdone` event so the set of * already-loaded specs is discarded whenever new faces arrive — a family that * was only partially subsetted must be re-checked rather than trusted. * * Degrades to a no-op subscriber outside the browser (no `document` or no * `document.fonts`), which keeps SSR and Node test runs working; readiness * checks then resolve without waiting on anything. * * @param options - `onFontsLoaded` fires after each `loadingdone`, letting the * host invalidate width caches measured against the previous faces. */ constructor(options?: { onFontsLoaded?: () => void; }); /** * Ensures the specified font is loaded and available for rendering. * * Readiness is asked about the Unicode ranges that will be measured, not * about the family in the abstract, so a family whose CJK subset is still in * flight is not reported as ready. * * Concurrent calls for the same spec and coverage share a single * `document.fonts.load()`: laying out a spread asks for the same font once * per column, and issuing one request per caller would multiply the webfont * traffic. A failed load is not cached, so the next call retries. * * @param fontSpec - CSS font specification (e.g. '16px "Noto Serif JP"'). * @param text - Text about to be measured with this spec. Defaults to a * representative sample spanning every range mejiro measures. * @throws If the font fails to load. */ ensureLoaded(fontSpec: string, text?: string): Promise; /** Requests the font from the host and verifies it really became usable. */ private load; /** * Returns whether the specified font has been successfully loaded for the * ranges covered by `text`. * * @param fontSpec - CSS font specification to check. * @param text - Text whose ranges the answer applies to. Defaults to the * representative sample used by {@link ensureLoaded}. */ isLoaded(fontSpec: string, text?: string): boolean; /** * Returns whether the host can render `fontSpec` for the ranges covered by * `text`. * * A family with no registered `FontFace` counts as available when the host * says it can render the sample — that is how locally installed fonts and * generic CSS families present themselves. Detecting a silent fallback to * another font is a separate, metric-based question; see the browser * integration's `strictFontCheck`. * * @param fontSpec - CSS font specification to check. * @param text - Text whose ranges the answer applies to. */ isAvailable(fontSpec: string, text?: string): boolean; } /** Options for {@link WidthCache}. */ interface WidthCacheOptions { /** * Maximum number of distinct font specs to retain. When a new font is * inserted past the limit, the least-recently-used font is evicted (all * of its cached codepoints go with it). * * `Infinity` (default) disables font-level eviction, which is fine for * typical reader sessions with a handful of fonts. Set a finite value * when long-running hosts switch fonts frequently. * @defaultValue Infinity */ maxFonts?: number; /** * Maximum number of cached codepoints per font. When a font's cache * crosses this limit the least-recently-used codepoint is dropped. Use * this to bound memory on multilingual corpora. * @defaultValue Infinity */ maxCodepointsPerFont?: number; } /** * Caches measured character widths keyed by font specification and codepoint. * * Optional LRU bounds are available through {@link WidthCacheOptions} so * long-running hosts can cap memory use without sacrificing the per-font * codepoint map. Internally we rely on Map's insertion-order iteration to * implement the LRU policy. */ declare class WidthCache { private store; private readonly maxFonts; private readonly maxCodepointsPerFont; /** * Creates an empty cache. Both bounds default to `Infinity`, which turns the * LRU bookkeeping off entirely — reads skip the reinsertion that maintains * recency order — so leave them unset unless memory actually needs capping. * * @param options - Optional per-font and per-codepoint LRU limits. */ constructor(options?: WidthCacheOptions); /** Retrieves a cached width, or undefined if not cached. */ get(fontKey: string, codepoint: number): number | undefined; /** Stores a measured width in the cache. */ set(fontKey: string, codepoint: number, width: number): void; /** * Clears cached entries. * @param fontKey - If provided, clears only entries for this font. Otherwise clears all. */ clear(fontKey?: string): void; /** * Returns the number of cached entries. * @param fontKey - If provided, returns count for this font only. Otherwise returns total. */ size(fontKey?: string): number; /** Returns the number of distinct font specs with cached entries. */ fontCount(): number; /** Returns aggregate cache statistics. */ stats(): { fonts: number; codepoints: number; }; } /** * Derives a ruby font spec from a base font family and size by scaling the size. * * @param fontFamily - CSS font family (string or array). * @param fontSize - Base font size in pixels. * @param ratio - Size ratio for ruby text. @defaultValue 0.5 * @returns CSS font specification for ruby text. */ declare function deriveRubyFont(fontFamily: FontFamily, fontSize: number, ratio?: number): string; /** * Measures character widths using the Canvas 2D API. * Maintains an internal cache to avoid redundant measurements. * * Constructing a measurer touches no DOM API: when no canvas is supplied, one * is created on the first uncached measurement. That keeps the whole * construction path — including `MejiroBrowser` and `MejiroBook` — usable on a * server, where snapshots are replayed and nothing is measured. */ declare class CharMeasurer { private ctx; private cache; private currentFont; /** * @param options - Optional collaborators. * @param options.canvas - Canvas to measure against. Validated eagerly, so a * canvas that yields no 2D context throws here rather than at first * measurement. When omitted, a canvas is created lazily on the first * uncached measurement, which keeps construction DOM-free. * @param options.cache - Width cache to read and populate. Pass a shared cache * to reuse measurements across measurers, and note that the cache is then * shared state: a caller that swaps fonts at runtime must invalidate it. * @defaultValue a private unbounded {@link WidthCache} * @throws When `options.canvas` is supplied but has no 2D rendering context. */ constructor(options?: { canvas?: HTMLCanvasElement; cache?: WidthCache; }); /** * Measures the advance width of a single character. * @param fontSpec - CSS font specification. * @param codepoint - Unicode codepoint to measure. * @returns Width in pixels. */ measure(fontSpec: string, codepoint: number): number; /** * Measures advance widths for all characters in the text. * @param fontSpec - CSS font specification. * @param text - Array of Unicode codepoints. * @returns Float32Array of advance widths in pixels. */ measureAll(fontSpec: string, text: Uint32Array): Float32Array; /** Returns the underlying width cache instance. */ getCache(): WidthCache; private context; private setFont; } /** * Computes the effective line width for vertical text layout. * * In CSS `writing-mode: vertical-rl`, each column's height is the * inline dimension. Canvas.measureText measures horizontal advance, * which can be slightly smaller than the vertical advance used by * the browser. This function applies a safety margin to prevent * columns from overflowing. * * @param containerHeight - Available height in pixels (CSS inline dimension). * @param fontSize - Base font size in pixels. * @returns Effective line width for the line breaking algorithm. */ declare function verticalLineWidth(containerHeight: number, fontSize: number): number; /** * Standalone function to lay out text with a specified font. * Handles font loading, measurement, and line break computation in one call. * * Accepts the same fields as {@link MejiroBrowser.layout} and produces the same * {@link BreakResult} for them, except that `fontFamily` and `fontSize` are * required: there is no instance to inherit fixed values from. Prefer * {@link MejiroBrowser} when laying out repeatedly, so the width cache and the * loaded-font set survive between calls. */ declare function layoutText(options: { text: string; fontFamily: FontFamily; fontSize: number; lineWidth: number; mode?: 'strict' | 'loose'; enableHanging?: boolean; inlineAnnotations?: readonly InlineAnnotation[]; /** * Token boundary indices for morphological-aware line breaking. * @see {@link LayoutOptions.tokenBoundaries} */ tokenBoundaries?: Uint32Array | readonly number[]; }): Promise; /** * Main browser integration class. * Manages font loading, width caching, and layout computation. */ declare class MejiroBrowser { private fontLoader; private measurer; private options; /** * Wires a fresh measurer to a font loader that clears the width cache on * every `loadingdone`, so widths measured against a fallback face are * discarded once the real font arrives. * * @param options - Fixed font family / size used when a layout call omits * them, plus the `strictFontCheck` guard. Captured at construction; layout * calls override the fixed values per call rather than mutating these. */ constructor(options?: MejiroBrowserOptions); /** * Computes line breaks for the given text and font. * * The text is normalized to NFC and the supplied `inlineAnnotations` move * with it, so a decomposed `が` and a precomposed `が` produce the same * break points and keep every annotation over the character it was authored * for. Annotations left covering nothing by the composition are dropped. * * @param options - Layout options including text, font, and line width. * @throws If no font family or font size is specified and no fixed values were configured. * @throws If `strictFontCheck` is enabled and the requested family measures * like the host's default font, i.e. it silently fell back. */ layout(options: LayoutOptions): Promise; /** * Preloads a font so it is available for subsequent layout calls. * @param fontFamily - CSS font family to preload (string or array). * @param fontSize - Font size in pixels (used for the font loading check). */ preloadFont(fontFamily?: FontFamily, fontSize?: number): Promise; /** * Lays out an entire chapter (multiple paragraphs) in one call. * * Each paragraph is measured and broken into lines. Paragraphs can * optionally override the font family and size (e.g. for headings). * * Paragraph text is normalized to NFC together with its annotations, so the * returned `chars` and the annotation indices address the same characters. * * @param options - Chapter layout options. * @returns Per-paragraph layout results with break points and character arrays. */ layoutChapter(options: ChapterLayoutOptions): Promise; /** * Computes the effective line width for vertical text layout. * Uses the instance's fixedFontSize unless overridden. * * @param containerHeight - Available height in pixels. * @param fontSize - Font size override in pixels. * @returns Effective line width for the line breaking algorithm. */ verticalLineWidth(containerHeight: number, fontSize?: number): number; /** * Clears the width measurement cache. * @param fontKey - If provided, clears only entries for this font. */ clearCache(fontKey?: string): void; /** * Returns the current measurement cache size. * @returns Number of font specs cached and the total number of codepoints * measured across all fonts. */ cacheStats(): { fonts: number; codepoints: number; }; /** @internal Returns the underlying {@link CharMeasurer} so the higher-level * `MejiroBook` can share it with the layout pipeline. */ getMeasurer(): CharMeasurer; } /** * Gesture an {@link OverlayDragSession} applies to the rectangle captured at * pointer-down: `'move'` translates it, `'resize'` grows or shrinks it from the * bottom-right corner. */ type OverlayDragMode = 'move' | 'resize'; /** Inputs for {@link createOverlayDragSession}. */ interface OverlayDragSessionOptions { /** Gesture the session applies to {@link OverlayDragSessionOptions.rect}. */ mode: OverlayDragMode; /** Rectangle captured at pointer-down. Never mutated. */ rect: ImageOverlayRect; /** Pointer x at pointer-down, in client coordinates (px). */ startX: number; /** Pointer y at pointer-down, in client coordinates (px). */ startY: number; /** * Pointer that owns the gesture. When set together with * {@link OverlayDragSessionOptions.captureElement}, the element captures it so * the gesture survives the pointer leaving the overlay. */ pointerId?: number; /** Element the pointer is captured on — usually the pointer-down target. */ captureElement?: HTMLElement | null; /** * Element carrying {@link OverlayDragSessionOptions.dragClass} while the * gesture runs. Often the overlay itself even when the gesture started on a * child handle. */ activeElement?: HTMLElement | null; /** Class toggled on `activeElement` for the duration of the gesture. */ dragClass?: string; /** Minimum width and height in `'resize'` mode (px). @defaultValue 40 */ minSize?: number; /** * Receives the rectangle re-derived from the cumulative pointer delta. Every * call gets a fresh object; the start rectangle is the base each time, so * rounding never accumulates across a gesture. */ onChange: (rect: ImageOverlayRect) => void; /** Called exactly once when the gesture ends, however it ended. */ onEnd?: () => void; /** * Set the session registers its disposer in for the gesture's lifetime, so a * host can end every gesture still in flight when its component unmounts. * The entry removes itself once the gesture ends. */ registry?: Set<() => void>; } /** Handle for a pointer drag started by {@link createOverlayDragSession}. */ interface OverlayDragSession { /** Whether the gesture is still running. */ readonly active: boolean; /** Ends the gesture and releases every listener. Idempotent. */ cancel: () => void; } /** * Starts a pointer drag on an image overlay and returns a handle to it. * * This is the single pointer-drag implementation behind the framework overlay * hooks: it owns pointer capture, the drag class, the document-level * `pointermove` / `pointerup` listeners, animation-frame coalescing and * teardown, leaving each host with nothing but its own state update in * {@link OverlayDragSessionOptions.onChange}. Call it from a pointer-down * handler after the host has decided the gesture applies. * * Framework-agnostic on purpose — no effect or watcher is involved, so the * session can be created from a plain DOM listener as well. It lives in the * browser layer because it drives real DOM APIs; the rectangle arithmetic it * applies stays in the DOM-free core as {@link moveImageOverlayRect} and * {@link resizeImageOverlayRect}. Updates are coalesced with * `requestAnimationFrame` where the runtime provides it, and delivered * synchronously where it does not. * * The rectangle is never clamped to the content area beyond the `'resize'` * minimum size, so an overlay can be dragged partly out of view; a host needing * containment clamps inside `onChange`. * * @param options - Gesture description and callbacks. * @returns A handle whose `cancel()` ends the gesture early. */ declare function createOverlayDragSession(options: OverlayDragSessionOptions): OverlayDragSession; export { ChapterLayoutOptions, ChapterLayoutResult, CharMeasurer, FontFamily, FontLoader, InlineAnnotation, LayoutOptions, MejiroBrowser, MejiroBrowserOptions, type OverlayDragMode, type OverlayDragSession, type OverlayDragSessionOptions, WidthCache, type WidthCacheOptions, createOverlayDragSession, deriveRubyFont, layoutText, verticalLineWidth };