First pass of font fallback rendering

This commit is contained in:
Harlan Lieberman-Berg 2017-02-25 22:54:07 -05:00 committed by Joe Wilm
parent 4b4a187fbd
commit 3ad6869967
2 changed files with 89 additions and 40 deletions

View File

@ -584,4 +584,4 @@ mod tests {
println!("");
}
}
}

View File

@ -87,46 +87,9 @@ impl ::Rasterize for FreeTypeRasterizer {
}
fn get_glyph(&mut self, glyph_key: &GlyphKey) -> Result<RasterizedGlyph, Error> {
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<RasterizedGlyph, Error> {
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<FontKey, Error> {
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