Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom glyph indices in GlyphKey #35

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 49 additions & 21 deletions src/darwin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ pub mod byte_order;
use byte_order::kCGBitmapByteOrder32Host;

use super::{
BitmapBuffer, Error, FontDesc, FontKey, GlyphKey, Metrics, RasterizedGlyph, Size, Slant, Style,
Weight,
BitmapBuffer, Error, FontDesc, FontKey, GlyphId, GlyphKey, Metrics, RasterizedGlyph, Size,
Slant, Style, Weight,
};

/// According to the documentation, the index of 0 must be a missing glyph character:
Expand Down Expand Up @@ -64,7 +64,7 @@ impl Descriptor {
font_name: desc.font_name(),
style_name: desc.style_name(),
display_name: desc.display_name(),
font_path: desc.font_path().unwrap_or_else(PathBuf::new),
font_path: desc.font_path().unwrap_or_default(),
ct_descriptor: desc,
}
}
Expand All @@ -89,19 +89,32 @@ impl Descriptor {
// Investigate if we can actually use the .-prefixed
// fallbacks somehow.
if let Ok(apple_symbols) = new_from_name("Apple Symbols", size) {
fallbacks.push(Font {
let path = apple_symbols.copy_descriptor().font_path().unwrap_or_default();
let mut font = Font {
cg_font: apple_symbols.copy_to_CGFont(),
ct_font: apple_symbols,
fallbacks: Vec::new(),
})
placeholder_glyph_index: 0,
path,
};
font.placeholder_glyph_index = font.glyph_index(' ');
fallbacks.push(font);
};

fallbacks
} else {
Vec::new()
};

Font { ct_font, cg_font, fallbacks }
let mut font = Font {
ct_font,
cg_font,
fallbacks,
placeholder_glyph_index: 0,
path: self.font_path.clone(),
};
font.placeholder_glyph_index = font.glyph_index(' ');
font
}
}

Expand Down Expand Up @@ -153,13 +166,27 @@ impl crate::Rasterize for Rasterizer {
// Find a font where the given character is present.
let (font, glyph_index) = iter::once(font)
.chain(font.fallbacks.iter())
.find_map(|font| match font.glyph_index(glyph.character) {
MISSING_GLYPH_INDEX => None,
glyph_index => Some((font, glyph_index)),
.find_map(|font| {
if let Some(c) = glyph.id.as_char() {
match font.glyph_index(c) {
MISSING_GLYPH_INDEX => None,
glyph_index => Some((font, glyph_index)),
}
} else {
let index = glyph.id.value();
if index == 0 {
match font.placeholder_glyph_index {
MISSING_GLYPH_INDEX => None,
glyph_index => Some((font, glyph_index)),
}
} else {
Some((font, index))
}
}
})
.unwrap_or((font, MISSING_GLYPH_INDEX));

let glyph = font.get_glyph(glyph.character, glyph_index, self.use_thin_strokes);
let glyph = font.get_glyph(glyph.id, glyph_index, self.use_thin_strokes);

if glyph_index == MISSING_GLYPH_INDEX {
Err(Error::MissingGlyph(glyph))
Expand All @@ -171,6 +198,10 @@ impl crate::Rasterize for Rasterizer {
fn update_dpr(&mut self, device_pixel_ratio: f32) {
self.device_pixel_ratio = device_pixel_ratio;
}

fn font_path(&self, key: FontKey) -> Result<&std::path::Path, Error> {
self.fonts.get(&key).ok_or(Error::UnknownFontKey).map(|font| font.path.as_path())
}
}

impl Rasterizer {
Expand Down Expand Up @@ -315,6 +346,8 @@ pub struct Font {
ct_font: CTFont,
cg_font: CGFont,
fallbacks: Vec<Font>,
placeholder_glyph_index: u32,
path: PathBuf,
}

unsafe impl Send for Font {}
Expand Down Expand Up @@ -375,7 +408,7 @@ impl Font {

pub fn get_glyph(
&self,
character: char,
id: GlyphId,
glyph_index: u32,
use_thin_strokes: bool,
) -> RasterizedGlyph {
Expand All @@ -391,14 +424,7 @@ impl Font {
let rasterized_height = (rasterized_descent + rasterized_ascent) as u32;

if rasterized_width == 0 || rasterized_height == 0 {
return RasterizedGlyph {
character: ' ',
width: 0,
height: 0,
top: 0,
left: 0,
buffer: BitmapBuffer::Rgb(Vec::new()),
};
return RasterizedGlyph::default();
}

let mut cg_context = CGContext::create_bitmap_context(
Expand Down Expand Up @@ -457,7 +483,7 @@ impl Font {
};

RasterizedGlyph {
character,
id,
left: rasterized_left,
top: (bounds.size.height + bounds.origin.y).ceil() as i32,
width: rasterized_width as i32,
Expand Down Expand Up @@ -498,6 +524,8 @@ impl Font {

#[cfg(test)]
mod tests {
use crate::GlyphId;

use super::BitmapBuffer;

#[test]
Expand All @@ -520,7 +548,7 @@ mod tests {
// Get a glyph.
for character in &['a', 'b', 'c', 'd'] {
let glyph_index = font.glyph_index(*character);
let glyph = font.get_glyph(*character, glyph_index, false);
let glyph = font.get_glyph(GlyphId::char(*character), glyph_index, false);

let buffer = match &glyph.buffer {
BitmapBuffer::Rgb(buffer) | BitmapBuffer::Rgba(buffer) => buffer,
Expand Down
52 changes: 39 additions & 13 deletions src/directwrite/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::{Path, PathBuf};

use dwrote::{
FontCollection, FontFace, FontFallback, FontStretch, FontStyle, FontWeight, GlyphOffset,
Expand All @@ -15,8 +16,8 @@ use winapi::um::dwrite;
use winapi::um::winnls::GetUserDefaultLocaleName;

use super::{
BitmapBuffer, Error, FontDesc, FontKey, GlyphKey, Metrics, RasterizedGlyph, Size, Slant, Style,
Weight,
BitmapBuffer, Error, FontDesc, FontKey, GlyphId, GlyphKey, Metrics, RasterizedGlyph, Size,
Slant, Style, Weight,
};

/// DirectWrite uses 0 for missing glyph symbols.
Expand All @@ -30,6 +31,8 @@ struct Font {
weight: FontWeight,
style: FontStyle,
stretch: FontStretch,
placeholder_glyph_index: u16,
path: PathBuf,
}

pub struct DirectWriteRasterizer {
Expand All @@ -45,7 +48,7 @@ impl DirectWriteRasterizer {
&self,
face: &FontFace,
size: Size,
character: char,
id: GlyphId,
glyph_index: u16,
) -> Result<RasterizedGlyph, Error> {
let em_size = em_size(size);
Expand Down Expand Up @@ -85,7 +88,7 @@ impl DirectWriteRasterizer {
);

Ok(RasterizedGlyph {
character,
id,
width: (bounds.right - bounds.left) as i32,
height: (bounds.bottom - bounds.top) as i32,
top: -bounds.top,
Expand Down Expand Up @@ -232,17 +235,28 @@ impl crate::Rasterize for DirectWriteRasterizer {

let loaded_fallback_font;
let mut font = loaded_font;
let mut glyph_index = self.get_glyph_index(&loaded_font.face, glyph.character);
if glyph_index == MISSING_GLYPH_INDEX {
if let Some(fallback_font) = self.get_fallback_font(&loaded_font, glyph.character) {
loaded_fallback_font = Font::from(fallback_font);
glyph_index = self.get_glyph_index(&loaded_fallback_font.face, glyph.character);
font = &loaded_fallback_font;

let glyph_index = if let Some(character) = glyph.id.as_char() {
let mut glyph_index = self.get_glyph_index(&loaded_font.face, character);
if glyph_index == MISSING_GLYPH_INDEX {
if let Some(fallback_font) = self.get_fallback_font(&loaded_font, character) {
loaded_fallback_font = Font::from(fallback_font);
glyph_index = self.get_glyph_index(&loaded_fallback_font.face, character);
font = &loaded_fallback_font;
}
}
}
glyph_index
} else {
let index = glyph.id.value();
if index == 0 {
loaded_font.placeholder_glyph_index
} else {
index as u16
}
};

let rasterized_glyph =
self.rasterize_glyph(&font.face, glyph.size, glyph.character, glyph_index)?;
self.rasterize_glyph(&font.face, glyph.size, glyph.id, glyph_index)?;

if glyph_index == MISSING_GLYPH_INDEX {
Err(Error::MissingGlyph(rasterized_glyph))
Expand All @@ -254,6 +268,10 @@ impl crate::Rasterize for DirectWriteRasterizer {
fn update_dpr(&mut self, device_pixel_ratio: f32) {
self.device_pixel_ratio = device_pixel_ratio;
}

fn font_path(&self, key: FontKey) -> Result<&Path, Error> {
Ok(&self.get_loaded_font(key)?.path)
}
}

fn em_size(size: Size) -> f32 {
Expand All @@ -262,12 +280,20 @@ fn em_size(size: Size) -> f32 {

impl From<dwrote::Font> for Font {
fn from(font: dwrote::Font) -> Font {
let face = font.create_font_face();
let placeholder_glyph_index =
face.get_glyph_indices(&[' ' as u32]).first().copied().unwrap_or(MISSING_GLYPH_INDEX);
let files = face.get_files();
let path = files.first().unwrap().get_font_file_path().unwrap();

Font {
face: font.create_font_face(),
face,
family_name: font.family_name(),
weight: font.weight(),
style: font.style(),
stretch: font.stretch(),
placeholder_glyph_index,
path,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ft/fc/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ macro_rules! string_accessor {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct PatternHash(pub u32);

#[derive(Hash, Eq, PartialEq, Debug)]
#[derive(Clone, Hash, Eq, PartialEq, Debug)]
pub struct FtFaceLocation {
pub path: PathBuf,
pub index: isize,
Expand Down
Loading