cosmic_text/
layout.rs

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