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