diff options
Diffstat (limited to 'components/gfx/platform/windows/font.rs')
-rw-r--r-- | components/gfx/platform/windows/font.rs | 279 |
1 files changed, 0 insertions, 279 deletions
diff --git a/components/gfx/platform/windows/font.rs b/components/gfx/platform/windows/font.rs deleted file mode 100644 index 4aeb04fc29f..00000000000 --- a/components/gfx/platform/windows/font.rs +++ /dev/null @@ -1,279 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -// NOTE: https://www.chromium.org/directwrite-font-proxy has useful -// information for an approach that we'll likely need to take when the -// renderer moves to a sandboxed process. - -use std::cmp::{max, min}; -use std::fmt; -use std::io::Cursor; -use std::ops::Deref; -use std::sync::Arc; - -use app_units::Au; -use dwrote::{FontFace, FontFile}; -use log::{debug, warn}; -use style::computed_values::font_stretch::T as StyleFontStretch; -use style::computed_values::font_weight::T as StyleFontWeight; -use style::values::computed::font::FontStyle as StyleFontStyle; -use truetype::tables::WindowsMetrics; -use truetype::value::Read; -use webrender_api::FontInstanceFlags; - -use crate::font::{ - FontMetrics, FontTableMethods, FontTableTag, FractionalPixel, PlatformFontMethods, -}; -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 -fn pt_to_px(pt: f64) -> f64 { - pt / 72. * 96. -} -fn em_to_px(em: f64) -> f64 { - em * 16. -} -fn au_from_em(em: f64) -> Au { - Au::from_f64_px(em_to_px(em)) -} -fn au_from_pt(pt: f64) -> Au { - Au::from_f64_px(pt_to_px(pt)) -} - -pub struct FontTable { - data: Vec<u8>, -} - -impl FontTable { - pub fn wrap(data: &[u8]) -> FontTable { - FontTable { - data: data.to_vec(), - } - } -} - -impl FontTableMethods for FontTable { - fn buffer(&self) -> &[u8] { - &self.data - } -} - -#[derive(Debug)] -pub struct PlatformFont { - face: Nondebug<FontFace>, - /// A reference to this data used to create this [`PlatformFont`], ensuring the - /// data stays alive of the lifetime of this struct. - _data: Arc<Vec<u8>>, - em_size: f32, - du_to_px: f32, - scaled_du_to_px: f32, -} - -// Based on information from the Skia codebase, it seems that DirectWrite APIs from -// Windows 10 and beyond are thread safe. If problems arise from this, we can protect the -// platform font with a Mutex. -// See https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/ports/SkScalerContext_win_dw.cpp;l=56;bpv=0;bpt=1. -unsafe impl Sync for PlatformFont {} -unsafe impl Send for PlatformFont {} - -struct Nondebug<T>(T); - -impl<T> fmt::Debug for Nondebug<T> { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } -} - -impl<T> Deref for Nondebug<T> { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } -} - -impl PlatformFontMethods for PlatformFont { - fn new_from_data( - _font_identifier: FontIdentifier, - data: Arc<Vec<u8>>, - face_index: u32, - pt_size: Option<Au>, - ) -> Result<Self, &'static str> { - let font_file = FontFile::new_from_data(data.clone()).ok_or("Could not create FontFile")?; - let face = font_file - .create_face(face_index, dwrote::DWRITE_FONT_SIMULATIONS_NONE) - .map_err(|_| "Could not create FontFace")?; - - let pt_size = pt_size.unwrap_or(au_from_pt(12.)); - let du_per_em = face.metrics().metrics0().designUnitsPerEm as f32; - - let em_size = pt_size.to_f32_px() / 16.; - let design_units_per_pixel = du_per_em / 16.; - - let design_units_to_pixels = 1. / design_units_per_pixel; - let scaled_design_units_to_pixels = em_size / design_units_per_pixel; - - Ok(PlatformFont { - face: Nondebug(face), - _data: data, - em_size, - du_to_px: design_units_to_pixels, - scaled_du_to_px: scaled_design_units_to_pixels, - }) - } - - fn descriptor(&self) -> FontTemplateDescriptor { - // We need the font (DWriteFont) in order to be able to query things like - // the family name, face name, weight, etc. On Windows 10, the - // DWriteFontFace3 interface provides this on the FontFace, but that's only - // available on Win10+. - // - // 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. - // - // 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(); - } - - let mut cursor = Cursor::new(windows_metrics_bytes.as_ref().unwrap()); - let Ok(table) = WindowsMetrics::read(&mut cursor) else { - warn!("Could not read OS/2 table in font."); - return FontTemplateDescriptor::default(); - }; - - let (weight_val, width_val, italic_bool) = match table { - WindowsMetrics::Version0(ref m) => { - (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1) - }, - WindowsMetrics::Version1(ref m) => { - (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1) - }, - WindowsMetrics::Version2(ref m) | - WindowsMetrics::Version3(ref m) | - WindowsMetrics::Version4(ref m) => { - (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1) - }, - WindowsMetrics::Version5(ref m) => { - (m.weight_class, m.width_class, m.selection_flags.0 & 1 == 1) - }, - }; - - let weight = StyleFontWeight::from_float(weight_val as f32); - let stretch = match min(9, max(1, width_val)) { - 1 => StyleFontStretch::ULTRA_CONDENSED, - 2 => StyleFontStretch::EXTRA_CONDENSED, - 3 => StyleFontStretch::CONDENSED, - 4 => StyleFontStretch::SEMI_CONDENSED, - 5 => StyleFontStretch::NORMAL, - 6 => StyleFontStretch::SEMI_EXPANDED, - 7 => StyleFontStretch::EXPANDED, - 8 => StyleFontStretch::EXTRA_EXPANDED, - 9 => StyleFontStretch::ULTRA_CONDENSED, - _ => { - warn!("Unknown stretch size."); - StyleFontStretch::NORMAL - }, - }; - - let style = if italic_bool { - StyleFontStyle::ITALIC - } else { - StyleFontStyle::NORMAL - }; - - FontTemplateDescriptor::new(weight, stretch, style) - } - - fn glyph_index(&self, codepoint: char) -> Option<GlyphId> { - let glyph = self.face.get_glyph_indices(&[codepoint as u32])[0]; - if glyph == 0 { - return None; - } - Some(glyph as GlyphId) - } - - fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> { - if glyph == 0 { - return None; - } - - let gm = self.face.get_design_glyph_metrics(&[glyph as u16], false)[0]; - let f = (gm.advanceWidth as f32 * self.scaled_du_to_px) as FractionalPixel; - - Some(f) - } - - /// Can this font do basic horizontal LTR shaping without Harfbuzz? - fn can_do_fast_shaping(&self) -> bool { - // TODO copy CachedKernTable from the MacOS X implementation to - // somehwere global and use it here. We could also implement the - // IDirectWriteFontFace1 interface and use the glyph kerning pair - // methods there. - false - } - - fn glyph_h_kerning(&self, _: GlyphId, _: GlyphId) -> FractionalPixel { - 0.0 - } - - fn metrics(&self) -> FontMetrics { - let dm = self.face.metrics().metrics0(); - - let au_from_du = |du| -> Au { Au::from_f32_px(du as f32 * self.du_to_px) }; - let au_from_du_s = |du| -> Au { Au::from_f32_px(du as f32 * self.scaled_du_to_px) }; - - // anything that we calculate and don't just pull out of self.face.metrics - // is pulled out here for clarity - let leading = dm.ascent - dm.capHeight; - - let zero_horizontal_advance = self - .glyph_index('0') - .and_then(|idx| self.glyph_h_advance(idx)) - .map(Au::from_f64_px); - let ic_horizontal_advance = self - .glyph_index('\u{6C34}') - .and_then(|idx| self.glyph_h_advance(idx)) - .map(Au::from_f64_px); - - let metrics = FontMetrics { - underline_size: au_from_du(dm.underlineThickness as i32), - underline_offset: au_from_du_s(dm.underlinePosition as i32), - strikeout_size: au_from_du(dm.strikethroughThickness as i32), - strikeout_offset: au_from_du_s(dm.strikethroughPosition as i32), - leading: au_from_du_s(leading as i32), - x_height: au_from_du_s(dm.xHeight as i32), - em_size: au_from_em(self.em_size as f64), - ascent: au_from_du_s(dm.ascent as i32), - descent: au_from_du_s(dm.descent as i32), - max_advance: au_from_pt(0.0), // FIXME - average_advance: au_from_pt(0.0), // FIXME - line_gap: au_from_du_s((dm.ascent + dm.descent + dm.lineGap as u16) as i32), - zero_horizontal_advance, - ic_horizontal_advance, - }; - debug!("Font metrics (@{} pt): {:?}", self.em_size * 12., metrics); - metrics - } - - 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 - .get_font_table(u32::swap_bytes(tag)) - .map(|bytes| FontTable { data: bytes }) - } - - fn webrender_font_instance_flags(&self) -> FontInstanceFlags { - FontInstanceFlags::empty() - } -} |