1 | use crate::layout::GlyphRasterConfig; |
2 | use crate::math::{Geometry, Line}; |
3 | use crate::platform::{as_i32, ceil, floor, fract, is_negative}; |
4 | use crate::raster::Raster; |
5 | use crate::table::{load_gsub, TableKern}; |
6 | use crate::unicode; |
7 | use crate::FontResult; |
8 | use alloc::string::String; |
9 | use alloc::vec; |
10 | use alloc::vec::*; |
11 | use core::hash::{Hash, Hasher}; |
12 | use core::mem; |
13 | use core::num::NonZeroU16; |
14 | use core::ops::Deref; |
15 | use hashbrown::{HashMap, HashSet}; |
16 | use ttf_parser::{Face, FaceParsingError, GlyphId, Tag}; |
17 | |
18 | #[cfg (feature = "parallel" )] |
19 | use rayon::prelude::*; |
20 | |
21 | /// Defines the bounds for a glyph's outline in subpixels. A glyph's outline is always contained in |
22 | /// its bitmap. |
23 | #[derive (Copy, Clone, PartialEq, Debug)] |
24 | pub struct OutlineBounds { |
25 | /// Subpixel offset of the left-most edge of the glyph's outline. |
26 | pub xmin: f32, |
27 | /// Subpixel offset of the bottom-most edge of the glyph's outline. |
28 | pub ymin: f32, |
29 | /// The width of the outline in subpixels. |
30 | pub width: f32, |
31 | /// The height of the outline in subpixels. |
32 | pub height: f32, |
33 | } |
34 | |
35 | impl Default for OutlineBounds { |
36 | fn default() -> Self { |
37 | Self { |
38 | xmin: 0.0, |
39 | ymin: 0.0, |
40 | width: 0.0, |
41 | height: 0.0, |
42 | } |
43 | } |
44 | } |
45 | |
46 | impl OutlineBounds { |
47 | /// Scales the bounding box by the given factor. |
48 | #[inline (always)] |
49 | pub fn scale(&self, scale: f32) -> OutlineBounds { |
50 | OutlineBounds { |
51 | xmin: self.xmin * scale, |
52 | ymin: self.ymin * scale, |
53 | width: self.width * scale, |
54 | height: self.height * scale, |
55 | } |
56 | } |
57 | } |
58 | |
59 | /// Encapsulates all layout information associated with a glyph for a fixed scale. |
60 | #[derive (Copy, Clone, PartialEq, Debug)] |
61 | pub struct Metrics { |
62 | /// Whole pixel offset of the left-most edge of the bitmap. This may be negative to reflect the |
63 | /// glyph is positioned to the left of the origin. |
64 | pub xmin: i32, |
65 | /// Whole pixel offset of the bottom-most edge of the bitmap. This may be negative to reflect |
66 | /// the glyph is positioned below the baseline. |
67 | pub ymin: i32, |
68 | /// The width of the bitmap in whole pixels. |
69 | pub width: usize, |
70 | /// The height of the bitmap in whole pixels. |
71 | pub height: usize, |
72 | /// Advance width of the glyph in subpixels. Used in horizontal fonts. |
73 | pub advance_width: f32, |
74 | /// Advance height of the glyph in subpixels. Used in vertical fonts. |
75 | pub advance_height: f32, |
76 | /// The bounding box that contains the glyph's outline at the offsets specified by the font. |
77 | /// This is always a smaller box than the bitmap bounds. |
78 | pub bounds: OutlineBounds, |
79 | } |
80 | |
81 | impl Default for Metrics { |
82 | fn default() -> Self { |
83 | Metrics { |
84 | xmin: 0, |
85 | ymin: 0, |
86 | width: 0, |
87 | height: 0, |
88 | advance_width: 0.0, |
89 | advance_height: 0.0, |
90 | bounds: OutlineBounds::default(), |
91 | } |
92 | } |
93 | } |
94 | |
95 | /// Metrics associated with line positioning. |
96 | #[derive (Copy, Clone, PartialEq, Debug)] |
97 | pub struct LineMetrics { |
98 | /// The highest point that any glyph in the font extends to above the baseline. Typically |
99 | /// positive. |
100 | pub ascent: f32, |
101 | /// The lowest point that any glyph in the font extends to below the baseline. Typically |
102 | /// negative. |
103 | pub descent: f32, |
104 | /// The gap to leave between the descent of one line and the ascent of the next. This is of |
105 | /// course only a guideline given by the font's designers. |
106 | pub line_gap: f32, |
107 | /// A precalculated value for the height or width of the line depending on if the font is laid |
108 | /// out horizontally or vertically. It's calculated by: ascent - descent + line_gap. |
109 | pub new_line_size: f32, |
110 | } |
111 | |
112 | impl LineMetrics { |
113 | /// Creates a new line metrics struct and computes the new line size. |
114 | fn new(ascent: i16, descent: i16, line_gap: i16) -> LineMetrics { |
115 | // Operations between this values can exceed i16, so we extend to i32 here. |
116 | let (ascent: i32, descent: i32, line_gap: i32) = (ascent as i32, descent as i32, line_gap as i32); |
117 | LineMetrics { |
118 | ascent: ascent as f32, |
119 | descent: descent as f32, |
120 | line_gap: line_gap as f32, |
121 | new_line_size: (ascent - descent + line_gap) as f32, |
122 | } |
123 | } |
124 | |
125 | /// Scales the line metrics by the given factor. |
126 | #[inline (always)] |
127 | fn scale(&self, scale: f32) -> LineMetrics { |
128 | LineMetrics { |
129 | ascent: self.ascent * scale, |
130 | descent: self.descent * scale, |
131 | line_gap: self.line_gap * scale, |
132 | new_line_size: self.new_line_size * scale, |
133 | } |
134 | } |
135 | } |
136 | |
137 | /// Stores compiled geometry and metric information. |
138 | #[derive (Clone)] |
139 | pub(crate) struct Glyph { |
140 | pub v_lines: Vec<Line>, |
141 | pub m_lines: Vec<Line>, |
142 | advance_width: f32, |
143 | advance_height: f32, |
144 | pub bounds: OutlineBounds, |
145 | } |
146 | |
147 | impl Default for Glyph { |
148 | fn default() -> Self { |
149 | Glyph { |
150 | v_lines: Vec::new(), |
151 | m_lines: Vec::new(), |
152 | advance_width: 0.0, |
153 | advance_height: 0.0, |
154 | bounds: OutlineBounds::default(), |
155 | } |
156 | } |
157 | } |
158 | |
159 | /// Settings for controlling specific font and layout behavior. |
160 | #[derive (Copy, Clone, PartialEq, Debug)] |
161 | pub struct FontSettings { |
162 | /// The default is 0. The index of the font to use if parsing a font collection. |
163 | pub collection_index: u32, |
164 | /// The default is 40. The scale in px the font geometry is optimized for. Fonts rendered at |
165 | /// the scale defined here will be the most optimal in terms of looks and performance. Glyphs |
166 | /// rendered smaller than this scale will look the same but perform slightly worse, while |
167 | /// glyphs rendered larger than this will looks worse but perform slightly better. The units of |
168 | /// the scale are pixels per Em unit. |
169 | pub scale: f32, |
170 | /// The default is true. If enabled, will load glyphs for substitutions (liagtures, etc.) from |
171 | /// the gsub table on compatible fonrs. Only makes a difference when using indexed operations, |
172 | /// i.e. `Font::raserize_indexed`, as singular characters do not have enough context to be |
173 | /// substituted. |
174 | pub load_substitutions: bool, |
175 | } |
176 | |
177 | impl Default for FontSettings { |
178 | fn default() -> FontSettings { |
179 | FontSettings { |
180 | collection_index: 0, |
181 | scale: 40.0, |
182 | load_substitutions: true, |
183 | } |
184 | } |
185 | } |
186 | |
187 | /// Represents a font. Fonts are immutable after creation and owns its own copy of the font data. |
188 | #[derive (Clone)] |
189 | pub struct Font { |
190 | name: Option<String>, |
191 | units_per_em: f32, |
192 | glyphs: Vec<Glyph>, |
193 | char_to_glyph: HashMap<char, NonZeroU16>, |
194 | horizontal_line_metrics: Option<LineMetrics>, |
195 | horizontal_kern: Option<HashMap<u32, i16>>, |
196 | vertical_line_metrics: Option<LineMetrics>, |
197 | settings: FontSettings, |
198 | hash: usize, |
199 | } |
200 | |
201 | impl Hash for Font { |
202 | fn hash<H: Hasher>(&self, state: &mut H) { |
203 | self.hash.hash(state); |
204 | } |
205 | } |
206 | |
207 | impl core::fmt::Debug for Font { |
208 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
209 | f&mut DebugStruct<'_, '_>.debug_struct("Font" ) |
210 | .field("name" , &self.name) |
211 | .field("settings" , &self.settings) |
212 | .field("units_per_em" , &self.units_per_em) |
213 | .field(name:"hash" , &self.hash) |
214 | .finish() |
215 | } |
216 | } |
217 | |
218 | /// Converts a ttf-parser FaceParsingError into a string. |
219 | fn convert_error(error: FaceParsingError) -> &'static str { |
220 | use FaceParsingError::*; |
221 | match error { |
222 | MalformedFont => "An attempt to read out of bounds detected." , |
223 | UnknownMagic => "Face data must start with 0x00010000, 0x74727565, 0x4F54544F or 0x74746366." , |
224 | FaceIndexOutOfBounds => "The face index is larger than the number of faces in the font." , |
225 | NoHeadTable => "The head table is missing or malformed." , |
226 | NoHheaTable => "The hhea table is missing or malformed." , |
227 | NoMaxpTable => "The maxp table is missing or malformed." , |
228 | } |
229 | } |
230 | |
231 | fn convert_name(face: &Face) -> Option<String> { |
232 | for name: Name<'_> in face.names() { |
233 | if name.name_id == 4 && name.is_unicode() { |
234 | return Some(unicode::decode_utf16(bytes:name.name)); |
235 | } |
236 | } |
237 | None |
238 | } |
239 | |
240 | impl Font { |
241 | /// Constructs a font from an array of bytes. |
242 | pub fn from_bytes<Data: Deref<Target = [u8]>>(data: Data, settings: FontSettings) -> FontResult<Font> { |
243 | let hash = crate::hash::hash(&data); |
244 | |
245 | let face = match Face::parse(&data, settings.collection_index) { |
246 | Ok(f) => f, |
247 | Err(e) => return Err(convert_error(e)), |
248 | }; |
249 | let name = convert_name(&face); |
250 | |
251 | // Optionally get kerning values for the font. This should be a try block in the future. |
252 | let horizontal_kern: Option<HashMap<u32, i16>> = (|| { |
253 | let table: &[u8] = face.raw_face().table(Tag::from_bytes(&b"kern" ))?; |
254 | let table: TableKern = TableKern::new(table)?; |
255 | Some(table.horizontal_mappings) |
256 | })(); |
257 | |
258 | // Collect all the unique codepoint to glyph mappings. |
259 | let glyph_count = face.number_of_glyphs(); |
260 | let mut indices_to_load = HashSet::with_capacity(glyph_count as usize); |
261 | let mut char_to_glyph = HashMap::with_capacity(glyph_count as usize); |
262 | indices_to_load.insert(0u16); |
263 | if let Some(subtable) = face.tables().cmap { |
264 | for subtable in subtable.subtables { |
265 | subtable.codepoints(|codepoint| { |
266 | if let Some(mapping) = subtable.glyph_index(codepoint) { |
267 | if let Some(mapping) = NonZeroU16::new(mapping.0) { |
268 | indices_to_load.insert(mapping.get()); |
269 | char_to_glyph.insert(unsafe { mem::transmute(codepoint) }, mapping); |
270 | } |
271 | } |
272 | }) |
273 | } |
274 | } |
275 | |
276 | // If the gsub table exists and the user needs it, add all of its glyphs to the glyphs we should load. |
277 | if settings.load_substitutions { |
278 | load_gsub(&face, &mut indices_to_load); |
279 | } |
280 | |
281 | let units_per_em = face.units_per_em() as f32; |
282 | |
283 | // Parse and store all unique codepoints. |
284 | let mut glyphs: Vec<Glyph> = vec::from_elem(Glyph::default(), glyph_count as usize); |
285 | |
286 | let generate_glyph = |index: u16| -> Result<Glyph, &'static str> { |
287 | if index >= glyph_count { |
288 | return Err("Attempted to map a codepoint out of bounds." ); |
289 | } |
290 | |
291 | let mut glyph = Glyph::default(); |
292 | let glyph_id = GlyphId(index); |
293 | if let Some(advance_width) = face.glyph_hor_advance(glyph_id) { |
294 | glyph.advance_width = advance_width as f32; |
295 | } |
296 | if let Some(advance_height) = face.glyph_ver_advance(glyph_id) { |
297 | glyph.advance_height = advance_height as f32; |
298 | } |
299 | |
300 | let mut geometry = Geometry::new(settings.scale, units_per_em); |
301 | face.outline_glyph(glyph_id, &mut geometry); |
302 | geometry.finalize(&mut glyph); |
303 | Ok(glyph) |
304 | }; |
305 | |
306 | #[cfg (not(feature = "parallel" ))] |
307 | for index in indices_to_load { |
308 | glyphs[index as usize] = generate_glyph(index)?; |
309 | } |
310 | |
311 | #[cfg (feature = "parallel" )] |
312 | { |
313 | let generated: Vec<(u16, Glyph)> = indices_to_load |
314 | .into_par_iter() |
315 | .map(|index| Ok((index, generate_glyph(index)?))) |
316 | .collect::<Result<_, _>>()?; |
317 | for (index, glyph) in generated { |
318 | glyphs[index as usize] = glyph; |
319 | } |
320 | } |
321 | |
322 | // New line metrics. |
323 | let horizontal_line_metrics = |
324 | Some(LineMetrics::new(face.ascender(), face.descender(), face.line_gap())); |
325 | let vertical_line_metrics = if let Some(ascender) = face.vertical_ascender() { |
326 | Some(LineMetrics::new( |
327 | ascender, |
328 | face.vertical_descender().unwrap_or(0), |
329 | face.vertical_line_gap().unwrap_or(0), |
330 | )) |
331 | } else { |
332 | None |
333 | }; |
334 | |
335 | Ok(Font { |
336 | name, |
337 | glyphs, |
338 | char_to_glyph, |
339 | units_per_em, |
340 | horizontal_line_metrics, |
341 | horizontal_kern, |
342 | vertical_line_metrics, |
343 | settings, |
344 | hash, |
345 | }) |
346 | } |
347 | |
348 | /// Returns all valid unicode codepoints that have mappings to glyph geometry in the font, along |
349 | /// with their associated index. This does not include grapheme cluster mappings. The mapped |
350 | /// NonZeroU16 index can be used in the _indexed font functions. |
351 | pub fn chars(&self) -> &HashMap<char, NonZeroU16> { |
352 | &self.char_to_glyph |
353 | } |
354 | |
355 | /// Returns a precomputed hash for the font file. |
356 | pub fn file_hash(&self) -> usize { |
357 | self.hash |
358 | } |
359 | |
360 | /// New line metrics for fonts that append characters to lines horizontally, and append new |
361 | /// lines vertically (above or below the current line). Only populated for fonts with the |
362 | /// appropriate metrics, none if it's missing. |
363 | /// # Arguments |
364 | /// |
365 | /// * `px` - The size to scale the line metrics by. The units of the scale are pixels per Em |
366 | /// unit. |
367 | pub fn horizontal_line_metrics(&self, px: f32) -> Option<LineMetrics> { |
368 | let metrics = self.horizontal_line_metrics?; |
369 | Some(metrics.scale(self.scale_factor(px))) |
370 | } |
371 | |
372 | /// New line metrics for fonts that append characters to lines vertically, and append new |
373 | /// lines horizontally (left or right of the current line). Only populated for fonts with the |
374 | /// appropriate metrics, none if it's missing. |
375 | /// # Arguments |
376 | /// |
377 | /// * `px` - The size to scale the line metrics by. The units of the scale are pixels per Em |
378 | /// unit. |
379 | pub fn vertical_line_metrics(&self, px: f32) -> Option<LineMetrics> { |
380 | let metrics = self.vertical_line_metrics?; |
381 | Some(metrics.scale(self.scale_factor(px))) |
382 | } |
383 | |
384 | /// Gets the font's units per em. |
385 | #[inline (always)] |
386 | pub fn units_per_em(&self) -> f32 { |
387 | self.units_per_em |
388 | } |
389 | |
390 | /// Calculates the glyph's outline scale factor for a given px size. The units of the scale are |
391 | /// pixels per Em unit. |
392 | #[inline (always)] |
393 | pub fn scale_factor(&self, px: f32) -> f32 { |
394 | px / self.units_per_em |
395 | } |
396 | |
397 | /// Retrieves the horizontal scaled kerning value for two adjacent characters. |
398 | /// # Arguments |
399 | /// |
400 | /// * `left` - The character on the left hand side of the pairing. |
401 | /// * `right` - The character on the right hand side of the pairing. |
402 | /// * `px` - The size to scale the kerning value for. The units of the scale are pixels per Em |
403 | /// unit. |
404 | /// # Returns |
405 | /// |
406 | /// * `Option<f32>` - The horizontal scaled kerning value if one is present in the font for the |
407 | /// given left and right pair, None otherwise. |
408 | #[inline (always)] |
409 | pub fn horizontal_kern(&self, left: char, right: char, px: f32) -> Option<f32> { |
410 | self.horizontal_kern_indexed(self.lookup_glyph_index(left), self.lookup_glyph_index(right), px) |
411 | } |
412 | |
413 | /// Retrieves the horizontal scaled kerning value for two adjacent glyph indicies. |
414 | /// # Arguments |
415 | /// |
416 | /// * `left` - The glyph index on the left hand side of the pairing. |
417 | /// * `right` - The glyph index on the right hand side of the pairing. |
418 | /// * `px` - The size to scale the kerning value for. The units of the scale are pixels per Em |
419 | /// unit. |
420 | /// # Returns |
421 | /// |
422 | /// * `Option<f32>` - The horizontal scaled kerning value if one is present in the font for the |
423 | /// given left and right pair, None otherwise. |
424 | #[inline (always)] |
425 | pub fn horizontal_kern_indexed(&self, left: u16, right: u16, px: f32) -> Option<f32> { |
426 | let scale = self.scale_factor(px); |
427 | let map = self.horizontal_kern.as_ref()?; |
428 | let key = u32::from(left) << 16 | u32::from(right); |
429 | let value = map.get(&key)?; |
430 | Some((*value as f32) * scale) |
431 | } |
432 | |
433 | /// Retrieves the layout metrics for the given character. If the character isn't present in the |
434 | /// font, then the layout for the font's default character is returned instead. |
435 | /// # Arguments |
436 | /// |
437 | /// * `index` - The character in the font to to generate the layout metrics for. |
438 | /// * `px` - The size to generate the layout metrics for the character at. Cannot be negative. |
439 | /// The units of the scale are pixels per Em unit. |
440 | /// # Returns |
441 | /// |
442 | /// * `Metrics` - Sizing and positioning metadata for the glyph. |
443 | #[inline ] |
444 | pub fn metrics(&self, character: char, px: f32) -> Metrics { |
445 | self.metrics_indexed(self.lookup_glyph_index(character), px) |
446 | } |
447 | |
448 | /// Retrieves the layout metrics at the given index. You normally want to be using |
449 | /// metrics(char, f32) instead, unless your glyphs are pre-indexed. |
450 | /// # Arguments |
451 | /// |
452 | /// * `index` - The glyph index in the font to to generate the layout metrics for. |
453 | /// * `px` - The size to generate the layout metrics for the glyph at. Cannot be negative. The |
454 | /// units of the scale are pixels per Em unit. |
455 | /// # Returns |
456 | /// |
457 | /// * `Metrics` - Sizing and positioning metadata for the glyph. |
458 | pub fn metrics_indexed(&self, index: u16, px: f32) -> Metrics { |
459 | let glyph = &self.glyphs[index as usize]; |
460 | let scale = self.scale_factor(px); |
461 | let (metrics, _, _) = self.metrics_raw(scale, glyph, 0.0); |
462 | metrics |
463 | } |
464 | |
465 | /// Internal function to generate the metrics, offset_x, and offset_y of the glyph. |
466 | fn metrics_raw(&self, scale: f32, glyph: &Glyph, offset: f32) -> (Metrics, f32, f32) { |
467 | let bounds = glyph.bounds.scale(scale); |
468 | let mut offset_x = fract(bounds.xmin + offset); |
469 | let mut offset_y = fract(1.0 - fract(bounds.height) - fract(bounds.ymin)); |
470 | if is_negative(offset_x) { |
471 | offset_x += 1.0; |
472 | } |
473 | if is_negative(offset_y) { |
474 | offset_y += 1.0; |
475 | } |
476 | let metrics = Metrics { |
477 | xmin: as_i32(floor(bounds.xmin)), |
478 | ymin: as_i32(floor(bounds.ymin)), |
479 | width: as_i32(ceil(bounds.width + offset_x)) as usize, |
480 | height: as_i32(ceil(bounds.height + offset_y)) as usize, |
481 | advance_width: scale * glyph.advance_width, |
482 | advance_height: scale * glyph.advance_height, |
483 | bounds, |
484 | }; |
485 | (metrics, offset_x, offset_y) |
486 | } |
487 | |
488 | /// Retrieves the layout rasterized bitmap for the given raster config. If the raster config's |
489 | /// character isn't present in the font, then the layout and bitmap for the font's default |
490 | /// character's raster is returned instead. |
491 | /// # Arguments |
492 | /// |
493 | /// * `config` - The settings to render the character at. |
494 | /// # Returns |
495 | /// |
496 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
497 | /// * `Vec<u8>` - Coverage vector for the glyph. Coverage is a linear scale where 0 represents |
498 | /// 0% coverage of that pixel by the glyph and 255 represents 100% coverage. The vec starts at |
499 | /// the top left corner of the glyph. |
500 | #[inline ] |
501 | pub fn rasterize_config(&self, config: GlyphRasterConfig) -> (Metrics, Vec<u8>) { |
502 | self.rasterize_indexed(config.glyph_index, config.px) |
503 | } |
504 | |
505 | /// Retrieves the layout metrics and rasterized bitmap for the given character. If the |
506 | /// character isn't present in the font, then the layout and bitmap for the font's default |
507 | /// character is returned instead. |
508 | /// # Arguments |
509 | /// |
510 | /// * `character` - The character to rasterize. |
511 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
512 | /// are pixels per Em unit. |
513 | /// # Returns |
514 | /// |
515 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
516 | /// * `Vec<u8>` - Coverage vector for the glyph. Coverage is a linear scale where 0 represents |
517 | /// 0% coverage of that pixel by the glyph and 255 represents 100% coverage. The vec starts at |
518 | /// the top left corner of the glyph. |
519 | #[inline ] |
520 | pub fn rasterize(&self, character: char, px: f32) -> (Metrics, Vec<u8>) { |
521 | self.rasterize_indexed(self.lookup_glyph_index(character), px) |
522 | } |
523 | |
524 | /// Retrieves the layout rasterized bitmap for the given raster config. If the raster config's |
525 | /// character isn't present in the font, then the layout and bitmap for the font's default |
526 | /// character's raster is returned instead. |
527 | /// |
528 | /// This will perform the operation with the width multiplied by 3, as to simulate subpixels. |
529 | /// Taking these as RGB values will perform subpixel anti aliasing. |
530 | /// # Arguments |
531 | /// |
532 | /// * `config` - The settings to render the character at. |
533 | /// # Returns |
534 | /// |
535 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
536 | /// * `Vec<u8>` - Swizzled RGB coverage vector for the glyph. Coverage is a linear scale where 0 |
537 | /// represents 0% coverage of that subpixel by the glyph and 255 represents 100% coverage. The |
538 | /// vec starts at the top left corner of the glyph. |
539 | #[inline ] |
540 | pub fn rasterize_config_subpixel(&self, config: GlyphRasterConfig) -> (Metrics, Vec<u8>) { |
541 | self.rasterize_indexed_subpixel(config.glyph_index, config.px) |
542 | } |
543 | |
544 | /// Retrieves the layout metrics and rasterized bitmap for the given character. If the |
545 | /// character isn't present in the font, then the layout and bitmap for the font's default |
546 | /// character is returned instead. |
547 | /// |
548 | /// This will perform the operation with the width multiplied by 3, as to simulate subpixels. |
549 | /// Taking these as RGB values will perform subpixel anti aliasing. |
550 | /// # Arguments |
551 | /// |
552 | /// * `character` - The character to rasterize. |
553 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
554 | /// are pixels per Em unit. |
555 | /// # Returns |
556 | /// |
557 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
558 | /// * `Vec<u8>` - Swizzled RGB coverage vector for the glyph. Coverage is a linear scale where 0 |
559 | /// represents 0% coverage of that subpixel by the glyph and 255 represents 100% coverage. The |
560 | /// vec starts at the top left corner of the glyph. |
561 | #[inline ] |
562 | pub fn rasterize_subpixel(&self, character: char, px: f32) -> (Metrics, Vec<u8>) { |
563 | self.rasterize_indexed_subpixel(self.lookup_glyph_index(character), px) |
564 | } |
565 | |
566 | /// Retrieves the layout metrics and rasterized bitmap at the given index. You normally want to |
567 | /// be using rasterize(char, f32) instead, unless your glyphs are pre-indexed. |
568 | /// # Arguments |
569 | /// |
570 | /// * `index` - The glyph index in the font to rasterize. |
571 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
572 | /// are pixels per Em unit. |
573 | /// # Returns |
574 | /// |
575 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
576 | /// * `Vec<u8>` - Coverage vector for the glyph. Coverage is a linear scale where 0 represents |
577 | /// 0% coverage of that pixel by the glyph and 255 represents 100% coverage. The vec starts at |
578 | /// the top left corner of the glyph. |
579 | pub fn rasterize_indexed(&self, index: u16, px: f32) -> (Metrics, Vec<u8>) { |
580 | if px <= 0.0 { |
581 | return (Metrics::default(), Vec::new()); |
582 | } |
583 | let glyph = &self.glyphs[index as usize]; |
584 | let scale = self.scale_factor(px); |
585 | let (metrics, offset_x, offset_y) = self.metrics_raw(scale, glyph, 0.0); |
586 | let mut canvas = Raster::new(metrics.width, metrics.height); |
587 | canvas.draw(&glyph, scale, scale, offset_x, offset_y); |
588 | (metrics, canvas.get_bitmap()) |
589 | } |
590 | |
591 | /// Retrieves the layout metrics and rasterized bitmap at the given index. You normally want to |
592 | /// be using rasterize(char, f32) instead, unless your glyphs are pre-indexed. |
593 | /// |
594 | /// This will perform the operation with the width multiplied by 3, as to simulate subpixels. |
595 | /// Taking these as RGB values will perform subpixel anti aliasing. |
596 | /// # Arguments |
597 | /// |
598 | /// * `index` - The glyph index in the font to rasterize. |
599 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
600 | /// are pixels per Em unit. |
601 | /// # Returns |
602 | /// |
603 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
604 | /// * `Vec<u8>` - Swizzled RGB coverage vector for the glyph. Coverage is a linear scale where 0 |
605 | /// represents 0% coverage of that subpixel by the glyph and 255 represents 100% coverage. The |
606 | /// vec starts at the top left corner of the glyph. |
607 | pub fn rasterize_indexed_subpixel(&self, index: u16, px: f32) -> (Metrics, Vec<u8>) { |
608 | if px <= 0.0 { |
609 | return (Metrics::default(), Vec::new()); |
610 | } |
611 | let glyph = &self.glyphs[index as usize]; |
612 | let scale = self.scale_factor(px); |
613 | let (metrics, offset_x, offset_y) = self.metrics_raw(scale, glyph, 0.0); |
614 | let mut canvas = Raster::new(metrics.width * 3, metrics.height); |
615 | canvas.draw(&glyph, scale * 3.0, scale, offset_x, offset_y); |
616 | (metrics, canvas.get_bitmap()) |
617 | } |
618 | |
619 | /// Checks if the font has a glyph for the given character. |
620 | #[inline ] |
621 | pub fn has_glyph(&self, character: char) -> bool { |
622 | self.lookup_glyph_index(character) != 0 |
623 | } |
624 | |
625 | /// Finds the internal glyph index for the given character. If the character is not present in |
626 | /// the font then 0 is returned. |
627 | #[inline ] |
628 | pub fn lookup_glyph_index(&self, character: char) -> u16 { |
629 | // This is safe, Option<NonZeroU16> is documented to have the same layout as u16. |
630 | unsafe { mem::transmute::<Option<NonZeroU16>, u16>(self.char_to_glyph.get(&character).copied()) } |
631 | } |
632 | |
633 | /// Gets the total glyphs in the font. |
634 | pub fn glyph_count(&self) -> u16 { |
635 | self.glyphs.len() as u16 |
636 | } |
637 | } |
638 | |