From 4fd152a38416f3f5945fa2ec684ed3c477803f57 Mon Sep 17 00:00:00 2001 From: Andy Carlson <2yinyang2@gmail.com> Date: Tue, 23 Dec 2025 11:09:23 -0800 Subject: [PATCH 1/3] bump dwrote version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f1ffceb..1c43bb1 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 = "0c307e826ac1d51af90bafbdfd81fc0675116c6f", default-features = false } [target.'cfg(target_family = "windows")'.dependencies.winapi] version = "0.3" From 2094718c7d5c0f5d929befdbf0f52a9d08ac0b12 Mon Sep 17 00:00:00 2001 From: Andy Carlson <2yinyang2@gmail.com> Date: Thu, 12 Feb 2026 20:55:40 +0100 Subject: [PATCH 2/3] utilize fallible methods --- Cargo.toml | 2 +- src/loaders/directwrite.rs | 56 +++++++++++++++++++++++++------------- src/sources/directwrite.rs | 24 ++++++++++++---- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c43bb1..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 = { git = "https://github.com/warpdotdev/dwrote-rs", rev = "0c307e826ac1d51af90bafbdfd81fc0675116c6f", 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..621571c 100644 --- a/src/sources/directwrite.rs +++ b/src/sources/directwrite.rs @@ -13,6 +13,7 @@ use dwrote::Font as DWriteFont; use dwrote::FontCollection as DWriteFontCollection; use std::any::Any; +use std::sync::Arc; use crate::error::SelectionError; use crate::family_handle::FamilyHandle; @@ -101,12 +102,23 @@ impl DirectWriteSource { } 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(), - } + if let Ok(font_face) = dwrite_font.create_font_face() { + if let Some(path) = font_face + .files() + .ok() + .and_then(|files| files.into_iter().next()) + .and_then(|file| file.font_file_path().ok()) + { + return Handle::Path { + path, + font_index: font_face.get_index(), + }; + }; + }; + return Handle::Memory { + bytes: Arc::new(vec![]), + font_index: 0, + }; } } From 995cf4216eb60576461995a9a51068ecb5d8710b Mon Sep 17 00:00:00 2001 From: Andy Carlson <2yinyang2@gmail.com> Date: Wed, 18 Feb 2026 16:50:46 +0100 Subject: [PATCH 3/3] fix create_handle_from_dwrite_font return type --- src/sources/directwrite.rs | 43 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/sources/directwrite.rs b/src/sources/directwrite.rs index 621571c..127c844 100644 --- a/src/sources/directwrite.rs +++ b/src/sources/directwrite.rs @@ -12,8 +12,9 @@ use dwrote::Font as DWriteFont; use dwrote::FontCollection as DWriteFontCollection; +use dwrote::HRESULT; use std::any::Any; -use std::sync::Arc; +use winapi::shared::winerror; use crate::error::SelectionError; use crate::family_handle::FamilyHandle; @@ -45,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) } } @@ -74,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) } @@ -101,24 +108,18 @@ impl DirectWriteSource { ::select_best_match(self, family_names, properties) } - fn create_handle_from_dwrite_font(&self, dwrite_font: DWriteFont) -> Handle { - if let Ok(font_face) = dwrite_font.create_font_face() { - if let Some(path) = font_face - .files() - .ok() - .and_then(|files| files.into_iter().next()) - .and_then(|file| file.font_file_path().ok()) - { - return Handle::Path { - path, - font_index: font_face.get_index(), - }; - }; - }; - return Handle::Memory { - bytes: Arc::new(vec![]), - font_index: 0, - }; + 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(), + }) } }