Use Tag type from font-types crate to represent opentype tags (#38870)

The `font-types` crate is the tiny type-only base crate of `fontations`.
This uses a strongly typed representation of open type tags, and allows
us to remove our custom macro for creating them.

---------

Signed-off-by: Nico Burns <nico@nicoburns.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Nico Burns 2025-08-23 21:32:47 +01:00 committed by GitHub
parent 0a8146143a
commit 1fc857865f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 31 additions and 57 deletions

View file

@ -19,6 +19,7 @@ use log::debug;
use malloc_size_of_derive::MallocSizeOf; use malloc_size_of_derive::MallocSizeOf;
use parking_lot::RwLock; use parking_lot::RwLock;
use read_fonts::tables::os2::{Os2, SelectionFlags}; use read_fonts::tables::os2::{Os2, SelectionFlags};
use read_fonts::types::Tag;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smallvec::SmallVec; use smallvec::SmallVec;
use style::computed_values::font_variant_caps; use style::computed_values::font_variant_caps;
@ -38,22 +39,14 @@ use crate::{
FontTemplateRefMethods, GlyphData, GlyphId, GlyphStore, LocalFontIdentifier, Shaper, FontTemplateRefMethods, GlyphData, GlyphId, GlyphStore, LocalFontIdentifier, Shaper,
}; };
#[macro_export] pub const GPOS: Tag = Tag::new(b"GPOS");
macro_rules! ot_tag { pub const GSUB: Tag = Tag::new(b"GSUB");
($t1:expr, $t2:expr, $t3:expr, $t4:expr) => { pub const KERN: Tag = Tag::new(b"kern");
(($t1 as u32) << 24) | (($t2 as u32) << 16) | (($t3 as u32) << 8) | ($t4 as u32) pub const SBIX: Tag = Tag::new(b"sbix");
}; pub const CBDT: Tag = Tag::new(b"CBDT");
} pub const COLR: Tag = Tag::new(b"COLR");
pub const BASE: Tag = Tag::new(b"BASE");
pub type OpenTypeTableTag = u32; pub const LIGA: Tag = Tag::new(b"liga");
pub const GPOS: OpenTypeTableTag = ot_tag!('G', 'P', 'O', 'S');
pub const GSUB: OpenTypeTableTag = ot_tag!('G', 'S', 'U', 'B');
pub const KERN: OpenTypeTableTag = ot_tag!('k', 'e', 'r', 'n');
pub const SBIX: OpenTypeTableTag = ot_tag!('s', 'b', 'i', 'x');
pub const CBDT: OpenTypeTableTag = ot_tag!('C', 'B', 'D', 'T');
pub const COLR: OpenTypeTableTag = ot_tag!('C', 'O', 'L', 'R');
pub const BASE: OpenTypeTableTag = ot_tag!('B', 'A', 'S', 'E');
pub const LIGA: OpenTypeTableTag = ot_tag!('l', 'i', 'g', 'a');
pub const LAST_RESORT_GLYPH_ADVANCE: FractionalPixel = 10.0; pub const LAST_RESORT_GLYPH_ADVANCE: FractionalPixel = 10.0;
@ -112,7 +105,7 @@ pub trait PlatformFontMethods: Sized {
fn glyph_h_kerning(&self, glyph0: GlyphId, glyph1: GlyphId) -> FractionalPixel; fn glyph_h_kerning(&self, glyph0: GlyphId, glyph1: GlyphId) -> FractionalPixel;
fn metrics(&self) -> FontMetrics; fn metrics(&self) -> FontMetrics;
fn table_for_tag(&self, _: FontTableTag) -> Option<FontTable>; fn table_for_tag(&self, _: Tag) -> Option<FontTable>;
fn typographic_bounds(&self, _: GlyphId) -> Rect<f32>; fn typographic_bounds(&self, _: GlyphId) -> Rect<f32>;
/// Get the necessary [`FontInstanceFlags`]` for this font. /// Get the necessary [`FontInstanceFlags`]` for this font.
@ -148,24 +141,6 @@ pub trait PlatformFontMethods: Sized {
// Used to abstract over the shaper's choice of fixed int representation. // Used to abstract over the shaper's choice of fixed int representation.
pub type FractionalPixel = f64; pub type FractionalPixel = f64;
pub type FontTableTag = u32;
trait FontTableTagConversions {
fn tag_to_str(&self) -> String;
}
impl FontTableTagConversions for FontTableTag {
fn tag_to_str(&self) -> String {
let bytes = [
(self >> 24) as u8,
(self >> 16) as u8,
(self >> 8) as u8,
*self as u8,
];
str::from_utf8(&bytes).unwrap().to_owned()
}
}
pub trait FontTableMethods { pub trait FontTableMethods {
fn buffer(&self) -> &[u8]; fn buffer(&self) -> &[u8];
} }
@ -533,7 +508,7 @@ impl Font {
glyphs.finalize_changes(); glyphs.finalize_changes();
} }
pub fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { pub fn table_for_tag(&self, tag: Tag) -> Option<FontTable> {
let result = self.handle.table_for_tag(tag); let result = self.handle.table_for_tag(tag);
let status = if result.is_some() { let status = if result.is_some() {
"Found" "Found"
@ -544,7 +519,7 @@ impl Font {
debug!( debug!(
"{} font table[{}] in {:?},", "{} font table[{}] in {:?},",
status, status,
tag.tag_to_str(), str::from_utf8(tag.as_ref()).unwrap(),
self.identifier() self.identifier()
); );
result result

View file

@ -24,9 +24,7 @@ use webrender_api::{FontInstanceFlags, FontVariation};
use super::LocalFontIdentifier; use super::LocalFontIdentifier;
use super::library_handle::FreeTypeLibraryHandle; use super::library_handle::FreeTypeLibraryHandle;
use crate::FontData; use crate::FontData;
use crate::font::{ use crate::font::{FontMetrics, FontTableMethods, FractionalPixel, PlatformFontMethods};
FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, PlatformFontMethods,
};
use crate::font_template::FontTemplateDescriptor; use crate::font_template::FontTemplateDescriptor;
use crate::glyph::GlyphId; use crate::glyph::GlyphId;
use crate::platform::freetype::freetype_face::FreeTypeFace; use crate::platform::freetype::freetype_face::FreeTypeFace;
@ -324,8 +322,7 @@ impl PlatformFontMethods for PlatformFont {
} }
} }
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { fn table_for_tag(&self, tag: Tag) -> Option<FontTable> {
let tag = Tag::from_u32(tag);
let font_ref = self.table_provider_data.font_ref().ok()?; let font_ref = self.table_provider_data.font_ref().ok()?;
let _table_data = font_ref.table_data(tag)?; let _table_data = font_ref.table_data(tag)?;
Some(FontTable { Some(FontTable {

View file

@ -18,15 +18,15 @@ use core_text::font_descriptor::{
}; };
use euclid::default::{Point2D, Rect, Size2D}; use euclid::default::{Point2D, Rect, Size2D};
use log::debug; use log::debug;
use skrifa::Tag;
use style::values::computed::font::{FontStretch, FontStyle, FontWeight}; use style::values::computed::font::{FontStretch, FontStyle, FontWeight};
use webrender_api::{FontInstanceFlags, FontVariation}; use webrender_api::{FontInstanceFlags, FontVariation};
use super::core_text_font_cache::CoreTextFontCache; use super::core_text_font_cache::CoreTextFontCache;
use super::font_list::LocalFontIdentifier; use super::font_list::LocalFontIdentifier;
use crate::{ use crate::{
CBDT, COLR, FontData, FontIdentifier, FontMetrics, FontTableMethods, FontTableTag, CBDT, COLR, FontData, FontIdentifier, FontMetrics, FontTableMethods, FontTemplateDescriptor,
FontTemplateDescriptor, FractionalPixel, GlyphId, KERN, PlatformFontMethods, SBIX, FractionalPixel, GlyphId, KERN, PlatformFontMethods, SBIX, map_platform_values_to_style_values,
map_platform_values_to_style_values,
}; };
const KERN_PAIR_LEN: usize = 6; const KERN_PAIR_LEN: usize = 6;
@ -346,8 +346,9 @@ impl PlatformFontMethods for PlatformFont {
metrics metrics
} }
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { fn table_for_tag(&self, tag: Tag) -> Option<FontTable> {
let result: Option<CFData> = self.ctfont.get_font_table(tag); let tag_u32 = u32::from_be_bytes(tag.to_be_bytes());
let result: Option<CFData> = self.ctfont.get_font_table(tag_u32);
result.map(FontTable::wrap) result.map(FontTable::wrap)
} }

View file

@ -26,7 +26,7 @@ use winapi::shared::minwindef::{BOOL, FALSE};
use super::font_list::LocalFontIdentifier; use super::font_list::LocalFontIdentifier;
use crate::{ use crate::{
FontData, FontIdentifier, FontMetrics, FontTableMethods, FontTableTag, FontTemplateDescriptor, FontData, FontIdentifier, FontMetrics, FontTableMethods, FontTemplateDescriptor,
FractionalPixel, GlyphId, PlatformFontMethods, FractionalPixel, GlyphId, PlatformFontMethods,
}; };
@ -282,12 +282,12 @@ impl PlatformFontMethods for PlatformFont {
metrics metrics
} }
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { fn table_for_tag(&self, tag: Tag) -> Option<FontTable> {
// dwrote (and presumably the Windows APIs) accept a reversed version of the table // 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 // 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. // use a byte order compatible with the rest of Servo.
self.face self.face
.font_table(u32::swap_bytes(tag)) .font_table(u32::from_be_bytes(tag.to_be_bytes()).swap_bytes())
.ok() .ok()
.flatten() .flatten()
.map(|bytes| FontTable { data: bytes }) .map(|bytes| FontTable { data: bytes })

View file

@ -26,16 +26,17 @@ use harfbuzz_sys::{
hb_variation_t, hb_variation_t,
}; };
use num_traits::Zero; use num_traits::Zero;
use read_fonts::types::Tag;
use super::{HarfBuzzShapedGlyphData, ShapedGlyphEntry, unicode_script_to_iso15924_tag}; use super::{HarfBuzzShapedGlyphData, ShapedGlyphEntry, unicode_script_to_iso15924_tag};
use crate::platform::font::FontTable; use crate::platform::font::FontTable;
use crate::{ use crate::{
BASE, Font, FontBaseline, FontTableMethods, FontTableTag, GlyphId, GlyphStore, KERN, LIGA, BASE, Font, FontBaseline, FontTableMethods, GlyphId, GlyphStore, KERN, LIGA, ShapingFlags,
OpenTypeTableTag, ShapingFlags, ShapingOptions, fixed_to_float, float_to_fixed, ot_tag, ShapingOptions, fixed_to_float, float_to_fixed,
}; };
const HB_OT_TAG_DEFAULT_SCRIPT: OpenTypeTableTag = ot_tag!('D', 'F', 'L', 'T'); const HB_OT_TAG_DEFAULT_SCRIPT: hb_tag_t = u32::from_be_bytes(Tag::new(b"DFLT").to_be_bytes());
const HB_OT_TAG_DEFAULT_LANGUAGE: OpenTypeTableTag = ot_tag!('d', 'f', 'l', 't'); const HB_OT_TAG_DEFAULT_LANGUAGE: hb_tag_t = u32::from_be_bytes(Tag::new(b"dflt").to_be_bytes());
pub struct ShapedGlyphData { pub struct ShapedGlyphData {
count: usize, count: usize,
@ -238,7 +239,7 @@ impl Shaper {
.contains(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG) .contains(ShapingFlags::IGNORE_LIGATURES_SHAPING_FLAG)
{ {
features.push(hb_feature_t { features.push(hb_feature_t {
tag: LIGA, tag: u32::from_be_bytes(LIGA.to_be_bytes()),
value: 0, value: 0,
start: 0, start: 0,
end: hb_buffer_get_length(hb_buffer), end: hb_buffer_get_length(hb_buffer),
@ -249,7 +250,7 @@ impl Shaper {
.contains(ShapingFlags::DISABLE_KERNING_SHAPING_FLAG) .contains(ShapingFlags::DISABLE_KERNING_SHAPING_FLAG)
{ {
features.push(hb_feature_t { features.push(hb_feature_t {
tag: KERN, tag: u32::from_be_bytes(KERN.to_be_bytes()),
value: 0, value: 0,
start: 0, start: 0,
end: hb_buffer_get_length(hb_buffer), end: hb_buffer_get_length(hb_buffer),
@ -391,7 +392,7 @@ extern "C" fn font_table_func(
assert!(!font.is_null()); assert!(!font.is_null());
// TODO(Issue #197): reuse font table data, which will change the unsound trickery here. // TODO(Issue #197): reuse font table data, which will change the unsound trickery here.
let Some(font_table) = (unsafe { (*font).table_for_tag(tag as FontTableTag) }) else { let Some(font_table) = (unsafe { (*font).table_for_tag(Tag::from_u32(tag)) }) else {
return ptr::null_mut(); return ptr::null_mut();
}; };