ori_core/text/
fonts.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use std::{
    any::{Any, TypeId},
    ops::Range,
};

use crate::layout::{Point, Rect, Size};

use super::{FontSource, Paragraph};

/// A trait for managing fonts and text layout.
pub trait Fonts: Any {
    /// Load the given font source.
    ///
    /// If `name` is provided, the fonts will be registered under that name
    /// instead of the default name provided by the source.
    fn load(&mut self, source: FontSource<'_>, name: Option<&str>);

    /// Layout the given paragraph with the given max width.
    fn layout(&mut self, paragraph: &Paragraph, width: f32) -> Vec<TextLayoutLine>;

    /// Measure the given paragraph with the given max width.
    fn measure(&mut self, paragraph: &Paragraph, width: f32) -> Size;
}

impl dyn Fonts {
    /// Attempt to downcast a reference to a concrete type.
    pub fn downcast_ref<T: Fonts>(&self) -> Option<&T> {
        if self.type_id() == TypeId::of::<T>() {
            let ptr = self as *const dyn Fonts as *const T;

            // SAFETY: We just checked that the type ID is correct.
            unsafe { Some(&*ptr) }
        } else {
            None
        }
    }

    /// Attempt to downcast a mutable reference to a concrete type.
    pub fn downcast_mut<T: Fonts>(&mut self) -> Option<&mut T> {
        if (*self).type_id() == TypeId::of::<T>() {
            let ptr = self as *mut dyn Fonts as *mut T;

            // SAFETY: We just checked that the type ID is correct.
            unsafe { Some(&mut *ptr) }
        } else {
            None
        }
    }
}

/// A line of text layout.
#[derive(Clone, Debug)]
pub struct TextLayoutLine {
    /// The ascent of the line.
    pub ascent: f32,

    /// The descent of the line.
    pub descent: f32,

    /// The left edge of the line.
    pub left: f32,

    /// The width of the line.
    pub width: f32,

    /// The height of the line.
    pub height: f32,

    /// The baseline of the line.
    pub baseline: f32,

    /// The range of the line in the original text.
    pub range: Range<usize>,

    /// The glyphs in the line.
    pub glyphs: Vec<GlyphCluster>,
}

impl TextLayoutLine {
    /// The left edge of the line.
    ///
    /// This is the same as 'left'.
    /// other edge methods.
    pub fn left(&self) -> f32 {
        self.left
    }

    /// The right edge of the line.
    ///
    /// This is the same as `left + width`.
    pub fn right(&self) -> f32 {
        self.left + self.width
    }

    /// The top edge of the line.
    ///
    /// This is the same as `baseline - ascent`.
    pub fn top(&self) -> f32 {
        self.baseline - self.ascent
    }

    /// The bottom edge of the line.
    ///
    /// This is the same as `baseline + descent`.
    pub fn bottom(&self) -> f32 {
        self.baseline + self.descent
    }

    /// The height of the line.
    pub fn width(&self) -> f32 {
        self.width
    }

    /// The height of the line.
    ///
    /// This is the same as `ascent + descent`.
    pub fn height(&self) -> f32 {
        self.height
    }

    /// The bounds of the line.
    pub fn bounds(&self) -> Rect {
        Rect::new(
            Point::new(self.left(), self.top()),
            Point::new(self.right(), self.bottom()),
        )
    }
}

/// A glyph cluster in a line of laid out text.
#[derive(Clone, Debug)]
pub struct GlyphCluster {
    /// The bounds of the cluster in local space.
    pub bounds: Rect,

    /// The byte range of the cluster in the original text.
    pub range: Range<usize>,

    /// The direction of the cluster.
    pub direction: TextDirection,
}

/// The direction of text.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TextDirection {
    /// Left-to-right text.
    Ltr,

    /// Right-to-left text.
    Rtl,
}