1use super::{FontData, FontDataInternal};
2use crate::style::text_anchor::Pos;
3use crate::style::{Color, TextStyle};
4
5use std::convert::From;
6
7pub type FontError = <FontDataInternal as FontData>::ErrorType;
9
10pub type FontResult<T> = Result<T, FontError>;
12
13#[derive(Clone)]
15pub enum FontTransform {
16 None,
18 Rotate90,
20 Rotate180,
22 Rotate270,
24}
25
26impl FontTransform {
27 pub fn transform(&self, x: i32, y: i32) -> (i32, i32) {
33 match self {
34 FontTransform::None => (x, y),
35 FontTransform::Rotate90 => (-y, x),
36 FontTransform::Rotate180 => (-x, -y),
37 FontTransform::Rotate270 => (y, -x),
38 }
39 }
40}
41
42#[derive(Clone)]
44pub struct FontDesc<'a> {
45 size: f64,
46 family: FontFamily<'a>,
47 data: FontResult<FontDataInternal>,
48 transform: FontTransform,
49 style: FontStyle,
50}
51
52#[derive(Clone, Copy)]
56pub enum FontFamily<'a> {
57 Serif,
59 SansSerif,
61 Monospace,
63 Name(&'a str),
65}
66
67impl<'a> FontFamily<'a> {
68 pub fn as_str(&self) -> &str {
71 match self {
72 FontFamily::Serif => "宋体",
73 FontFamily::SansSerif => "宋体",
74 FontFamily::Monospace => "monospace",
75 FontFamily::Name(face) => face,
76 }
77 }
78}
79
80impl<'a> From<&'a str> for FontFamily<'a> {
81 fn from(from: &'a str) -> FontFamily<'a> {
82 match from.to_lowercase().as_str() {
83 "serif" => FontFamily::Serif,
84 "sans-serif" => FontFamily::SansSerif,
85 "monospace" => FontFamily::Monospace,
86 _ => FontFamily::Name(from),
87 }
88 }
89}
90
91#[derive(Clone, Copy)]
93pub enum FontStyle {
94 Normal,
96 Oblique,
98 Italic,
100 Bold,
102}
103
104impl FontStyle {
105 pub fn as_str(&self) -> &str {
107 match self {
108 FontStyle::Normal => "normal",
109 FontStyle::Italic => "italic",
110 FontStyle::Oblique => "oblique",
111 FontStyle::Bold => "bold",
112 }
113 }
114}
115
116impl<'a> From<&'a str> for FontStyle {
117 fn from(from: &'a str) -> FontStyle {
118 match from.to_lowercase().as_str() {
119 "normal" => FontStyle::Normal,
120 "italic" => FontStyle::Italic,
121 "oblique" => FontStyle::Oblique,
122 "bold" => FontStyle::Bold,
123 _ => FontStyle::Normal,
124 }
125 }
126}
127
128impl<'a> From<&'a str> for FontDesc<'a> {
129 fn from(from: &'a str) -> FontDesc<'a> {
130 FontDesc::new(from.into(), 1.0, FontStyle::Normal)
131 }
132}
133
134impl<'a> From<FontFamily<'a>> for FontDesc<'a> {
135 fn from(family: FontFamily<'a>) -> FontDesc<'a> {
136 FontDesc::new(family, 1.0, FontStyle::Normal)
137 }
138}
139
140impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> {
141 fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> {
142 FontDesc::new(family, size.into(), FontStyle::Normal)
143 }
144}
145
146impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
147 fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
148 FontDesc::new(typeface.into(), size.into(), FontStyle::Normal)
149 }
150}
151
152impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(FontFamily<'a>, T, S)> for FontDesc<'a> {
153 fn from((family, size, style): (FontFamily<'a>, T, S)) -> FontDesc<'a> {
154 FontDesc::new(family, size.into(), style.into())
155 }
156}
157
158impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(&'a str, T, S)> for FontDesc<'a> {
159 fn from((typeface, size, style): (&'a str, T, S)) -> FontDesc<'a> {
160 FontDesc::new(typeface.into(), size.into(), style.into())
161 }
162}
163
164pub trait IntoFont<'a> {
166 fn into_font(self) -> FontDesc<'a>;
168}
169
170impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
171 fn into_font(self) -> FontDesc<'a> {
172 self.into()
173 }
174}
175
176impl<'a> FontDesc<'a> {
177 pub fn new(family: FontFamily<'a>, size: f64, style: FontStyle) -> Self {
184 Self {
185 size,
186 family,
187 data: FontDataInternal::new(family, style),
188 transform: FontTransform::None,
189 style,
190 }
191 }
192
193 pub fn resize(&self, size: f64) -> FontDesc<'a> {
198 Self {
199 size,
200 family: self.family,
201 data: self.data.clone(),
202 transform: self.transform.clone(),
203 style: self.style,
204 }
205 }
206
207 pub fn style(&self, style: FontStyle) -> Self {
212 Self {
213 size: self.size,
214 family: self.family,
215 data: self.data.clone(),
216 transform: self.transform.clone(),
217 style,
218 }
219 }
220
221 pub fn transform(&self, trans: FontTransform) -> Self {
226 Self {
227 size: self.size,
228 family: self.family,
229 data: self.data.clone(),
230 transform: trans,
231 style: self.style,
232 }
233 }
234
235 pub fn get_transform(&self) -> FontTransform {
237 self.transform.clone()
238 }
239
240 pub fn color<C: Color>(&self, color: &C) -> TextStyle<'a> {
242 TextStyle {
243 font: self.clone(),
244 color: color.to_rgba(),
245 pos: Pos::default(),
246 }
247 }
248
249 pub fn get_name(&self) -> &str {
251 self.family.as_str()
252 }
253
254 pub fn get_style(&self) -> FontStyle {
256 self.style
257 }
258
259 pub fn get_size(&self) -> f64 {
261 self.size
262 }
263
264 pub fn layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))> {
269 match &self.data {
270 Ok(ref font) => font.estimate_layout(self.size, text),
271 Err(e) => Err(e.clone()),
272 }
273 }
274
275 pub fn box_size(&self, text: &str) -> FontResult<(u32, u32)> {
279 let ((min_x, min_y), (max_x, max_y)) = self.layout_box(text)?;
280 let (w, h) = self.get_transform().transform(max_x - min_x, max_y - min_y);
281 Ok((w.abs() as u32, h.abs() as u32))
282 }
283
284 pub fn draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>(
286 &self,
287 text: &str,
288 (x, y): (i32, i32),
289 draw: DrawFunc,
290 ) -> FontResult<Result<(), E>> {
291 match &self.data {
292 Ok(ref font) => font.draw((x, y), self.size, text, draw),
293 Err(e) => Err(e.clone()),
294 }
295 }
296}