From 2c0d0d57b100ea08824839a2d52beb2b3f1448fc Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 17 Jun 2024 10:53:04 +0200 Subject: [PATCH] fonts: Fix loading SFNT tables on Windows (#32499) DirectWrite APIs expect the bytes of table tags to be reversed when reading them. Servo was doing this when loading font tables, but not all of them. This led to shaping being broken on Windows. This fixes that issue in a more comprehensive way and adds a comment to avoid this failing in the future. --- components/gfx/platform/windows/font.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/components/gfx/platform/windows/font.rs b/components/gfx/platform/windows/font.rs index 5ec0a4c658a..4aeb04fc29f 100644 --- a/components/gfx/platform/windows/font.rs +++ b/components/gfx/platform/windows/font.rs @@ -27,6 +27,7 @@ use crate::font::{ }; use crate::font_cache_thread::FontIdentifier; use crate::font_template::FontTemplateDescriptor; +use crate::ot_tag; use crate::text::glyph::GlyphId; // 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch @@ -61,16 +62,6 @@ impl FontTableMethods for FontTable { } } -#[macro_export] -/// Packs the components of a font tag name into 32 bytes, while respecting the -/// necessary Rust 4-byte alignment for pointers. This is similar to -/// [`crate::ot_tag`], but the bytes are reversed. -macro_rules! font_tag { - ($t1:expr, $t2:expr, $t3:expr, $t4:expr) => { - (($t4 as u32) << 24) | (($t3 as u32) << 16) | (($t2 as u32) << 8) | ($t1 as u32) - }; -} - #[derive(Debug)] pub struct PlatformFont { face: Nondebug, @@ -142,7 +133,12 @@ impl PlatformFontMethods for PlatformFont { // // Instead, we do the parsing work using the truetype crate for raw fonts. // We're just extracting basic info, so this is sufficient for now. - let windows_metrics_bytes = self.face.get_font_table(font_tag!('O', 'S', '/', '2')); + // + // The `dwrote` APIs take SFNT table tags in a reversed byte order, which + // is why `u32::swap_bytes()` is called here. + let windows_metrics_bytes = self + .face + .get_font_table(u32::swap_bytes(ot_tag!('O', 'S', '/', '2'))); if windows_metrics_bytes.is_none() { warn!("Could not find OS/2 table in font."); return FontTemplateDescriptor::default(); @@ -269,8 +265,11 @@ impl PlatformFontMethods for PlatformFont { } fn table_for_tag(&self, tag: FontTableTag) -> Option { + // dwrote (and presumably the Windows APIs) accept a reversed version of the table + // tag bytes, which means that `u32::swap_bytes` must be called here in order to + // use a byte order compatible with the rest of Servo. self.face - .get_font_table(tag) + .get_font_table(u32::swap_bytes(tag)) .map(|bytes| FontTable { data: bytes }) }