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.
This commit is contained in:
Martin Robinson 2024-06-17 10:53:04 +02:00 committed by GitHub
parent e902d63732
commit 2c0d0d57b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -27,6 +27,7 @@ use crate::font::{
}; };
use crate::font_cache_thread::FontIdentifier; use crate::font_cache_thread::FontIdentifier;
use crate::font_template::FontTemplateDescriptor; use crate::font_template::FontTemplateDescriptor;
use crate::ot_tag;
use crate::text::glyph::GlyphId; use crate::text::glyph::GlyphId;
// 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch // 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)] #[derive(Debug)]
pub struct PlatformFont { pub struct PlatformFont {
face: Nondebug<FontFace>, face: Nondebug<FontFace>,
@ -142,7 +133,12 @@ impl PlatformFontMethods for PlatformFont {
// //
// Instead, we do the parsing work using the truetype crate for raw fonts. // 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. // 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() { if windows_metrics_bytes.is_none() {
warn!("Could not find OS/2 table in font."); warn!("Could not find OS/2 table in font.");
return FontTemplateDescriptor::default(); return FontTemplateDescriptor::default();
@ -269,8 +265,11 @@ impl PlatformFontMethods for PlatformFont {
} }
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
// 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 self.face
.get_font_table(tag) .get_font_table(u32::swap_bytes(tag))
.map(|bytes| FontTable { data: bytes }) .map(|bytes| FontTable { data: bytes })
} }