diff --git a/font/src/ft/list_fonts.rs b/font/src/ft/list_fonts.rs index 3867611..0789bbd 100644 --- a/font/src/ft/list_fonts.rs +++ b/font/src/ft/list_fonts.rs @@ -584,4 +584,4 @@ mod tests { println!(""); } } - +} diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs index 6fdae4b..d69aad9 100644 --- a/font/src/ft/mod.rs +++ b/font/src/ft/mod.rs @@ -87,46 +87,9 @@ impl ::Rasterize for FreeTypeRasterizer { } fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result { - let face = self.faces - .get(&glyph_key.font_key) - .ok_or(Error::FontNotLoaded)?; - - let size = glyph_key.size.as_f32_pts() * self.dpr; - let c = glyph_key.c; - - face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?; - face.load_char(c as usize, freetype::face::TARGET_LIGHT)?; - let glyph = face.glyph(); - glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?; - - unsafe { - let ft_lib = self.library.raw(); - freetype::ffi::FT_Library_SetLcdFilter( - ft_lib, - freetype::ffi::FT_LCD_FILTER_DEFAULT - ); - } - - let bitmap = glyph.bitmap(); - let buf = bitmap.buffer(); - let pitch = bitmap.pitch() as usize; - - let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize); - for i in 0..bitmap.rows() { - let start = (i as usize) * pitch; - let stop = start + bitmap.width() as usize; - packed.extend_from_slice(&buf[start..stop]); - } - - Ok(RasterizedGlyph { - c: c, - top: glyph.bitmap_top(), - left: glyph.bitmap_left(), - width: glyph.bitmap().width() / 3, - height: glyph.bitmap().rows(), - buf: packed, - }) + self.get_rendered_glyph(glyph_key, false) } + } pub trait IntoFontconfigType { @@ -213,6 +176,92 @@ impl FreeTypeRasterizer { Err(Error::MissingFont(desc.to_owned())) } } + + fn get_rendered_glyph(&mut self, glyph_key: &GlyphKey, have_recursed: bool) + -> Result { + let faces = self.faces.clone(); + let face = faces + .get(&glyph_key.font_key) + .ok_or(Error::FontNotLoaded)?; + + let size = glyph_key.size.as_f32_pts() * self.dpr; + let c = glyph_key.c; + + face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y)?; + let index = face.get_char_index(c as usize); + + if index == 0 && have_recursed == false { + let key = self.load_face_with_glyph(c).unwrap_or(glyph_key.font_key); + let new_glyph_key = GlyphKey { + c: glyph_key.c, + font_key: key, + size: glyph_key.size + }; + + return self.get_rendered_glyph(&new_glyph_key, true); + } + + face.load_glyph(index as u32, freetype::face::TARGET_LIGHT)?; + let glyph = face.glyph(); + glyph.render_glyph(freetype::render_mode::RenderMode::Lcd)?; + + unsafe { + let ft_lib = self.library.raw(); + freetype::ffi::FT_Library_SetLcdFilter( + ft_lib, + freetype::ffi::FT_LCD_FILTER_DEFAULT + ); + } + + let bitmap = glyph.bitmap(); + let buf = bitmap.buffer(); + let pitch = bitmap.pitch() as usize; + + let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize); + for i in 0..bitmap.rows() { + let start = (i as usize) * pitch; + let stop = start + bitmap.width() as usize; + packed.extend_from_slice(&buf[start..stop]); + } + + Ok(RasterizedGlyph { + c: c, + top: glyph.bitmap_top(), + left: glyph.bitmap_left(), + width: glyph.bitmap().width() / 3, + height: glyph.bitmap().rows(), + buf: packed, + }) + } + + fn load_face_with_glyph(&mut self, glyph: char) -> Result { + let mut charset = fc::CharSet::new(); + charset.add(glyph); + let mut pattern = fc::Pattern::new(); + unsafe { + pattern.add_charset(&charset); + } + + let config = fc::Config::get_current(); + match fc::font_match(config, &mut pattern) { + Some(font) => { + if let (Some(path), Some(index)) = (font.file(0), font.index(0)) { + let face = self.library.new_face(path, index)?; + let key = FontKey::next(); + self.faces.insert(key, face); + return Ok(key) + } + 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())) + )) + } + } + } } /// Errors occurring when using the freetype rasterizer