diff options
Diffstat (limited to 'font/src/ft/mod.rs')
-rw-r--r-- | font/src/ft/mod.rs | 175 |
1 files changed, 81 insertions, 94 deletions
diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs index 6bcda2a1..bc6d6d89 100644 --- a/font/src/ft/mod.rs +++ b/font/src/ft/mod.rs @@ -13,19 +13,18 @@ // limitations under the License. // //! Rasterization powered by FreeType and FontConfig -use std::collections::HashMap; use std::cmp::min; -use std::path::PathBuf; +use std::collections::HashMap; use std::fmt; +use std::path::PathBuf; use freetype::tt_os2::TrueTypeOS2Table; use freetype::{self, Library}; use libc::c_uint; - pub mod fc; -use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style}; +use super::{FontDesc, FontKey, GlyphKey, Metrics, RasterizedGlyph, Size, Slant, Style, Weight}; struct FixedSize { pixelsize: f64, @@ -37,7 +36,7 @@ struct Face { load_flags: freetype::face::LoadFlag, render_mode: freetype::RenderMode, lcd_filter: c_uint, - non_scalable: Option<FixedSize> + non_scalable: Option<FixedSize>, } impl fmt::Debug for Face { @@ -46,14 +45,17 @@ impl fmt::Debug for Face { .field("ft_face", &self.ft_face) .field("key", &self.key) .field("load_flags", &self.load_flags) - .field("render_mode", &match self.render_mode { - freetype::RenderMode::Normal => "Normal", - freetype::RenderMode::Light => "Light", - freetype::RenderMode::Mono => "Mono", - freetype::RenderMode::Lcd => "Lcd", - freetype::RenderMode::LcdV => "LcdV", - freetype::RenderMode::Max => "Max", - }) + .field( + "render_mode", + &match self.render_mode { + freetype::RenderMode::Normal => "Normal", + freetype::RenderMode::Light => "Light", + freetype::RenderMode::Mono => "Mono", + freetype::RenderMode::Lcd => "Lcd", + freetype::RenderMode::LcdV => "LcdV", + freetype::RenderMode::Max => "Max", + }, + ) .field("lcd_filter", &self.lcd_filter) .finish() } @@ -87,9 +89,7 @@ impl ::Rasterize for FreeTypeRasterizer { } fn metrics(&self, key: FontKey, _size: Size) -> Result<Metrics, Error> { - let face = self.faces - .get(&key) - .ok_or(Error::FontNotLoaded)?; + let face = self.faces.get(&key).ok_or(Error::FontNotLoaded)?; let full = self.full_metrics(key)?; let height = (full.size_metrics.height / 64) as f64; @@ -108,20 +108,19 @@ impl ::Rasterize for FreeTypeRasterizer { // Get strikeout position and thickness in device pixels let (strikeout_position, strikeout_thickness) = - match TrueTypeOS2Table::from_face(&mut face.ft_face.clone()) - { - Some(os2) => { - let strikeout_position = f32::from(os2.y_strikeout_position()) * x_scale / 64.; - let strikeout_thickness = f32::from(os2.y_strikeout_size()) * x_scale / 64.; - (strikeout_position, strikeout_thickness) - }, - _ => { - // Fallback if font doesn't provide info about strikeout - trace!("Using fallback strikeout metrics"); - let strikeout_position = height as f32 / 2. + descent; - (strikeout_position, underline_thickness) - }, - }; + match TrueTypeOS2Table::from_face(&mut face.ft_face.clone()) { + Some(os2) => { + let strikeout_position = f32::from(os2.y_strikeout_position()) * x_scale / 64.; + let strikeout_thickness = f32::from(os2.y_strikeout_size()) * x_scale / 64.; + (strikeout_position, strikeout_thickness) + }, + _ => { + // Fallback if font doesn't provide info about strikeout + trace!("Using fallback strikeout metrics"); + let strikeout_position = height as f32 / 2. + descent; + (strikeout_position, underline_thickness) + }, + }; Ok(Metrics { average_advance: full.cell_width, @@ -154,6 +153,7 @@ pub trait IntoFontconfigType { impl IntoFontconfigType for Slant { type FcType = fc::Slant; + fn into_fontconfig_type(&self) -> Self::FcType { match *self { Slant::Normal => fc::Slant::Roman, @@ -176,7 +176,7 @@ impl IntoFontconfigType for Weight { struct FullMetrics { size_metrics: freetype::ffi::FT_Size_Metrics, - cell_width: f64 + cell_width: f64, } impl FreeTypeRasterizer { @@ -189,31 +189,25 @@ impl FreeTypeRasterizer { Style::Description { slant, weight } => { // Match nearest font self.get_matching_face(&desc, slant, weight, size) - } + }, Style::Specific(ref style) => { // If a name was specified, try and load specifically that font. self.get_specific_face(&desc, &style, size) - } + }, } } fn full_metrics(&self, key: FontKey) -> Result<FullMetrics, Error> { - let face = self.faces - .get(&key) - .ok_or(Error::FontNotLoaded)?; + let face = self.faces.get(&key).ok_or(Error::FontNotLoaded)?; - let size_metrics = face.ft_face.size_metrics() - .ok_or(Error::MissingSizeMetrics)?; + let size_metrics = face.ft_face.size_metrics().ok_or(Error::MissingSizeMetrics)?; let width = match face.ft_face.load_char('0' as usize, face.load_flags) { - Ok(_) => face.ft_face.glyph().metrics().horiAdvance / 64, - Err(_) => size_metrics.max_advance / 64 + Ok(_) => face.ft_face.glyph().metrics().horiAdvance / 64, + Err(_) => size_metrics.max_advance / 64, } as f64; - Ok(FullMetrics { - size_metrics, - cell_width: width - }) + Ok(FullMetrics { size_metrics, cell_width: width }) } fn get_matching_face( @@ -232,12 +226,9 @@ impl FreeTypeRasterizer { let font = fc::font_match(fc::Config::get_current(), &mut pattern) .ok_or_else(|| Error::MissingFont(desc.to_owned()))?; - self.face_from_pattern(&font) - .and_then(|pattern| { - pattern - .map(Ok) - .unwrap_or_else(|| Err(Error::MissingFont(desc.to_owned()))) - }) + self.face_from_pattern(&font).and_then(|pattern| { + pattern.map(Ok).unwrap_or_else(|| Err(Error::MissingFont(desc.to_owned()))) + }) } fn get_specific_face( @@ -253,12 +244,9 @@ impl FreeTypeRasterizer { let font = fc::font_match(fc::Config::get_current(), &mut pattern) .ok_or_else(|| Error::MissingFont(desc.to_owned()))?; - self.face_from_pattern(&font) - .and_then(|pattern| { - pattern - .map(Ok) - .unwrap_or_else(|| Err(Error::MissingFont(desc.to_owned()))) - }) + self.face_from_pattern(&font).and_then(|pattern| { + pattern.map(Ok).unwrap_or_else(|| Err(Error::MissingFont(desc.to_owned()))) + }) } fn face_from_pattern(&mut self, pattern: &fc::Pattern) -> Result<Option<FontKey>, Error> { @@ -277,9 +265,7 @@ impl FreeTypeRasterizer { let mut pixelsize = pattern.pixelsize(); debug!("pixelsizes: {:?}", pixelsize); - Some(FixedSize { - pixelsize: pixelsize.next().expect("has 1+ pixelsize"), - }) + Some(FixedSize { pixelsize: pixelsize.next().expect("has 1+ pixelsize") }) }; let face = Face { @@ -303,7 +289,11 @@ impl FreeTypeRasterizer { } } - fn face_for_glyph(&mut self, glyph_key: GlyphKey, have_recursed: bool) -> Result<FontKey, Error> { + fn face_for_glyph( + &mut self, + glyph_key: GlyphKey, + have_recursed: bool, + ) -> Result<FontKey, Error> { let c = glyph_key.c; let use_initial_face = if let Some(face) = self.faces.get(&glyph_key.font_key) { @@ -322,8 +312,7 @@ impl FreeTypeRasterizer { } } - fn get_rendered_glyph(&mut self, glyph_key: GlyphKey) - -> Result<RasterizedGlyph, Error> { + fn get_rendered_glyph(&mut self, glyph_key: GlyphKey) -> Result<RasterizedGlyph, Error> { // Render a custom symbol for the underline and beam cursor match glyph_key.c { super::UNDERLINE_CURSOR_CHAR => { @@ -370,9 +359,10 @@ impl FreeTypeRasterizer { let face = &self.faces[&font_key]; let index = face.ft_face.get_char_index(glyph_key.c as usize); - let size = face.non_scalable.as_ref() - .map(|v| v.pixelsize as f32) - .unwrap_or_else(|| glyph_key.size.as_f32_pts() * self.device_pixel_ratio * 96. / 72.); + let size = + face.non_scalable.as_ref().map(|v| v.pixelsize as f32).unwrap_or_else(|| { + glyph_key.size.as_f32_pts() * self.device_pixel_ratio * 96. / 72. + }); face.ft_face.set_char_size(to_freetype_26_6(size), 0, 0, 0)?; @@ -405,7 +395,7 @@ impl FreeTypeRasterizer { use freetype::face::LoadFlag; match (antialias, hinting, rgba) { (false, fc::HintStyle::None, _) => LoadFlag::NO_HINTING | LoadFlag::MONOCHROME, - (false, _, _) => LoadFlag::TARGET_MONO | LoadFlag::MONOCHROME, + (false, ..) => LoadFlag::TARGET_MONO | LoadFlag::MONOCHROME, (true, fc::HintStyle::None, _) => LoadFlag::NO_HINTING | LoadFlag::TARGET_NORMAL, // hintslight does *not* use LCD hinting even when a subpixel mode // is selected. @@ -459,7 +449,9 @@ impl FreeTypeRasterizer { /// Given a FreeType `Bitmap`, returns packed buffer with 1 byte per LCD channel. /// /// The i32 value in the return type is the number of pixels per row. - fn normalize_buffer(bitmap: &freetype::bitmap::Bitmap) -> freetype::FtResult<(i32, i32, Vec<u8>)> { + fn normalize_buffer( + bitmap: &freetype::bitmap::Bitmap, + ) -> freetype::FtResult<(i32, i32, Vec<u8>)> { use freetype::bitmap::PixelMode; let buf = bitmap.buffer(); @@ -475,7 +467,7 @@ impl FreeTypeRasterizer { Ok((bitmap.rows(), bitmap.width() / 3, packed)) }, PixelMode::LcdV => { - for i in 0..bitmap.rows()/3 { + for i in 0..bitmap.rows() / 3 { for j in 0..bitmap.width() { for k in 0..3 { let offset = ((i as usize) * 3 + k) * pitch + (j as usize); @@ -529,14 +521,11 @@ impl FreeTypeRasterizer { } Ok((bitmap.rows(), bitmap.width(), packed)) }, - mode => panic!("unhandled pixel mode: {:?}", mode) + mode => panic!("unhandled pixel mode: {:?}", mode), } } - fn load_face_with_glyph( - &mut self, - glyph: char, - ) -> Result<FontKey, Error> { + fn load_face_with_glyph(&mut self, glyph: char) -> Result<FontKey, Error> { let mut charset = fc::CharSet::new(); charset.add(glyph); let mut pattern = fc::Pattern::new(); @@ -560,19 +549,19 @@ impl FreeTypeRasterizer { // and index above. let key = self.face_from_pattern(&pattern)?.unwrap(); Ok(key) - } + }, } - } - else { - Err(Error::MissingFont( - FontDesc::new("fallback-without-path", Style::Specific(glyph.to_string())))) + } else { + Err(Error::MissingFont(FontDesc::new( + "fallback-without-path", + Style::Specific(glyph.to_string()), + ))) } }, - None => { - Err(Error::MissingFont( - FontDesc::new("no-fallback-for", Style::Specific(glyph.to_string())) - )) - } + None => Err(Error::MissingFont(FontDesc::new( + "no-fallback-for", + Style::Specific(glyph.to_string()), + ))), } } } @@ -614,19 +603,17 @@ impl ::std::error::Error for Error { impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { - Error::FreeType(ref err) => { - err.fmt(f) - }, - Error::MissingFont(ref desc) => { - write!(f, "Couldn't find a font with {}\ - \n\tPlease check the font config in your alacritty.yml.", desc) - }, - Error::FontNotLoaded => { - f.write_str("Tried to use a font that hasn't been loaded") - }, + Error::FreeType(ref err) => err.fmt(f), + Error::MissingFont(ref desc) => write!( + f, + "Couldn't find a font with {}\n\tPlease check the font config in your \ + alacritty.yml.", + desc + ), + Error::FontNotLoaded => f.write_str("Tried to use a font that hasn't been loaded"), Error::MissingSizeMetrics => { f.write_str("Tried to get size metrics from a face without a size") - } + }, } } } |