From ed7feb0fdc9af1eae913cb8054d88d9e741d2ada Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Mon, 27 Nov 2017 18:19:12 -0500 Subject: [PATCH 1/2] Split out ResourceGenerator from the other state in YamlFrameWriter This cleans up things a little and will make it easier for us to generate files for native fonts because we won't have multiple mutable borrows on YamlFrameWriter. --- wrench/src/yaml_frame_writer.rs | 60 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/wrench/src/yaml_frame_writer.rs b/wrench/src/yaml_frame_writer.rs index 3a85b90989..b5df2a0628 100644 --- a/wrench/src/yaml_frame_writer.rs +++ b/wrench/src/yaml_frame_writer.rs @@ -254,11 +254,30 @@ struct CachedImage { tiling: Option, } +struct ResourceGenerator { + base: PathBuf, + next_num: u32, + prefix: String, +} + +impl ResourceGenerator { + fn next_rsrc_paths(&mut self, base: &str, ext: &str) -> (PathBuf, PathBuf) { + let mut path_file = self.base.to_owned(); + let mut path = PathBuf::from("res"); + + let fstr = format!("{}-{}-{}.{}", self.prefix, base, self.next_num, ext); + path_file.push(&fstr); + path.push(&fstr); + + self.next_num += 1; + + (path_file, path) + } +} + pub struct YamlFrameWriter { frame_base: PathBuf, - rsrc_base: PathBuf, - next_rsrc_num: u32, - rsrc_prefix: String, + rsrc_gen: ResourceGenerator, images: HashMap, fonts: HashMap, font_instances: HashMap, @@ -299,9 +318,11 @@ impl YamlFrameWriter { YamlFrameWriter { frame_base: path.to_owned(), - rsrc_base, - rsrc_prefix, - next_rsrc_num: 1, + rsrc_gen: ResourceGenerator { + base: rsrc_base, + prefix: rsrc_prefix, + next_num: 1, + }, images: HashMap::new(), fonts: HashMap::new(), font_instances: HashMap::new(), @@ -472,24 +493,7 @@ impl YamlFrameWriter { } } - fn next_rsrc_paths( - prefix: &str, - counter: &mut u32, - base_path: &Path, - base: &str, - ext: &str, - ) -> (PathBuf, PathBuf) { - let mut path_file = base_path.to_owned(); - let mut path = PathBuf::from("res"); - let fstr = format!("{}-{}-{}.{}", prefix, base, counter, ext); - path_file.push(&fstr); - path.push(&fstr); - - *counter += 1; - - (path_file, path) - } fn path_for_image(&mut self, key: ImageKey) -> Option { if let Some(ref mut data) = self.images.get_mut(&key) { @@ -503,10 +507,7 @@ impl YamlFrameWriter { // Remove the data to munge it let mut data = self.images.remove(&key).unwrap(); let mut bytes = data.bytes.take().unwrap(); - let (path_file, path) = Self::next_rsrc_paths( - &self.rsrc_prefix, - &mut self.next_rsrc_num, - &self.rsrc_base, + let (path_file, path) = self.rsrc_gen.next_rsrc_paths( "img", "png", ); @@ -693,10 +694,7 @@ impl YamlFrameWriter { } &mut CachedFont::Raw(ref mut bytes_opt, index, ref mut path_opt) => { if let Some(bytes) = bytes_opt.take() { - let (path_file, path) = Self::next_rsrc_paths( - &self.rsrc_prefix, - &mut self.next_rsrc_num, - &self.rsrc_base, + let (path_file, path) = self.rsrc_gen.next_rsrc_paths( "font", "ttf", ); From 7bd05c062d3bf3ea3c87ab416a3ea4dbe9b229a2 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Mon, 27 Nov 2017 18:11:17 -0500 Subject: [PATCH 2/2] Write out font files for CGFonts This ups the core-graphics dependency and adds the ability to convert a CGFont into a font file. The code is based on the code in https://searchfox.org/mozilla-central/rev/7a8c667bdd2a4a32746c9862356e199627c0896d/gfx/2d/ScaledFontMac.cpp#255 We also switch to CFNumber::from to avoid breakage with the latest core-foundation --- Cargo.lock | 38 ++++---- webrender/src/platform/macos/font.rs | 2 +- wrench/Cargo.toml | 4 + wrench/src/cgfont_to_data.rs | 124 +++++++++++++++++++++++++++ wrench/src/main.rs | 6 ++ wrench/src/yaml_frame_writer.rs | 47 ++++++++-- 6 files changed, 194 insertions(+), 27 deletions(-) create mode 100644 wrench/src/cgfont_to_data.rs diff --git a/Cargo.lock b/Cargo.lock index 687c009f06..9b1583ac92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,7 +150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -162,16 +162,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "core-foundation" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-foundation-sys" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", @@ -179,11 +179,11 @@ dependencies = [ [[package]] name = "core-graphics" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -193,8 +193,8 @@ name = "core-text" version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -293,7 +293,7 @@ name = "font-loader" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "core-text 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", @@ -815,8 +815,8 @@ dependencies = [ "android_glue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cocoa 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", "dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl_generator 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1019,8 +1019,8 @@ dependencies = [ "bincode 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-text 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1054,8 +1054,8 @@ dependencies = [ "bincode 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.15.5 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1082,6 +1082,8 @@ dependencies = [ "bincode 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1179,9 +1181,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum cocoa 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac0d785ff4faf0ff23d7b5561346bb50dc7ef9a11cb0e65e07ef776b7752938f" "checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d" -"checksum core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5909502e547762013619f4c4e01cc7393c20fe2d52d7fa471c1210adb2320dc7" -"checksum core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc9fb3d6cb663e6fd7cf1c63f9b144ee2b1e4a78595a0451dd34bff85b9a3387" -"checksum core-graphics 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5dc0a78ab2ac23b6ea7b3fe5fe93b227900dc0956979735b8f68032417976dd4" +"checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e" +"checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5" +"checksum core-graphics 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8de78908c558a9ba526877d165635c9eaed0818a785a93efddde1c5bfd2ce5d1" "checksum core-text 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcad23756dd1dc4b47bf6a914ace27aadb8fa68889db5837af2308d018d0467c" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" "checksum deflate 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4dddda59aaab719767ab11d3efd9a714e95b610c4445d4435765021e9d52dfb1" diff --git a/webrender/src/platform/macos/font.rs b/webrender/src/platform/macos/font.rs index c3ee903c07..b67200bb8a 100644 --- a/webrender/src/platform/macos/font.rs +++ b/webrender/src/platform/macos/font.rs @@ -247,7 +247,7 @@ fn new_ct_font_with_variations(cg_font: &CGFont, size: f64, variations: &[FontVa val = val.max(min_val).min(max_val); if val != def_val { - vals.push((name, CFNumber::from_f64(val))); + vals.push((name, CFNumber::from(val))); } } if vals.is_empty() { diff --git a/wrench/Cargo.toml b/wrench/Cargo.toml index 29b5f0623f..ba0ca3a271 100644 --- a/wrench/Cargo.toml +++ b/wrench/Cargo.toml @@ -27,6 +27,10 @@ osmesa-src = { git = "https://github.com/servo/osmesa-src", optional = true } webrender = {path = "../webrender", features=["debugger","profiler"]} serde = {version = "1.0", features = ["derive"] } +[target.'cfg(target_os = "macos")'.dependencies] +core-graphics = "0.12.4" +core-foundation = "0.4" + [features] headless = [ "osmesa-sys", "osmesa-src" ] logging = [ "env_logger" ] diff --git a/wrench/src/cgfont_to_data.rs b/wrench/src/cgfont_to_data.rs new file mode 100644 index 0000000000..5c63bef69f --- /dev/null +++ b/wrench/src/cgfont_to_data.rs @@ -0,0 +1,124 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; +use core_foundation::data::CFData; +use core_graphics::font::CGFont; +use std; +use std::io::Cursor; +use std::io::Read; +use std::io::Write; + + +fn calc_table_checksum(mut data: D) -> u32 { + let mut sum: u32 = 0; + + while let Ok(x) = data.read_u32::() { + sum = sum.wrapping_add(x); + } + // read the remaining bytes + let mut buf: [u8; 4] = [0; 4]; + data.read(&mut buf).unwrap(); + // if there was nothing left in buf we'll just read a 0 + // which won't affect the checksum + sum = sum.wrapping_add(BigEndian::read_u32(&buf)); + sum +} + +fn max_pow_2_less_than(a: u16) -> u16 { + let x = 1; + let mut shift = 0; + while (x << (shift + 1)) < a { + shift += 1; + } + shift +} + +struct TableRecord { + tag: u32, + checksum: u32, + offset: u32, + length: u32, + data: CFData +} + +const CFF_TAG: u32 = 0x43464620; // 'CFF ' +const HEAD_TAG: u32 = 0x68656164; // 'head' +const OTTO_TAG: u32 = 0x4f54544f; // 'OTTO' +const TRUE_TAG: u32 = 0x00010000; + +pub fn font_to_data(font: CGFont) -> Result, std::io::Error> { + // We'll reconstruct a TTF font from the tables we can get from the CGFont + let mut cff = false; + let tags = font.copy_table_tags(); + let count = tags.len() as u16; + + let mut records = Vec::new(); + let mut offset: u32 = 0; + offset += 4 * 3; + offset += 4 * 4 * (count as u32); + for tag in tags.iter() { + if tag == CFF_TAG { + cff = true; + } + let data = font.copy_table_for_tag(tag).unwrap(); + let length = data.len() as u32; + let checksum; + if tag == HEAD_TAG { + // we need to skip the checksum field + checksum = calc_table_checksum(&data.bytes()[0..2]) + .wrapping_add(calc_table_checksum(&data.bytes()[3..])) + } else { + checksum = calc_table_checksum(data.bytes()); + } + records.push(TableRecord { tag, offset, data, length, checksum } ); + offset += length; + // 32 bit align the tables + offset = (offset + 3) & !3; + } + + let mut buf = Vec::new(); + if cff { + buf.write_u32::(OTTO_TAG)?; + } else { + buf.write_u32::(TRUE_TAG)?; + } + + buf.write_u16::(count)?; + buf.write_u16::((1 << max_pow_2_less_than(count)) * 16)?; + buf.write_u16::(max_pow_2_less_than(count))?; + buf.write_u16::(count * 16 - ((1 << max_pow_2_less_than(count)) * 16))?; + + // write table record entries + for r in &records { + buf.write_u32::(r.tag)?; + buf.write_u32::(r.checksum)?; + buf.write_u32::(r.offset)?; + buf.write_u32::(r.length)?; + } + + // write tables + let mut check_sum_adjustment_offset = 0; + for r in &records { + if r.tag == 0x68656164 { + check_sum_adjustment_offset = buf.len() + 2 * 4; + } + buf.write(r.data.bytes())?; + // 32 bit align the tables + while buf.len() & 3 != 0 { + buf.push(0); + } + } + + let mut c = Cursor::new(buf); + c.set_position(check_sum_adjustment_offset as u64); + // clear the checksumAdjust field before checksumming the whole font + c.write_u32::(0)?; + let sum = 0xb1b0afba_u32.wrapping_sub(calc_table_checksum(&c.get_mut()[..])); + // set checkSumAdjust to the computed checksum + c.set_position(check_sum_adjustment_offset as u64); + c.write_u32::(sum)?; + + Ok(c.into_inner()) +} diff --git a/wrench/src/main.rs b/wrench/src/main.rs index 9b4a3b4b53..0a06c4358a 100644 --- a/wrench/src/main.rs +++ b/wrench/src/main.rs @@ -8,6 +8,10 @@ extern crate bincode; extern crate byteorder; #[macro_use] extern crate clap; +#[cfg(target_os = "macos")] +extern crate core_foundation; +#[cfg(target_os = "macos")] +extern crate core_graphics; extern crate crossbeam; #[cfg(target_os = "windows")] extern crate dwrote; @@ -46,6 +50,8 @@ mod wrench; mod yaml_frame_reader; mod yaml_frame_writer; mod yaml_helper; +#[cfg(target_os = "macos")] +mod cgfont_to_data; use binary_frame_reader::BinaryFrameReader; use gleam::gl; diff --git a/wrench/src/yaml_frame_writer.rs b/wrench/src/yaml_frame_writer.rs index b5df2a0628..9eb7f33111 100644 --- a/wrench/src/yaml_frame_writer.rs +++ b/wrench/src/yaml_frame_writer.rs @@ -217,7 +217,12 @@ fn write_sc(parent: &mut Table, sc: &StackingContext, properties: &SceneProperti } #[cfg(target_os = "windows")] -fn native_font_handle_to_yaml(handle: &NativeFontHandle, parent: &mut yaml_rust::yaml::Hash) { +fn native_font_handle_to_yaml( + _rsrc: &mut ResourceGenerator, + handle: &NativeFontHandle, + parent: &mut yaml_rust::yaml::Hash, + _: &mut Option, +) { str_node(parent, "family", &handle.family_name); u32_node(parent, "weight", handle.weight.to_u32()); u32_node(parent, "style", handle.style.to_u32()); @@ -225,17 +230,43 @@ fn native_font_handle_to_yaml(handle: &NativeFontHandle, parent: &mut yaml_rust: } #[cfg(target_os = "macos")] -fn native_font_handle_to_yaml(_: &NativeFontHandle, _: &mut yaml_rust::yaml::Hash) { - panic!("Can't native_handle_to_yaml on this platform"); +fn native_font_handle_to_yaml( + rsrc: &mut ResourceGenerator, + handle: &NativeFontHandle, + parent: &mut yaml_rust::yaml::Hash, + path_opt: &mut Option, +) { + let path = match *path_opt { + Some(ref path) => { path.clone() }, + None => { + use cgfont_to_data; + let bytes = cgfont_to_data::font_to_data(handle.0.clone()).unwrap(); + let (path_file, path) = rsrc.next_rsrc_paths( + "font", + "ttf", + ); + let mut file = fs::File::create(&path_file).unwrap(); + file.write_all(&bytes).unwrap(); + *path_opt = Some(path.clone()); + path + } + }; + + path_node(parent, "font", &path); } #[cfg(not(any(target_os = "macos", target_os = "windows")))] -fn native_font_handle_to_yaml(handle: &NativeFontHandle, parent: &mut yaml_rust::yaml::Hash) { +fn native_font_handle_to_yaml( + _rsrc: &mut ResourceGenerator, + handle: &NativeFontHandle, + parent: &mut yaml_rust::yaml::Hash, + _: &mut Option, +) { str_node(parent, "font", &handle.pathname); } enum CachedFont { - Native(NativeFontHandle), + Native(NativeFontHandle, Option), Raw(Option>, u32, Option), } @@ -475,7 +506,7 @@ impl YamlFrameWriter { .insert(key, CachedFont::Raw(Some(bytes.clone()), index, None)); } &AddFont::Native(key, ref handle) => { - self.fonts.insert(key, CachedFont::Native(handle.clone())); + self.fonts.insert(key, CachedFont::Native(handle.clone(), None)); } }, ResourceUpdate::DeleteFont(_) => {} @@ -689,8 +720,8 @@ impl YamlFrameWriter { }); match entry { - &mut CachedFont::Native(ref handle) => { - native_font_handle_to_yaml(handle, &mut v); + &mut CachedFont::Native(ref handle, ref mut path_opt) => { + native_font_handle_to_yaml(&mut self.rsrc_gen, handle, &mut v, path_opt); } &mut CachedFont::Raw(ref mut bytes_opt, index, ref mut path_opt) => { if let Some(bytes) = bytes_opt.take() {