| 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 crate::{HashMap, HashSet}; |
| 9 | use alloc::string::String; |
| 10 | use alloc::vec; |
| 11 | use alloc::vec::*; |
| 12 | use core::hash::{Hash, Hasher}; |
| 13 | use core::mem; |
| 14 | use core::num::NonZeroU16; |
| 15 | use core::ops::Deref; |
| 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 fonts. 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::<u32, char>(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 the font's face name if it has one. It is from `Name ID 4` (Full Name) in the name table. |
| 349 | /// See https://learn.microsoft.com/en-us/typography/opentype/spec/name#name-ids for more info. |
| 350 | pub fn name(&self) -> Option<&str> { |
| 351 | self.name.as_deref() |
| 352 | } |
| 353 | |
| 354 | /// Returns all valid unicode codepoints that have mappings to glyph geometry in the font, along |
| 355 | /// with their associated index. This does not include grapheme cluster mappings. The mapped |
| 356 | /// NonZeroU16 index can be used in the _indexed font functions. |
| 357 | pub fn chars(&self) -> &HashMap<char, NonZeroU16> { |
| 358 | &self.char_to_glyph |
| 359 | } |
| 360 | |
| 361 | /// Returns a precomputed hash for the font file. |
| 362 | pub fn file_hash(&self) -> usize { |
| 363 | self.hash |
| 364 | } |
| 365 | |
| 366 | /// New line metrics for fonts that append characters to lines horizontally, and append new |
| 367 | /// lines vertically (above or below the current line). Only populated for fonts with the |
| 368 | /// appropriate metrics, none if it's missing. |
| 369 | /// # Arguments |
| 370 | /// |
| 371 | /// * `px` - The size to scale the line metrics by. The units of the scale are pixels per Em |
| 372 | /// unit. |
| 373 | pub fn horizontal_line_metrics(&self, px: f32) -> Option<LineMetrics> { |
| 374 | let metrics = self.horizontal_line_metrics?; |
| 375 | Some(metrics.scale(self.scale_factor(px))) |
| 376 | } |
| 377 | |
| 378 | /// New line metrics for fonts that append characters to lines vertically, and append new |
| 379 | /// lines horizontally (left or right of the current line). Only populated for fonts with the |
| 380 | /// appropriate metrics, none if it's missing. |
| 381 | /// # Arguments |
| 382 | /// |
| 383 | /// * `px` - The size to scale the line metrics by. The units of the scale are pixels per Em |
| 384 | /// unit. |
| 385 | pub fn vertical_line_metrics(&self, px: f32) -> Option<LineMetrics> { |
| 386 | let metrics = self.vertical_line_metrics?; |
| 387 | Some(metrics.scale(self.scale_factor(px))) |
| 388 | } |
| 389 | |
| 390 | /// Gets the font's units per em. |
| 391 | #[inline (always)] |
| 392 | pub fn units_per_em(&self) -> f32 { |
| 393 | self.units_per_em |
| 394 | } |
| 395 | |
| 396 | /// Calculates the glyph's outline scale factor for a given px size. The units of the scale are |
| 397 | /// pixels per Em unit. |
| 398 | #[inline (always)] |
| 399 | pub fn scale_factor(&self, px: f32) -> f32 { |
| 400 | px / self.units_per_em |
| 401 | } |
| 402 | |
| 403 | /// Retrieves the horizontal scaled kerning value for two adjacent characters. |
| 404 | /// # Arguments |
| 405 | /// |
| 406 | /// * `left` - The character on the left hand side of the pairing. |
| 407 | /// * `right` - The character on the right hand side of the pairing. |
| 408 | /// * `px` - The size to scale the kerning value for. The units of the scale are pixels per Em |
| 409 | /// unit. |
| 410 | /// # Returns |
| 411 | /// |
| 412 | /// * `Option<f32>` - The horizontal scaled kerning value if one is present in the font for the |
| 413 | /// given left and right pair, None otherwise. |
| 414 | #[inline (always)] |
| 415 | pub fn horizontal_kern(&self, left: char, right: char, px: f32) -> Option<f32> { |
| 416 | self.horizontal_kern_indexed(self.lookup_glyph_index(left), self.lookup_glyph_index(right), px) |
| 417 | } |
| 418 | |
| 419 | /// Retrieves the horizontal scaled kerning value for two adjacent glyph indicies. |
| 420 | /// # Arguments |
| 421 | /// |
| 422 | /// * `left` - The glyph index on the left hand side of the pairing. |
| 423 | /// * `right` - The glyph index on the right hand side of the pairing. |
| 424 | /// * `px` - The size to scale the kerning value for. The units of the scale are pixels per Em |
| 425 | /// unit. |
| 426 | /// # Returns |
| 427 | /// |
| 428 | /// * `Option<f32>` - The horizontal scaled kerning value if one is present in the font for the |
| 429 | /// given left and right pair, None otherwise. |
| 430 | #[inline (always)] |
| 431 | pub fn horizontal_kern_indexed(&self, left: u16, right: u16, px: f32) -> Option<f32> { |
| 432 | let scale = self.scale_factor(px); |
| 433 | let map = self.horizontal_kern.as_ref()?; |
| 434 | let key = u32::from(left) << 16 | u32::from(right); |
| 435 | let value = map.get(&key)?; |
| 436 | Some((*value as f32) * scale) |
| 437 | } |
| 438 | |
| 439 | /// Retrieves the layout metrics for the given character. If the character isn't present in the |
| 440 | /// font, then the layout for the font's default character is returned instead. |
| 441 | /// # Arguments |
| 442 | /// |
| 443 | /// * `index` - The character in the font to to generate the layout metrics for. |
| 444 | /// * `px` - The size to generate the layout metrics for the character at. Cannot be negative. |
| 445 | /// The units of the scale are pixels per Em unit. |
| 446 | /// # Returns |
| 447 | /// |
| 448 | /// * `Metrics` - Sizing and positioning metadata for the glyph. |
| 449 | #[inline ] |
| 450 | pub fn metrics(&self, character: char, px: f32) -> Metrics { |
| 451 | self.metrics_indexed(self.lookup_glyph_index(character), px) |
| 452 | } |
| 453 | |
| 454 | /// Retrieves the layout metrics at the given index. You normally want to be using |
| 455 | /// metrics(char, f32) instead, unless your glyphs are pre-indexed. |
| 456 | /// # Arguments |
| 457 | /// |
| 458 | /// * `index` - The glyph index in the font to to generate the layout metrics for. |
| 459 | /// * `px` - The size to generate the layout metrics for the glyph at. Cannot be negative. The |
| 460 | /// units of the scale are pixels per Em unit. |
| 461 | /// # Returns |
| 462 | /// |
| 463 | /// * `Metrics` - Sizing and positioning metadata for the glyph. |
| 464 | pub fn metrics_indexed(&self, index: u16, px: f32) -> Metrics { |
| 465 | let glyph = &self.glyphs[index as usize]; |
| 466 | let scale = self.scale_factor(px); |
| 467 | let (metrics, _, _) = self.metrics_raw(scale, glyph, 0.0); |
| 468 | metrics |
| 469 | } |
| 470 | |
| 471 | /// Internal function to generate the metrics, offset_x, and offset_y of the glyph. |
| 472 | fn metrics_raw(&self, scale: f32, glyph: &Glyph, offset: f32) -> (Metrics, f32, f32) { |
| 473 | let bounds = glyph.bounds.scale(scale); |
| 474 | let mut offset_x = fract(bounds.xmin + offset); |
| 475 | let mut offset_y = fract(1.0 - fract(bounds.height) - fract(bounds.ymin)); |
| 476 | if is_negative(offset_x) { |
| 477 | offset_x += 1.0; |
| 478 | } |
| 479 | if is_negative(offset_y) { |
| 480 | offset_y += 1.0; |
| 481 | } |
| 482 | let metrics = Metrics { |
| 483 | xmin: as_i32(floor(bounds.xmin)), |
| 484 | ymin: as_i32(floor(bounds.ymin)), |
| 485 | width: as_i32(ceil(bounds.width + offset_x)) as usize, |
| 486 | height: as_i32(ceil(bounds.height + offset_y)) as usize, |
| 487 | advance_width: scale * glyph.advance_width, |
| 488 | advance_height: scale * glyph.advance_height, |
| 489 | bounds, |
| 490 | }; |
| 491 | (metrics, offset_x, offset_y) |
| 492 | } |
| 493 | |
| 494 | /// Retrieves the layout rasterized bitmap for the given raster config. If the raster config's |
| 495 | /// character isn't present in the font, then the layout and bitmap for the font's default |
| 496 | /// character's raster is returned instead. |
| 497 | /// # Arguments |
| 498 | /// |
| 499 | /// * `config` - The settings to render the character at. |
| 500 | /// # Returns |
| 501 | /// |
| 502 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
| 503 | /// * `Vec<u8>` - Coverage vector for the glyph. Coverage is a linear scale where 0 represents |
| 504 | /// 0% coverage of that pixel by the glyph and 255 represents 100% coverage. The vec starts at |
| 505 | /// the top left corner of the glyph. |
| 506 | #[inline ] |
| 507 | pub fn rasterize_config(&self, config: GlyphRasterConfig) -> (Metrics, Vec<u8>) { |
| 508 | self.rasterize_indexed(config.glyph_index, config.px) |
| 509 | } |
| 510 | |
| 511 | /// Retrieves the layout metrics and rasterized bitmap for the given character. If the |
| 512 | /// character isn't present in the font, then the layout and bitmap for the font's default |
| 513 | /// character is returned instead. |
| 514 | /// # Arguments |
| 515 | /// |
| 516 | /// * `character` - The character to rasterize. |
| 517 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
| 518 | /// are pixels per Em unit. |
| 519 | /// # Returns |
| 520 | /// |
| 521 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
| 522 | /// * `Vec<u8>` - Coverage vector for the glyph. Coverage is a linear scale where 0 represents |
| 523 | /// 0% coverage of that pixel by the glyph and 255 represents 100% coverage. The vec starts at |
| 524 | /// the top left corner of the glyph. |
| 525 | #[inline ] |
| 526 | pub fn rasterize(&self, character: char, px: f32) -> (Metrics, Vec<u8>) { |
| 527 | self.rasterize_indexed(self.lookup_glyph_index(character), px) |
| 528 | } |
| 529 | |
| 530 | /// Retrieves the layout rasterized bitmap for the given raster config. If the raster config's |
| 531 | /// character isn't present in the font, then the layout and bitmap for the font's default |
| 532 | /// character's raster is returned instead. |
| 533 | /// |
| 534 | /// This will perform the operation with the width multiplied by 3, as to simulate subpixels. |
| 535 | /// Taking these as RGB values will perform subpixel anti aliasing. |
| 536 | /// # Arguments |
| 537 | /// |
| 538 | /// * `config` - The settings to render the character at. |
| 539 | /// # Returns |
| 540 | /// |
| 541 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
| 542 | /// * `Vec<u8>` - Swizzled RGB coverage vector for the glyph. Coverage is a linear scale where 0 |
| 543 | /// represents 0% coverage of that subpixel by the glyph and 255 represents 100% coverage. The |
| 544 | /// vec starts at the top left corner of the glyph. |
| 545 | #[inline ] |
| 546 | pub fn rasterize_config_subpixel(&self, config: GlyphRasterConfig) -> (Metrics, Vec<u8>) { |
| 547 | self.rasterize_indexed_subpixel(config.glyph_index, config.px) |
| 548 | } |
| 549 | |
| 550 | /// Retrieves the layout metrics and rasterized bitmap for the given character. If the |
| 551 | /// character isn't present in the font, then the layout and bitmap for the font's default |
| 552 | /// character is returned instead. |
| 553 | /// |
| 554 | /// This will perform the operation with the width multiplied by 3, as to simulate subpixels. |
| 555 | /// Taking these as RGB values will perform subpixel anti aliasing. |
| 556 | /// # Arguments |
| 557 | /// |
| 558 | /// * `character` - The character to rasterize. |
| 559 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
| 560 | /// are pixels per Em unit. |
| 561 | /// # Returns |
| 562 | /// |
| 563 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
| 564 | /// * `Vec<u8>` - Swizzled RGB coverage vector for the glyph. Coverage is a linear scale where 0 |
| 565 | /// represents 0% coverage of that subpixel by the glyph and 255 represents 100% coverage. The |
| 566 | /// vec starts at the top left corner of the glyph. |
| 567 | #[inline ] |
| 568 | pub fn rasterize_subpixel(&self, character: char, px: f32) -> (Metrics, Vec<u8>) { |
| 569 | self.rasterize_indexed_subpixel(self.lookup_glyph_index(character), px) |
| 570 | } |
| 571 | |
| 572 | /// Retrieves the layout metrics and rasterized bitmap at the given index. You normally want to |
| 573 | /// be using rasterize(char, f32) instead, unless your glyphs are pre-indexed. |
| 574 | /// # Arguments |
| 575 | /// |
| 576 | /// * `index` - The glyph index in the font to rasterize. |
| 577 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
| 578 | /// are pixels per Em unit. |
| 579 | /// # Returns |
| 580 | /// |
| 581 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
| 582 | /// * `Vec<u8>` - Coverage vector for the glyph. Coverage is a linear scale where 0 represents |
| 583 | /// 0% coverage of that pixel by the glyph and 255 represents 100% coverage. The vec starts at |
| 584 | /// the top left corner of the glyph. |
| 585 | pub fn rasterize_indexed(&self, index: u16, px: f32) -> (Metrics, Vec<u8>) { |
| 586 | if px <= 0.0 { |
| 587 | return (Metrics::default(), Vec::new()); |
| 588 | } |
| 589 | let glyph = &self.glyphs[index as usize]; |
| 590 | let scale = self.scale_factor(px); |
| 591 | let (metrics, offset_x, offset_y) = self.metrics_raw(scale, glyph, 0.0); |
| 592 | let mut canvas = Raster::new(metrics.width, metrics.height); |
| 593 | canvas.draw(&glyph, scale, scale, offset_x, offset_y); |
| 594 | (metrics, canvas.get_bitmap()) |
| 595 | } |
| 596 | |
| 597 | /// Retrieves the layout metrics and rasterized bitmap at the given index. You normally want to |
| 598 | /// be using rasterize(char, f32) instead, unless your glyphs are pre-indexed. |
| 599 | /// |
| 600 | /// This will perform the operation with the width multiplied by 3, as to simulate subpixels. |
| 601 | /// Taking these as RGB values will perform subpixel anti aliasing. |
| 602 | /// # Arguments |
| 603 | /// |
| 604 | /// * `index` - The glyph index in the font to rasterize. |
| 605 | /// * `px` - The size to render the character at. Cannot be negative. The units of the scale |
| 606 | /// are pixels per Em unit. |
| 607 | /// # Returns |
| 608 | /// |
| 609 | /// * `Metrics` - Sizing and positioning metadata for the rasterized glyph. |
| 610 | /// * `Vec<u8>` - Swizzled RGB coverage vector for the glyph. Coverage is a linear scale where 0 |
| 611 | /// represents 0% coverage of that subpixel by the glyph and 255 represents 100% coverage. The |
| 612 | /// vec starts at the top left corner of the glyph. |
| 613 | pub fn rasterize_indexed_subpixel(&self, index: u16, px: f32) -> (Metrics, Vec<u8>) { |
| 614 | if px <= 0.0 { |
| 615 | return (Metrics::default(), Vec::new()); |
| 616 | } |
| 617 | let glyph = &self.glyphs[index as usize]; |
| 618 | let scale = self.scale_factor(px); |
| 619 | let (metrics, offset_x, offset_y) = self.metrics_raw(scale, glyph, 0.0); |
| 620 | let mut canvas = Raster::new(metrics.width * 3, metrics.height); |
| 621 | canvas.draw(&glyph, scale * 3.0, scale, offset_x, offset_y); |
| 622 | (metrics, canvas.get_bitmap()) |
| 623 | } |
| 624 | |
| 625 | /// Checks if the font has a glyph for the given character. |
| 626 | #[inline ] |
| 627 | pub fn has_glyph(&self, character: char) -> bool { |
| 628 | self.lookup_glyph_index(character) != 0 |
| 629 | } |
| 630 | |
| 631 | /// Finds the internal glyph index for the given character. If the character is not present in |
| 632 | /// the font then 0 is returned. |
| 633 | #[inline ] |
| 634 | pub fn lookup_glyph_index(&self, character: char) -> u16 { |
| 635 | // This is safe, Option<NonZeroU16> is documented to have the same layout as u16. |
| 636 | unsafe { mem::transmute::<Option<NonZeroU16>, u16>(self.char_to_glyph.get(&character).copied()) } |
| 637 | } |
| 638 | |
| 639 | /// Gets the total glyphs in the font. |
| 640 | pub fn glyph_count(&self) -> u16 { |
| 641 | self.glyphs.len() as u16 |
| 642 | } |
| 643 | } |
| 644 | |