diff --git a/Cargo.toml b/Cargo.toml index f1ffceb..9c7eca1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ pbr = "1.0" prettytable-rs = "0.10" [target.'cfg(target_family = "windows")'.dependencies] -dwrote = { version = "^0.11.3", default-features = false } +dwrote = { git = "https://github.com/warpdotdev/dwrote-rs", rev = "a71ce6c0136f7d0954a9a8b181b5b2d8ace5eb9c", default-features = false } [target.'cfg(target_family = "windows")'.dependencies.winapi] version = "0.3" diff --git a/src/loaders/directwrite.rs b/src/loaders/directwrite.rs index 36d8b86..351e29d 100644 --- a/src/loaders/directwrite.rs +++ b/src/loaders/directwrite.rs @@ -110,7 +110,9 @@ impl Font { let Ok(dwrite_font) = family.font(family_font_index) else { continue; }; - let dwrite_font_face = dwrite_font.create_font_face(); + let Ok(dwrite_font_face) = dwrite_font.create_font_face() else { + continue; + }; return Ok(Font { dwrite_font, dwrite_font_face, @@ -224,7 +226,7 @@ impl Font { #[inline] pub fn postscript_name(&self) -> Option { let dwrite_font = &self.dwrite_font; - dwrite_font.informational_string(DWriteInformationalStringId::PostscriptName) + dwrite_font.informational_string(DWriteInformationalStringId::PostscriptName).ok()? } /// Returns the full name of the font (also known as "display name" on macOS). @@ -233,13 +235,15 @@ impl Font { let dwrite_font = &self.dwrite_font; dwrite_font .informational_string(DWriteInformationalStringId::FullName) - .unwrap_or_else(|| dwrite_font.family_name()) + .ok() + .flatten() + .unwrap_or_else(|| dwrite_font.family_name().unwrap_or_default()) } /// Returns the name of the font family. #[inline] pub fn family_name(&self) -> String { - self.dwrite_font.family_name() + self.dwrite_font.family_name().unwrap_or_default() } /// Returns true if and only if the font is monospace (fixed-width). @@ -265,8 +269,10 @@ impl Font { /// use cases like "what does character X look like on its own". pub fn glyph_for_char(&self, character: char) -> Option { let chars = [character as u32]; - self.dwrite_font_face - .get_glyph_indices(&chars) + let indices = self.dwrite_font_face + .glyph_indices(&chars) + .ok()?; + indices .into_iter() .next() .and_then(|g| { @@ -304,7 +310,7 @@ impl Font { S: OutlineSink, { let outline_sink = OutlineCanonicalizer::new(); - self.dwrite_font_face.get_glyph_run_outline( + self.dwrite_font_face.glyph_run_outline( self.metrics().units_per_em as f32, &[glyph_id as u16], None, @@ -312,7 +318,7 @@ impl Font { false, false, Box::new(outline_sink.clone()), - ); + ).map_err(|_| GlyphLoadingError::NoSuchGlyph)?; outline_sink .0 .lock() @@ -327,7 +333,8 @@ impl Font { pub fn typographic_bounds(&self, glyph_id: u32) -> Result { let metrics = self .dwrite_font_face - .get_design_glyph_metrics(&[glyph_id as u16], false); + .design_glyph_metrics(&[glyph_id as u16], false) + .map_err(|_| GlyphLoadingError::NoSuchGlyph)?; let metrics = &metrics[0]; let advance_width = metrics.advanceWidth as i32; @@ -354,7 +361,8 @@ impl Font { pub fn advance(&self, glyph_id: u32) -> Result { let metrics = self .dwrite_font_face - .get_design_glyph_metrics(&[glyph_id as u16], false); + .design_glyph_metrics(&[glyph_id as u16], false) + .map_err(|_| GlyphLoadingError::NoSuchGlyph)?; let metrics = &metrics[0]; Ok(Vector2F::new(metrics.advanceWidth as f32, 0.0)) } @@ -363,7 +371,8 @@ impl Font { pub fn origin(&self, glyph: u32) -> Result { let metrics = self .dwrite_font_face - .get_design_glyph_metrics(&[glyph as u16], false); + .design_glyph_metrics(&[glyph as u16], false) + .map_err(|_| GlyphLoadingError::NoSuchGlyph)?; Ok(Vector2I::new( metrics[0].leftSideBearing, metrics[0].verticalOriginY + metrics[0].bottomSideBearing, @@ -400,7 +409,9 @@ impl Font { DWriteFontMetrics::Metrics0(metrics) => { let bounding_box = match self .dwrite_font_face - .get_font_table(OPENTYPE_TABLE_TAG_HEAD.swap_bytes()) + .font_table(OPENTYPE_TABLE_TAG_HEAD.swap_bytes()) + .ok() + .flatten() { Some(head) => { let mut reader = &head[36..]; @@ -446,10 +457,13 @@ impl Font { pub fn copy_font_data(&self) -> Option>> { let mut font_data = self.cached_data.lock().unwrap(); if font_data.is_none() { - let files = self.dwrite_font_face.get_files(); - // FIXME(pcwalton): Is this right? When can a font have multiple files? - if let Some(file) = files.get(0) { - *font_data = Some(Arc::new(file.get_font_file_bytes())) + if let Ok(files) = self.dwrite_font_face.files() { + // FIXME(pcwalton): Is this right? When can a font have multiple files? + if let Some(file) = files.get(0) { + if let Ok(bytes) = file.font_file_bytes() { + *font_data = Some(Arc::new(bytes)) + } + } } } (*font_data).clone() @@ -668,14 +682,16 @@ impl Font { 0, text_utf16_len, &collection, - Some(&self.dwrite_font.family_name()), + self.dwrite_font.family_name().ok().as_deref(), self.dwrite_font.weight(), self.dwrite_font.style(), self.dwrite_font.stretch(), ); let valid_len = convert_len_utf16_to_utf8(text, fallback_result.mapped_length); let fonts = if let Some(dwrite_font) = fallback_result.mapped_font { - let dwrite_font_face = dwrite_font.create_font_face(); + let Ok(dwrite_font_face) = dwrite_font.create_font_face() else { + return FallbackResult { fonts: vec![], valid_len }; + }; let font = Font { dwrite_font, dwrite_font_face, @@ -699,7 +715,9 @@ impl Font { /// [OpenType specification]: https://docs.microsoft.com/en-us/typography/opentype/spec/ pub fn load_font_table(&self, table_tag: u32) -> Option> { self.dwrite_font_face - .get_font_table(table_tag.swap_bytes()) + .font_table(table_tag.swap_bytes()) + .ok() + .flatten() .map(|v| v.into()) } } diff --git a/src/sources/directwrite.rs b/src/sources/directwrite.rs index b295279..127c844 100644 --- a/src/sources/directwrite.rs +++ b/src/sources/directwrite.rs @@ -12,7 +12,9 @@ use dwrote::Font as DWriteFont; use dwrote::FontCollection as DWriteFontCollection; +use dwrote::HRESULT; use std::any::Any; +use winapi::shared::winerror; use crate::error::SelectionError; use crate::family_handle::FamilyHandle; @@ -44,7 +46,10 @@ impl DirectWriteSource { let Ok(dwrite_font) = dwrite_family.font(font_index) else { continue; }; - handles.push(self.create_handle_from_dwrite_font(dwrite_font)) + let Ok(handle) = self.create_handle_from_dwrite_font(dwrite_font) else { + continue; + }; + handles.push(handle) } } @@ -73,7 +78,10 @@ impl DirectWriteSource { let Ok(dwrite_font) = dwrite_family.font(font_index) else { continue; }; - family.push(self.create_handle_from_dwrite_font(dwrite_font)); + let Ok(handle) = self.create_handle_from_dwrite_font(dwrite_font) else { + continue; + }; + family.push(handle); } Ok(family) } @@ -100,13 +108,18 @@ impl DirectWriteSource { ::select_best_match(self, family_names, properties) } - fn create_handle_from_dwrite_font(&self, dwrite_font: DWriteFont) -> Handle { - let dwrite_font_face = dwrite_font.create_font_face(); - let dwrite_font_files = dwrite_font_face.get_files(); - Handle::Path { - path: dwrite_font_files[0].get_font_file_path().unwrap(), - font_index: dwrite_font_face.get_index(), - } + fn create_handle_from_dwrite_font(&self, dwrite_font: DWriteFont) -> Result { + let font_face = dwrite_font.create_font_face()?; + let path = font_face + .files()? + .into_iter() + .next() + .ok_or(winerror::E_FAIL)? + .font_file_path()?; + Ok(Handle::Path { + path, + font_index: font_face.get_index(), + }) } }