cosmic_text/
layout.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use core::fmt::Display;
4
5#[cfg(not(feature = "std"))]
6use alloc::vec::Vec;
7
8use crate::{math, CacheKey, CacheKeyFlags, Color};
9
10/// A laid out glyph
11#[derive(Clone, Debug)]
12pub struct LayoutGlyph {
13    /// Start index of cluster in original line
14    pub start: usize,
15    /// End index of cluster in original line
16    pub end: usize,
17    /// Font size of the glyph
18    pub font_size: f32,
19    /// Line height of the glyph, will override buffer setting
20    pub line_height_opt: Option<f32>,
21    /// Font id of the glyph
22    pub font_id: fontdb::ID,
23    /// Font id of the glyph
24    pub glyph_id: u16,
25    /// X offset of hitbox
26    pub x: f32,
27    /// Y offset of hitbox
28    pub y: f32,
29    /// Width of hitbox
30    pub w: f32,
31    /// Unicode `BiDi` embedding level, character is left-to-right if `level` is divisible by 2
32    pub level: unicode_bidi::Level,
33    /// X offset in line
34    ///
35    /// If you are dealing with physical coordinates, use [`Self::physical`] to obtain a
36    /// [`PhysicalGlyph`] for rendering.
37    ///
38    /// This offset is useful when you are dealing with logical units and you do not care or
39    /// cannot guarantee pixel grid alignment. For instance, when you want to use the glyphs
40    /// for vectorial text, apply linear transformations to the layout, etc.
41    pub x_offset: f32,
42    /// Y offset in line
43    ///
44    /// If you are dealing with physical coordinates, use [`Self::physical`] to obtain a
45    /// [`PhysicalGlyph`] for rendering.
46    ///
47    /// This offset is useful when you are dealing with logical units and you do not care or
48    /// cannot guarantee pixel grid alignment. For instance, when you want to use the glyphs
49    /// for vectorial text, apply linear transformations to the layout, etc.
50    pub y_offset: f32,
51    /// Optional color override
52    pub color_opt: Option<Color>,
53    /// Metadata from `Attrs`
54    pub metadata: usize,
55    /// [`CacheKeyFlags`]
56    pub cache_key_flags: CacheKeyFlags,
57}
58
59#[derive(Clone, Debug)]
60pub struct PhysicalGlyph {
61    /// Cache key, see [`CacheKey`]
62    pub cache_key: CacheKey,
63    /// Integer component of X offset in line
64    pub x: i32,
65    /// Integer component of Y offset in line
66    pub y: i32,
67}
68
69impl LayoutGlyph {
70    pub fn physical(&self, offset: (f32, f32), scale: f32) -> PhysicalGlyph {
71        let x_offset = self.font_size * self.x_offset;
72        let y_offset = self.font_size * self.y_offset;
73
74        let (cache_key, x, y) = CacheKey::new(
75            self.font_id,
76            self.glyph_id,
77            self.font_size * scale,
78            (
79                (self.x + x_offset) * scale + offset.0,
80                math::truncf((self.y - y_offset) * scale + offset.1), // Hinting in Y axis
81            ),
82            self.cache_key_flags,
83        );
84
85        PhysicalGlyph { cache_key, x, y }
86    }
87}
88
89/// A line of laid out glyphs
90#[derive(Clone, Debug)]
91pub struct LayoutLine {
92    /// Width of the line
93    pub w: f32,
94    /// Maximum ascent of the glyphs in line
95    pub max_ascent: f32,
96    /// Maximum descent of the glyphs in line
97    pub max_descent: f32,
98    /// Maximum line height of any spans in line
99    pub line_height_opt: Option<f32>,
100    /// Glyphs in line
101    pub glyphs: Vec<LayoutGlyph>,
102}
103
104/// Wrapping mode
105#[derive(Debug, Eq, PartialEq, Clone, Copy)]
106pub enum Wrap {
107    /// No wrapping
108    None,
109    /// Wraps at a glyph level
110    Glyph,
111    /// Wraps at the word level
112    Word,
113    /// Wraps at the word level, or fallback to glyph level if a word can't fit on a line by itself
114    WordOrGlyph,
115}
116
117impl Display for Wrap {
118    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
119        match self {
120            Self::None => write!(f, "No Wrap"),
121            Self::Word => write!(f, "Word Wrap"),
122            Self::WordOrGlyph => write!(f, "Word Wrap or Character"),
123            Self::Glyph => write!(f, "Character"),
124        }
125    }
126}
127
128/// Align or justify
129#[derive(Debug, Eq, PartialEq, Clone, Copy)]
130pub enum Align {
131    Left,
132    Right,
133    Center,
134    Justified,
135    End,
136}
137
138impl Display for Align {
139    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
140        match self {
141            Self::Left => write!(f, "Left"),
142            Self::Right => write!(f, "Right"),
143            Self::Center => write!(f, "Center"),
144            Self::Justified => write!(f, "Justified"),
145            Self::End => write!(f, "End"),
146        }
147    }
148}