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,
}