floem_renderer/text/
mod.rs1mod attrs;
11
12use peniko::{
13 BrushRef, Fill, FontData, StyleRef,
14 kurbo::{Affine, Point},
15};
16
17pub use attrs::{Attrs, AttrsList, AttrsOwned, FamilyOwned, LineHeightValue};
18pub use fontique::{FontStyle, FontWeight, FontWidth};
19pub use parley::layout::Glyph;
20
21#[derive(Clone, Copy, Debug, PartialEq)]
30pub struct TextBrush(pub peniko::Color);
31
32impl Default for TextBrush {
33 fn default() -> Self {
34 TextBrush(peniko::Color::from_rgba8(0, 0, 0, 255))
35 }
36}
37
38impl From<peniko::Color> for TextBrush {
39 fn from(c: peniko::Color) -> Self {
40 TextBrush(c)
41 }
42}
43
44impl From<TextBrush> for peniko::Color {
45 fn from(b: TextBrush) -> Self {
46 b.0
47 }
48}
49
50pub type NormalizedCoord = i16;
52
53#[derive(Clone, Debug)]
55pub struct GlyphRunProps<'a> {
56 pub font: FontData,
57 pub font_size: f32,
58 pub hint: bool,
59 pub normalized_coords: &'a [NormalizedCoord],
60 pub style: StyleRef<'a>,
61 pub brush: BrushRef<'a>,
62 pub brush_alpha: f32,
63 pub transform: Affine,
64 pub glyph_transform: Option<Affine>,
65}
66
67impl<'a> GlyphRunProps<'a> {
68 pub fn new(font: &FontData) -> Self {
69 Self {
70 font: font.clone(),
71 font_size: 16.0,
72 hint: false,
73 normalized_coords: &[],
74 style: Fill::NonZero.into(),
75 brush: peniko::color::palette::css::BLACK.into(),
76 brush_alpha: 1.0,
77 transform: Affine::IDENTITY,
78 glyph_transform: None,
79 }
80 }
81
82 pub fn font(mut self, font: &FontData) -> Self {
83 self.font = font.clone();
84 self
85 }
86
87 pub fn font_size(mut self, font_size: f32) -> Self {
88 self.font_size = font_size;
89 self
90 }
91
92 pub fn hint(mut self, hint: bool) -> Self {
93 self.hint = hint;
94 self
95 }
96
97 pub fn normalized_coords(mut self, normalized_coords: &'a [NormalizedCoord]) -> Self {
98 self.normalized_coords = normalized_coords;
99 self
100 }
101
102 pub fn style(mut self, style: impl Into<StyleRef<'a>>) -> Self {
103 self.style = style.into();
104 self
105 }
106
107 pub fn brush(mut self, brush: impl Into<BrushRef<'a>>) -> Self {
108 self.brush = brush.into();
109 self
110 }
111
112 pub fn brush_alpha(mut self, brush_alpha: f32) -> Self {
113 self.brush_alpha = brush_alpha;
114 self
115 }
116
117 pub fn transform(mut self, transform: Affine) -> Self {
118 self.transform = transform;
119 self
120 }
121
122 pub fn glyph_transform(mut self, glyph_transform: Option<Affine>) -> Self {
123 self.glyph_transform = glyph_transform;
124 self
125 }
126}
127
128pub trait GlyphDrawer {
129 fn draw_glyphs<'a>(
130 &mut self,
131 origin: Point,
132 props: &GlyphRunProps<'a>,
133 glyphs: impl Iterator<Item = Glyph> + 'a,
134 );
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
144 fn text_brush_default_is_opaque_black() {
145 let b = TextBrush::default();
146 let c: peniko::Color = b.into();
147 assert_eq!(c, peniko::Color::from_rgba8(0, 0, 0, 255));
148 }
149
150 #[test]
151 fn text_glyphs_props_default_is_usable() {
152 let font = FontData::new(peniko::Blob::new(std::sync::Arc::new([])), 0);
153 let props = GlyphRunProps::new(&font);
154 assert_eq!(props.font, font);
155 assert_eq!(props.font_size, 16.0);
156 assert_eq!(props.brush_alpha, 1.0);
157 assert_eq!(props.transform, Affine::IDENTITY);
158 assert!(props.normalized_coords.is_empty());
159 }
160}