Skip to main content

text_typeset/
types.rs

1/// Opaque handle to a registered font face.
2///
3/// Obtained from [`crate::Typesetter::register_font`] or [`crate::Typesetter::register_font_as`].
4/// Pass to [`crate::Typesetter::set_default_font`] to make it the default.
5#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
6pub struct FontFaceId(pub u32);
7
8// ── Render output ───────────────────────────────────────────────
9
10/// Everything needed to draw one frame.
11///
12/// Produced by [`crate::Typesetter::render`]. Contains glyph quads (textured rectangles
13/// from the atlas), inline image placeholders, and decoration rectangles
14/// (selections, cursor, underlines, table borders, etc.).
15///
16/// The adapter draws the frame in three passes:
17/// 1. Upload `atlas_pixels` as a GPU texture (only when `atlas_dirty` is true).
18/// 2. Draw each [`GlyphQuad`] as a textured rectangle from the atlas.
19/// 3. Draw each [`DecorationRect`] as a colored rectangle.
20pub struct RenderFrame {
21    /// True if the atlas texture changed since the last frame (needs re-upload).
22    pub atlas_dirty: bool,
23    /// Atlas texture width in pixels.
24    pub atlas_width: u32,
25    /// Atlas texture height in pixels.
26    pub atlas_height: u32,
27    /// RGBA pixel data, row-major. Length = `atlas_width * atlas_height * 4`.
28    pub atlas_pixels: Vec<u8>,
29    /// One textured rectangle per visible glyph.
30    pub glyphs: Vec<GlyphQuad>,
31    /// Inline image placeholders. The adapter loads the actual image data
32    /// (e.g., via `TextDocument::resource(name)`) and draws it at the given
33    /// screen position.
34    pub images: Vec<ImageQuad>,
35    /// Decoration rectangles: selections, cursor, underlines, strikeouts,
36    /// overlines, backgrounds, table borders, and cell backgrounds.
37    pub decorations: Vec<DecorationRect>,
38    /// Per-block glyph data for incremental updates. Keyed by block_id.
39    pub(crate) block_glyphs: Vec<(usize, Vec<GlyphQuad>)>,
40    /// Per-block decoration data (underlines, etc. — NOT cursor/selection).
41    pub(crate) block_decorations: Vec<(usize, Vec<DecorationRect>)>,
42    /// Per-block image data for incremental updates.
43    pub(crate) block_images: Vec<(usize, Vec<ImageQuad>)>,
44    /// Per-block height snapshot for detecting height changes in incremental render.
45    pub(crate) block_heights: std::collections::HashMap<usize, f32>,
46}
47
48/// A positioned glyph to draw as a textured quad from the atlas.
49///
50/// The adapter draws the rectangle at `screen` position, sampling from
51/// the `atlas` rectangle in the atlas texture, tinted with `color`.
52#[derive(Clone)]
53pub struct GlyphQuad {
54    /// Screen position and size: `[x, y, width, height]` in pixels.
55    pub screen: [f32; 4],
56    /// Atlas source rectangle: `[x, y, width, height]` in atlas pixel coordinates.
57    pub atlas: [f32; 4],
58    /// Glyph color: `[r, g, b, a]`, 0.0-1.0.
59    /// For normal text glyphs, this is the text color (default black).
60    /// For color emoji, this is `[1, 1, 1, 1]` (color is baked into the atlas).
61    pub color: [f32; 4],
62}
63
64/// An inline image placeholder.
65///
66/// text-typeset computes the position and size but does NOT load or rasterize
67/// the image. The adapter retrieves the image data (e.g., from
68/// `TextDocument::resource(name)`) and draws it as a separate texture.
69#[derive(Clone)]
70pub struct ImageQuad {
71    /// Screen position and size: `[x, y, width, height]` in pixels.
72    pub screen: [f32; 4],
73    /// Image resource name (matches `FragmentContent::Image::name` from text-document).
74    pub name: String,
75}
76
77/// A colored rectangle for decorations (underlines, selections, borders, etc.).
78#[derive(Clone)]
79pub struct DecorationRect {
80    /// Screen position and size: `[x, y, width, height]` in pixels.
81    pub rect: [f32; 4],
82    /// Color: `[r, g, b, a]`, 0.0-1.0.
83    pub color: [f32; 4],
84    /// What kind of decoration this rectangle represents.
85    pub kind: DecorationKind,
86}
87
88/// The type of a [`DecorationRect`].
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum DecorationKind {
91    /// Selection highlight (translucent background behind selected text).
92    Selection,
93    /// Cursor caret (thin vertical line at the insertion point).
94    Cursor,
95    /// Underline (below baseline, from font metrics).
96    Underline,
97    /// Strikethrough (at x-height, from font metrics).
98    Strikeout,
99    /// Overline (at ascent line).
100    Overline,
101    /// Generic background (e.g., frame borders).
102    Background,
103    /// Block-level background color.
104    BlockBackground,
105    /// Table border line.
106    TableBorder,
107    /// Table cell background color.
108    TableCellBackground,
109    /// Text-level background highlight (behind individual text runs).
110    /// Adapters should draw these before glyph quads so text appears on top.
111    TextBackground,
112    /// Cell-level selection highlight (entire cell background when cells are
113    /// selected as a rectangular region, as opposed to text within cells).
114    CellSelection,
115}
116
117/// Underline style for text decorations.
118#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
119pub enum UnderlineStyle {
120    /// No underline.
121    #[default]
122    None,
123    /// Solid single underline.
124    Single,
125    /// Dashed underline.
126    Dash,
127    /// Dotted underline.
128    Dot,
129    /// Alternating dash-dot pattern.
130    DashDot,
131    /// Alternating dash-dot-dot pattern.
132    DashDotDot,
133    /// Wavy underline.
134    Wave,
135    /// Spell-check underline (wavy, typically red).
136    SpellCheck,
137}
138
139/// Vertical alignment for characters (superscript, subscript, etc.).
140#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
141pub enum VerticalAlignment {
142    /// Normal baseline alignment.
143    #[default]
144    Normal,
145    /// Superscript: smaller size, shifted up.
146    SuperScript,
147    /// Subscript: smaller size, shifted down.
148    SubScript,
149}
150
151// ── Hit testing ─────────────────────────────────────────────────
152
153/// Result of [`crate::Typesetter::hit_test`] - maps a screen-space point to a
154/// document position.
155pub struct HitTestResult {
156    /// Absolute character position in the document.
157    pub position: usize,
158    /// Which block (paragraph) was hit, identified by stable block ID.
159    pub block_id: usize,
160    /// Character offset within the block (0 = start of block).
161    pub offset_in_block: usize,
162    /// What region of the layout was hit.
163    pub region: HitRegion,
164    /// Tooltip text if the hit position has a tooltip. None otherwise.
165    pub tooltip: Option<String>,
166}
167
168/// What region of the layout a hit test landed in.
169#[derive(Debug)]
170pub enum HitRegion {
171    /// Inside a text run (normal text content).
172    Text,
173    /// In the block's left margin area (before any text content).
174    LeftMargin,
175    /// In the block's indent area.
176    Indent,
177    /// On a table border line.
178    TableBorder,
179    /// Below all content in the document.
180    BelowContent,
181    /// Past the end of a line (to the right of the last character).
182    PastLineEnd,
183    /// On an inline image.
184    Image { name: String },
185    /// On a hyperlink.
186    Link { href: String },
187}
188
189// ── Cursor display ──────────────────────────────────────────────
190
191/// Cursor display state for rendering.
192///
193/// The adapter reads cursor position from text-document's `TextCursor`
194/// and creates this struct to feed to [`crate::Typesetter::set_cursor`].
195/// text-typeset uses it to generate caret and selection decorations
196/// in the next [`crate::Typesetter::render`] call.
197pub struct CursorDisplay {
198    /// Cursor position (character offset in the document).
199    pub position: usize,
200    /// Selection anchor. Equals `position` when there is no selection.
201    /// When different from `position`, the range `[min(anchor, position), max(anchor, position))`
202    /// is highlighted as a selection.
203    pub anchor: usize,
204    /// Whether the caret is visible (false during the blink-off phase).
205    /// The adapter manages the blink timer; text-typeset just respects this flag.
206    pub visible: bool,
207    /// When non-empty, render cell-level selection highlights instead of
208    /// text-level selection. Each tuple is `(table_id, row, col)` identifying
209    /// a selected cell. The adapter fills this from `TextCursor::selected_cells()`.
210    pub selected_cells: Vec<(usize, usize, usize)>,
211}
212
213// ── Scrolling ───────────────────────────────────────────────────
214
215/// Visual position and size of a laid-out block.
216///
217/// Returned by [`crate::Typesetter::block_visual_info`].
218pub struct BlockVisualInfo {
219    /// Block ID (matches `BlockSnapshot::block_id`).
220    pub block_id: usize,
221    /// Y position of the block's top edge relative to the document start, in pixels.
222    pub y: f32,
223    /// Total height of the block including margins, in pixels.
224    pub height: f32,
225}
226
227impl RenderFrame {
228    pub(crate) fn new() -> Self {
229        Self {
230            atlas_dirty: false,
231            atlas_width: 0,
232            atlas_height: 0,
233            atlas_pixels: Vec::new(),
234            glyphs: Vec::new(),
235            images: Vec::new(),
236            decorations: Vec::new(),
237            block_glyphs: Vec::new(),
238            block_decorations: Vec::new(),
239            block_images: Vec::new(),
240            block_heights: std::collections::HashMap::new(),
241        }
242    }
243}